Browse Source

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

pull/384/head
jonathangreen 12 years ago
parent
commit
95c95b33bb
  1. 19
      .travis.yml
  2. 27
      README.md
  3. 164
      build.xml
  4. 3
      build/Doxyfile
  5. 39
      css/islandora.objects.css
  6. 12
      includes/add_datastream.form.inc
  7. 225
      includes/admin.form.inc
  8. 78
      includes/breadcrumb.inc
  9. 57
      includes/content_model.autocomplete.inc
  10. 84
      includes/datastream.inc
  11. 6
      includes/delete_datastream.form.inc
  12. 4
      includes/delete_object.form.inc
  13. 485
      includes/ingest.form.inc
  14. 49
      includes/ingest.menu.inc
  15. 18
      includes/mime_detect.inc
  16. 11
      includes/object_properties.form.inc
  17. 125
      includes/solution_packs.inc
  18. 26
      includes/tuque_wrapper.inc
  19. 263
      includes/utilities.inc
  20. 192
      islandora.api.php
  21. 4
      islandora.info
  22. 5
      islandora.install
  23. 491
      islandora.module
  24. 6
      islandora.rules.inc
  25. 3
      tests/README.md
  26. 149
      tests/hooked_access.test
  27. 12
      tests/hooks.test
  28. 118
      tests/ingest.test
  29. 7
      tests/islandora_hooked_access_test.info
  30. 31
      tests/islandora_hooked_access_test.module
  31. 3
      tests/islandora_hooks_test.info
  32. 14
      tests/islandora_hooks_test.module
  33. 7
      tests/islandora_ingest_test.info
  34. 166
      tests/islandora_ingest_test.module
  35. 114
      tests/islandora_manage_permissions.test
  36. 130
      tests/islandora_web_test_case.inc
  37. 14
      tests/scripts/line_endings.sh
  38. 40
      tests/scripts/travis_setup.sh
  39. 6
      tests/travis.test_config.ini
  40. 17
      theme/islandora-objects-grid.tpl.php
  41. 29
      theme/islandora-objects-list.tpl.php
  42. 21
      theme/islandora-objects.tpl.php
  43. 161
      theme/theme.inc

19
.travis.yml

@ -0,0 +1,19 @@
language: php
php:
- 5.3.3
- 5.4
branches:
only:
- 7.x
env:
- FEDORA_VERSION="3.5"
before_install:
- export ISLANDORA_DIR=$TRAVIS_BUILD_DIR
- $TRAVIS_BUILD_DIR/tests/scripts/travis_setup.sh
- cd $HOME/drupal-*
script:
- ant -buildfile sites/all/modules/islandora/build.xml lint
- $ISLANDORA_DIR/tests/scripts/line_endings.sh sites/all/modules/islandora
- 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

27
README.txt → README.md

@ -1,16 +1,10 @@
CONTENTS OF THIS FILE BUILD STATUS
--------------------- ------------
Current build status:
* summary [![Build Status](https://travis-ci.org/Islandora/islandora.png?branch=7.x)](https://travis-ci.org/Islandora/islandora)
* requirements
* installation
* configuration
* customization
* troubleshooting
* faq
* contact
* sponsors
CI Server:
http://jenkins.discoverygarden.ca
SUMMARY SUMMARY
------- -------
@ -29,7 +23,11 @@ https://jira.duraspace.org/browse/ISLANDORA
REQUIREMENTS 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 INSTALLATION
------------ ------------
@ -41,7 +39,7 @@ should be copied into the Fedora global XACML policies folder. This will allow
CONFIGURATION CONFIGURATION
------------- -------------
The islandora_drupal_filter passes the username of 'anonymous' through to The islandora_drupal_filter passes the username of 'anonymous' through to
Fedora for unauthenticated Drupal Users. A user with the name of 'anonymous' Fedora for unauthenticated Drupal Users. A user with the name of 'anonymous'
may have XACML policies applied to them that are meant to be applied to Drupal may have XACML policies applied to them that are meant to be applied to Drupal
users that are not logged in or vice-versa. This is a potential security issue users that are not logged in or vice-versa. This is a potential security issue
@ -53,6 +51,7 @@ Drupal's cron will can be ran to remove expired authentication tokens.
CUSTOMIZATION CUSTOMIZATION
------------- -------------
[Customize ingest forms](http://github.com/Islandora/islandora/wiki/Multi-paged-Ingest-Forms)
TROUBLESHOOTING TROUBLESHOOTING
--------------- ---------------

164
build.xml

@ -1,110 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project name="islandora" default="build"> <project name="islandora" default="build">
<target name="build" <target name="build" depends="clean,prepare,lint,phploc,code_sniff,phpcpd,pdepend,doxygen,phpcb,test" />
depends="prepare,lint,doxygen,phploc,pdepend,phpcs-ci,phpcpd,phpcb"/>
<target name="clean" description="Cleanup build artifacts"> <target name="clean" description="Cleanup build artifacts">
<delete dir="${basedir}/build/api"/> <delete dir="${basedir}/build/test" />
<delete dir="${basedir}/build/code-browser"/> <delete dir="${basedir}/build/logs" />
<delete dir="${basedir}/build/coverage"/> <delete dir="${basedir}/build/pdepend" />
<delete dir="${basedir}/build/logs"/> <delete dir="${basedir}/build/api" />
<delete dir="${basedir}/build/pdepend"/> <delete dir="${basedir}/build/code-browser" />
</target> </target>
<target name="prepare" depends="clean" <target name="prepare" description="Prepares workspace for artifacts" >
description="Prepare for build"> <mkdir dir="${basedir}/build/test" />
<mkdir dir="${basedir}/build/api"/> <mkdir dir="${basedir}/build/logs" />
<mkdir dir="${basedir}/build/code-browser"/> <mkdir dir="${basedir}/build/pdepend" />
<mkdir dir="${basedir}/build/coverage"/> <mkdir dir="${basedir}/build/api" />
<mkdir dir="${basedir}/build/logs"/> <mkdir dir="${basedir}/build/code-browser" />
<mkdir dir="${basedir}/build/pdepend"/> </target>
</target>
<target name="lint"> <target name="lint" description="Perform syntax check of sourcecode files">
<apply executable="php" failonerror="true"> <apply executable="php" failonerror="true">
<arg value="-l" /> <arg value="-l" />
<fileset dir="${basedir}"> <fileset dir="${basedir}">
<include name="**/*.php" /> <include name="**/*.php" />
<modified /> <include name="**/*.inc" />
</fileset> <include name="**/*.module" />
</apply> <include name="**/*.install" />
</target> <include name="**/*.test" />
<modified />
</fileset>
</apply>
</target>
<target name="phploc" description="Measure project size using PHPLOC"> <target name="phploc" description="Measure project size using PHPLOC">
<exec executable="phploc"> <exec executable="phploc">
<arg value="--log-csv" /> <arg line="--log-csv ${basedir}/build/logs/phploc.csv --exclude build --exclude css --exclude images --exclude xml --names *.php,*.module,*.inc,*.test,*.install ${basedir}" />
<arg value="${basedir}/build/logs/phploc.csv" /> </exec>
<arg path="${basedir}" /> </target>
</exec>
</target>
<target name="pdepend" <target name="code_sniff" description="Checks the code for Drupal coding standard violations" >
description="Calculate software metrics using PHP_Depend"> <exec executable="phpcs">
<exec executable="pdepend"> <arg line="--standard=Drupal --report=checkstyle --report-file=${basedir}/build/logs/checkstyle.xml --extensions=php,inc,test,module,install --ignore=build/,xml/,images/,css/ ${basedir}" />
<arg value="--jdepend-xml=${basedir}/build/logs/jdepend.xml" /> </exec>
<arg value="--jdepend-chart=${basedir}/build/pdepend/dependencies.svg" /> </target>
<arg value="--overview-pyramid=${basedir}/build/pdepend/overview-pyramid.svg" />
<arg path="${basedir}" />
</exec>
</target>
<target name="phpcs" <target name="phpcpd" description="Copy/Paste code detection">
description="Find coding standard violations using PHP_CodeSniffer and print human readable output. Intended for usage on the command line before committing."> <exec executable="phpcpd">
<exec executable="phpcs"> <arg line="--log-pmd ${basedir}/build/logs/pmd-cpd.xml --exclude build --exclude css --exclude images --exclude xml --names *.php,*.module,*.inc,*.test,*.install ${basedir}" />
<arg value="--standard=Drupal" /> </exec>
<arg value="--extensions=php" /> </target>
<arg value="--ignore=build/" />
<arg path="${basedir}" />
</exec>
</target>
<target name="phpcs-ci" <target name="pdepend" description="Calculate software metrics using PHP_Depend">
description="Find coding standard violations using PHP_CodeSniffer creating a log file for the continuous integration server"> <exec executable="pdepend">
<exec executable="phpcs" output="/dev/null"> <arg line="--jdepend-xml=${basedir}/build/logs/jdepend.xml --jdepend-chart=${basedir}/build/pdepend/dependencies.svg --overview-pyramid=${basedir}/build/pdepend/overview-pyramid.svg ${basedir}"/>
<arg value="--report=checkstyle" /> </exec>
<arg value="--extensions=php" /> </target>
<arg value="--ignore=build/" />
<arg value="--report-file=${basedir}/build/logs/checkstyle.xml" />
<arg value="--standard=Drupal" />
<arg path="${basedir}" />
</exec>
</target>
<target name="phpcpd" description="Find duplicate code using PHPCPD"> <target name="doxygen" description="Generate API documentation with doxygen" depends="prepare">
<exec executable="phpcpd"> <exec executable="bash">
<arg value="--log-pmd" /> <arg line='-c "sed -i s/PROJECT_NUMBER\ \ \ \ \ \ \ \ \ =/PROJECT_NUMBER\ \ \ \ \ \ \ \ \ =\ `git log -1 --pretty=format:%h`/ build/Doxyfile"'/>
<arg value="${basedir}/build/logs/pmd-cpd.xml" /> </exec>
<arg path="${basedir}" /> <exec executable="doxygen">
</exec> <arg line="${basedir}/build/Doxyfile" />
</target> </exec>
<exec executable="git">
<arg line="checkout ${basedir}/build/Doxyfile"/>
</exec>
</target>
<target name="doxygen" description="Generate API documentation with doxygen" depends="prepare"> <target name="phpcb" description="Aggregate tool output with PHP_CodeBrowser">
<echo file="${basedir}/build/Doxyfile" append="true" message="PROJECT_NUMBER = "/> <exec executable="phpcb">
<exec executable="git" output="${basedir}/build/Doxyfile" append="true"> <arg line="--log ${basedir}/build/logs --source ${basedir} --output ${basedir}/build/code-browser"/>
<arg value="log" /> </exec>
<arg value="-1" /> </target>
<arg value="--pretty=format:%h" />
</exec>
<exec executable="doxygen">
<arg path="${basedir}/build/Doxyfile" />
</exec>
<exec executable="git">
<arg value="checkout" />
<arg path="${basedir}/build/Doxyfile" />
</exec>
</target>
<target name="phpcb" <target name="test">
description="Aggregate tool output with PHP_CodeBrowser"> <exec executable="bash">
<exec executable="phpcb"> <arg line='-c "php ../../../../scripts/run-tests.sh --xml ${basedir}/build/test Islandora"' />
<arg value="--log" /> </exec>
<arg path="${basedir}/build/logs" /> </target>
<arg value="--source" />
<arg path="${basedir}" />
<arg value="--output" />
<arg path="${basedir}/build/code-browser" />
</exec>
</target>
</project> </project>

3
build/Doxyfile

@ -27,6 +27,9 @@ DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = Islandora 7.x PROJECT_NAME = Islandora 7.x
# Put the git hash here using sed before generating the documentation.
PROJECT_NUMBER =
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put. # base path where the generated documentation will be put.
# If a relative path is entered, it will be relative to the location # If a relative path is entered, it will be relative to the location

39
css/islandora.objects.css

@ -0,0 +1,39 @@
/**
* @file
* Styles for rendering grids/lists of objects.
*/
.islandora-objects-display-switch {
float: right;
}
.islandora-objects-grid-item {
display: inline-block;
width: 20%;
min-width: 100px;
min-height: 180px;
display: -moz-inline-stack;
display: inline-block;
vertical-align: top;
margin: 1.5em 1.84%;
zoom: 1;
*display: inline;
_height: 180px;
}
.islandora-objects-list-item {
padding-bottom: 1.5em;
border-bottom: 1px solid #ddd;
}
.islandora-objects-list-item .islandora-object-thumb {
clear: left;
float: left;
padding: 3px 0 0;
text-align: center;
width: 100px;
}
.islandora-objects-list-item .islandora-object-caption, .islandora-objects-list-item .islandora-object-description {
margin: 0 0 0 130px;
padding-top: 2px;
padding-bottom: 2px;
}
.islandora-object-thumb img {
width: 100%;
}

12
includes/add_datastream.form.inc

@ -12,13 +12,13 @@
* The Drupal form. * The Drupal form.
* @param array $form_state * @param array $form_state
* The Drupal form state. * The Drupal form state.
* @param FedoraObject $object * @param AbstractObject $object
* The object to be deleted. * The object to be deleted.
* *
* @return array * @return array
* The drupal form definition. * 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/content_model');
module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('inc', 'islandora', 'includes/utilities');
form_load_include($form_state, 'inc', 'islandora', 'includes/add_datastream.form'); form_load_include($form_state, 'inc', 'islandora', 'includes/add_datastream.form');
@ -39,7 +39,7 @@ function islandora_add_datastream_form(array $form, array &$form_state, FedoraOb
'#collapsed' => FALSE, '#collapsed' => FALSE,
'dsid' => array( 'dsid' => array(
'#title' => 'Datastream ID', '#title' => 'Datastream ID',
'#description' => t("An ID for this stream that is unique to this object. Must start with a letter and contain only alphanumeric characters and dashes and underscores. Datastreams that are defined by the content model don't currently exist: <b>@unused_dsids</b>.", array('@unused_dsids' => $unused_datastreams)), '#description' => t("An ID for this stream that is unique to this object. Must start with a letter and contain only alphanumeric characters, dashes and underscores. The following datastreams are defined by this content model but don't currently exist: <b>@unused_dsids</b>.", array('@unused_dsids' => $unused_datastreams)),
), ),
'#type' => 'textfield', '#type' => 'textfield',
'#size' => 64, '#size' => 64,
@ -57,7 +57,7 @@ function islandora_add_datastream_form(array $form, array &$form_state, FedoraOb
'#required' => TRUE, '#required' => TRUE,
'#size' => 64, '#size' => 64,
'#maxlength' => 64, '#maxlength' => 64,
'#description' => t('A Human readable label'), '#description' => t('A human-readable label'),
'#type' => 'textfield', '#type' => 'textfield',
'#element_validate' => array('islandora_add_datastream_form_field_does_not_contain_a_forward_slash'), '#element_validate' => array('islandora_add_datastream_form_field_does_not_contain_a_forward_slash'),
), ),
@ -206,13 +206,13 @@ function islandora_add_datastream_form_submit(array $form, array &$form_state) {
* *
* It lists the missing required (may be optional) datastreams. * 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 object used to check for missing required datastreams used to populate
* the options in this callback. * the options in this callback.
* @param string $query * @param string $query
* vThe user query to match against the missing required datastreams. * 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/content_model');
module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('inc', 'islandora', 'includes/utilities');
$dsids = array_keys(islandora_get_missing_datastreams_requirements($object)); $dsids = array_keys(islandora_get_missing_datastreams_requirements($object));

225
includes/admin.form.inc

@ -19,139 +19,111 @@
function islandora_repository_admin(array $form, array &$form_state) { function islandora_repository_admin(array $form, array &$form_state) {
module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('inc', 'islandora', 'includes/utilities');
drupal_add_css(drupal_get_path('module', 'islandora') . '/css/islandora.admin.css'); drupal_add_css(drupal_get_path('module', 'islandora') . '/css/islandora.admin.css');
$url = islandora_system_settings_form_default_value('islandora_base_url', 'http://localhost:8080/fedora', $form_state);
$restrict_namespaces = islandora_system_settings_form_default_value('islandora_namespace_restriction_enforced', FALSE, $form_state);
$confirmation_message = islandora_admin_settings_form_repository_access_message($url);
$form = array(
'islandora_tabs' => array(
'#type' => 'vertical_tabs',
'islandora_general' => array(
'#type' => 'fieldset',
'#title' => t('General Configuarion'),
'wrapper' => array(
'#prefix' => '<div id="islandora-url">',
'#suffix' => '</div>',
'#type' => 'markup',
'islandora_base_url' => array(
'#type' => 'textfield',
'#title' => t('Fedora base URL'),
'#default_value' => variable_get('islandora_base_url', 'http://localhost:8080/fedora'),
'#description' => t('The URL to use for REST connections <br/> !confirmation_message', array(
'!confirmation_message' => $confirmation_message)),
'#required' => TRUE,
'#ajax' => array(
'callback' => 'islandora_update_url_div',
'wrapper' => 'islandora-url',
'effect' => 'fade',
'event' => 'blur',
'progress' => array('type' => 'throbber'),
),
),
),
'islandora_repository_pid' => array(
'#type' => 'textfield',
'#title' => t('Root Collection PID'),
'#default_value' => variable_get('islandora_repository_pid', 'islandora:root'),
'#description' => t('The PID of the Root Collection Object'),
'#required' => TRUE,
),
),
'islandora_namespace' => array(
'#type' => 'fieldset',
'#title' => t('Namespaces'),
'islandora_namespace_restriction_enforced' => array(
'#type' => 'checkbox',
'#title' => t('Enforce namespace restrictions'),
'#description' => t("Allow administrator to restrict user's access to the PID namepaces listed below"),
'#default_value' => $restrict_namespaces,
),
'islandora_pids_allowed' => array(
'#type' => 'textfield',
'#title' => t('PID namespaces allowed in this Drupal install'),
'#description' => t('A list of PID namespaces, separated by spaces, that users are permitted to access from this Drupal installation. <br /> This could be more than a simple namespace, e.g. <b>demo:mydemos</b>. <br /> The namespace <b>islandora:</b> is reserved, and is always allowed.'),
'#default_value' => variable_get('islandora_pids_allowed', 'default: demo: changeme: ilives: islandora-book: books: newspapers: '),
'#states' => array(
'invisible' => array(
':input[name="islandora_namespace_restriction_enforced"]' => array('checked' => FALSE),
),
),
),
),
),
);
return system_settings_form($form);
}
$form = array(); /**
if (isset($form_state['values']['islandora_base_url'])) { * Gets a message which describes if the repository is accessible.
$url = $form_state['values']['islandora_base_url']; *
} * Also describes if the user is considered an authenticated user by the
else { * repository.
$url = variable_get('islandora_base_url', 'http://localhost:8080/fedora'); *
} * @param string $url
* The url to the Fedora Repository.
*
* @return string
* A message describing the accessibility of the repository at the given url.
*/
function islandora_admin_settings_form_repository_access_message($url) {
$info = $dc = FALSE;
$connection = islandora_get_tuque_connection(NULL, $url); $connection = islandora_get_tuque_connection(NULL, $url);
if (!$connection) { if ($connection) {
return;
}
try {
$info = $connection->api->a->describeRepository();
}
catch (RepositoryException $e) {
$info = FALSE;
}
if ($info) {
try { try {
$info = $connection->api->a->describeRepository();
// If we are able to successfully call API-M::getDatastream, assume we are
// an authenticated user, as API-M is usally locked down.
$dc = $connection->api->m->getDatastream('fedora-system:ContentModel-3.0', 'DC'); $dc = $connection->api->m->getDatastream('fedora-system:ContentModel-3.0', 'DC');
} }
catch (RepositoryException $e) { catch (RepositoryException $e) {
$dc = FALSE; // Ignore, we only testing to see what is accessible.
} }
} }
if ($info && $dc) {
if ($info) { $confirmation_message = theme_image(array('path' => 'misc/watchdog-ok.png', 'attributes' => array()));
if ($dc) { $confirmation_message .= t('Successfully connected to Fedora Server (Version !version).', array(
$confirmation_message = theme_image(array('path' => 'misc/watchdog-ok.png', 'attributes' => array())); '!version' => $info['repositoryVersion']));
$confirmation_message .= t('Successfully connected to Fedora Server (Version !version).', array( }
'!version' => $info['repositoryVersion'])); elseif ($info) {
} $confirmation_message = theme_image(array('path' => 'misc/watchdog-warning.png', 'attributes' => array()));
else { $confirmation_message .= t('Unable to authenticate when connecting to to Fedora Server (Version !version). Please configure the !filter.', array(
$confirmation_message = theme_image(array('path' => 'misc/watchdog-warning.png', 'attributes' => array())); '!version' => $info['repositoryVersion'], '!filter' => 'Drupal Filter'));
$confirmation_message .= t('Unable to authenticate when connecting to to Fedora Server (Version !version). Please configure the !filter.',
array('!version' => $info['repositoryVersion'], '!filter' => 'Drupal Filter'));
}
} }
else { else {
$confirmation_message = theme_image(array('path' => 'misc/watchdog-error.png', 'attributes' => array())); $confirmation_message = theme_image(array('path' => 'misc/watchdog-error.png', 'attributes' => array()));
$confirmation_message .= t('Unable to connect to Fedora server at !islandora_url', array( $confirmation_message .= t('Unable to connect to Fedora server at !islandora_url', array(
'!islandora_url' => $url)); '!islandora_url' => $url));
} }
return $confirmation_message;
$form['islandora_tabs'] = array(
'#type' => 'vertical_tabs',
);
$form['islandora_tabs']['islandora_general'] = array(
'#type' => 'fieldset',
'#title' => t('General Configuarion'),
);
// Ajax wrapper for url checking.
$form['islandora_tabs']['islandora_general']['wrapper'] = array(
'#prefix' => '<div id="islandora-url">',
'#suffix' => '</div>',
'#type' => 'markup',
);
$form['islandora_tabs']['islandora_general']['wrapper']['islandora_base_url'] = array(
'#type' => 'textfield',
'#title' => t('Fedora base URL'),
'#default_value' => variable_get('islandora_base_url', 'http://localhost:8080/fedora'),
'#description' => t('The URL to use for REST connections <br /> !confirmation_message', array(
'!confirmation_message' => $confirmation_message,
)),
'#required' => TRUE,
'#ajax' => array(
'callback' => 'islandora_update_url_div',
'wrapper' => 'islandora-url',
'effect' => 'fade',
'event' => 'blur',
'progress' => array('type' => 'throbber'),
),
);
$form['islandora_tabs']['islandora_general']['islandora_repository_pid'] = array(
'#type' => 'textfield',
'#title' => t('Root Collection PID'),
'#default_value' => variable_get('islandora_repository_pid', 'islandora:root'),
'#description' => t('The PID of the Root Collection Object'),
'#required' => TRUE,
);
$form['islandora_tabs']['islandora_namespace'] = array(
'#type' => 'fieldset',
'#title' => t('Namespaces'),
);
$form['islandora_tabs']['islandora_namespace']['wrapper'] = array(
'#type' => 'markup',
'#prefix' => '<div id="islandora-namespace">',
'#suffix' => '</div>',
);
$form['islandora_tabs']['islandora_namespace']['wrapper']['islandora_namespace_restriction_enforced'] = array(
'#weight' => -1,
'#type' => 'checkbox',
'#title' => t('Enforce namespace restrictions'),
'#description' => t("Allow administrator to restrict user's access to the PID namepaces listed below"),
'#default_value' => variable_get('islandora_namespace_restriction_enforced', FALSE),
'#ajax' => array(
'callback' => 'islandora_update_namespace_div',
'wrapper' => 'islandora-namespace',
'effect' => 'fade',
'event' => 'change',
'progress' => array('type' => 'throbber'),
),
);
if (isset($form_state['values']['islandora_namespace_restriction_enforced'])) {
$namespaces = $form_state['values']['islandora_namespace_restriction_enforced'];
}
else {
$namespaces = variable_get('islandora_namespace_restriction_enforced', FALSE);
}
if ($namespaces) {
$form['islandora_tabs']['islandora_namespace']['wrapper']['islandora_pids_allowed'] = array(
'#type' => 'textfield',
'#title' => t('PID namespaces allowed in this Drupal install'),
'#default_value' => variable_get('islandora_pids_allowed', 'default: demo: changeme: ilives: islandora-book: books: newspapers: '),
'#description' => t('A space separated list of PID namespaces that users are permitted to access from this Drupal installation. <br /> This could be more than a simple namespace ie demo:mydemos. <br /> islandora: is reserved and is always allowed.'),
'#weight' => 0,
);
}
return system_settings_form($form);
} }
/** /**
@ -168,18 +140,3 @@ function islandora_repository_admin(array $form, array &$form_state) {
function islandora_update_url_div(array $form, array $form_state) { function islandora_update_url_div(array $form, array $form_state) {
return $form['islandora_tabs']['islandora_general']['wrapper']; return $form['islandora_tabs']['islandora_general']['wrapper'];
} }
/**
* Get the element to render for the AJAX event that triggered this callback.
*
* @param array $form
* The Drupal form definition.
* @param array $form_state
* The Drupal form state.
*
* @return array
* The form element to render.
*/
function islandora_update_namespace_div(array $form, array $form_state) {
return $form['islandora_tabs']['islandora_namespace']['wrapper'];
}

78
includes/breadcrumb.inc

@ -14,7 +14,7 @@
* ancestry which is identified by any of the following RELS-EXT terms * ancestry which is identified by any of the following RELS-EXT terms
* (isMemberOf,isMemberOfCollection,isPartOf). * (isMemberOf,isMemberOfCollection,isPartOf).
* *
* @param FedoraObject $object * @param AbstractObject $object
* An object whose ancestry will be mapped to bread-crumbs. * An object whose ancestry will be mapped to bread-crumbs.
* *
* @see drupal_set_breadcrumb() * @see drupal_set_breadcrumb()
@ -25,13 +25,8 @@
* drupal_set_breadcrumb(). * drupal_set_breadcrumb().
*/ */
function islandora_get_breadcrumbs($object) { function islandora_get_breadcrumbs($object) {
$breadcrumbs = array(); $breadcrumbs = islandora_get_breadcrumbs_recursive($object->id, $object->repository);
islandora_get_breadcrumbs_recursive($object->id, $breadcrumbs, $object->repository); array_pop($breadcrumbs);
if (isset($breadcrumbs[0])) {
// Remove the actual object.
unset($breadcrumbs[0]);
}
$breadcrumbs = array_reverse($breadcrumbs);
return $breadcrumbs; return $breadcrumbs;
} }
@ -40,30 +35,44 @@ function islandora_get_breadcrumbs($object) {
* *
* @todo Make fully recursive... * @todo Make fully recursive...
* *
* @todo Could use some clean up, can't be called multiple times safely due to
* the use of static variables.
*
* @param string $pid * @param string $pid
* THe object id whose parent will be fetched for the next link. * The object id whose parent will be fetched for the next link.
* @param array $breadcrumbs
* The list of existing bread-crumb links in reverse order.
* @param FedoraRepository $repository * @param FedoraRepository $repository
* The fedora repository. * The fedora repository.
* @param array $context
* An associative array of context for internal use when recursing. Currently
* only used to track a single value:
* - level: The number of child-parent relationships to follow. Defaults to
* 10.
*
* @return array
* An array of links representing the breadcrumb trail, "root" first.
*/ */
function islandora_get_breadcrumbs_recursive($pid, array &$breadcrumbs, FedoraRepository $repository) { function islandora_get_breadcrumbs_recursive($pid, FedoraRepository $repository, array &$context = NULL) {
// Before executing the query, we have a base case of accessing the top-level // Before executing the query, we have a base case of accessing the top-level
// collection. // collection.
static $max_level = 10; if ($context === NULL) {
static $level = -1; $context['level'] = 10;
if (count($breadcrumbs) === 0) {
$level = $max_level;
} }
$root = variable_get('islandora_repository_pid', 'islandora:root'); $root = variable_get('islandora_repository_pid', 'islandora:root');
if ($pid == $root) { if ($pid == $root) {
$breadcrumbs[] = l(menu_get_active_title(), 'islandora'); $title = 'Islandora Repository';
$breadcrumbs[] = l(t('Home'), '<front>'); $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'), '<front>'),
l($title, 'islandora'),
);
} }
else { else {
$query_string = 'select $parentObject $title $content from <#ri> $query_string = 'select $parentObject $title $content from <#ri>
@ -82,7 +91,7 @@ function islandora_get_breadcrumbs_recursive($pid, array &$breadcrumbs, FedoraRe
order by $title desc'; order by $title desc';
$results = $repository->ri->itqlQuery($query_string); $results = $repository->ri->itqlQuery($query_string);
if (count($results) > 0 && $level > 0) { if (count($results) > 0 && $context['level'] > 0) {
$parent = $results[0]['parentObject']['value']; $parent = $results[0]['parentObject']['value'];
$this_title = $results[0]['title']['value']; $this_title = $results[0]['title']['value'];
@ -90,16 +99,23 @@ function islandora_get_breadcrumbs_recursive($pid, array &$breadcrumbs, FedoraRe
$this_title = t('-'); $this_title = t('-');
} }
$breadcrumbs[] = l($this_title, "islandora/object/$pid"); $context['level']--;
return array_merge(
$level--; islandora_get_breadcrumbs_recursive($parent, $repository, $context),
islandora_get_breadcrumbs_recursive($parent, $breadcrumbs, $repository); array(
l($this_title, "islandora/object/$pid"),
)
);
} }
else { else {
// Add an non-link, as we don't know how to get back to the root. // Add an non-link, as we don't know how to get back to the root, and
$breadcrumbs[] = '...'; // render the last two links and break (on the next pass).
// And render the last two links and break (on the next pass). return array_merge(
islandora_get_breadcrumbs_recursive($root, $breadcrumbs, $repository); islandora_get_breadcrumbs_recursive($root, $repository, $context),
array(
'...',
)
);
} }
} }
} }

57
includes/content_model.autocomplete.inc

@ -0,0 +1,57 @@
<?php
/**
* @file
* Autocomplete functionality for content models in Islandora.
*/
/**
* Autocomplete the content model name.
*
* @param string $string
* A search string.
*
* @return string
* The rendered JSON results.
*/
function islandora_content_model_autocomplete($string) {
$content_models = islandora_get_content_model_names();
$output = array();
foreach ($content_models as $model => $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;
}

84
includes/datastream.inc

@ -8,10 +8,10 @@
/** /**
* Callback to download the given datastream to the users computer. * Callback to download the given datastream to the users computer.
* *
* @param FedoraDatastream $datastream * @param AbstractDatastream $datastream
* The datastream to download. * The datastream to download.
*/ */
function islandora_download_datastream(FedoraDatastream $datastream) { function islandora_download_datastream(AbstractDatastream $datastream) {
islandora_view_datastream($datastream, TRUE); islandora_view_datastream($datastream, TRUE);
} }
@ -21,13 +21,13 @@ function islandora_download_datastream(FedoraDatastream $datastream) {
* @note * @note
* This function calls exit(). * This function calls exit().
* *
* @param FedoraDatastream $datastream * @param AbstractDatastream $datastream
* The datastream to view/download. * The datastream to view/download.
* @param bool $download * @param bool $download
* If TRUE the file is download to the user computer for viewing otherwise it * If TRUE the file is download to the user computer for viewing otherwise it
* will attempt to display in the browser natively. * 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('Cache-Control');
header_remove('Expires'); header_remove('Expires');
header('Content-type: ' . $datastream->mimetype); 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. * Get the human readable size of the given datastream.
* *
* @param FedoraDatastream $datastream * @param AbstractDatastream $datastream
* The datastream to check. * The datastream to check.
* *
* @return string * @return string
* A human readable size of the given datastream, or '-' if the size could not * A human readable size of the given datastream, or '-' if the size could not
* be determined. * 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'); module_load_include('inc', 'islandora', 'includes/utilities');
$size_is_calculatable = $datastream->controlGroup == 'M' || $datastream->controlGroup == 'X'; $size_is_calculatable = $datastream->controlGroup == 'M' || $datastream->controlGroup == 'X';
return $size_is_calculatable ? islandora_convert_bytes_to_human_readable($datastream->size) : '-'; return $size_is_calculatable ? islandora_convert_bytes_to_human_readable($datastream->size) : '-';
@ -67,47 +67,53 @@ function islandora_datastream_get_human_readable_size(FedoraDatastream $datastre
/** /**
* Get either the 'view' or 'download' url for the given datastream if possible. * 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. * The datastream to generated the url to.
* *
* @return string * @return string
* either the 'view' or 'download' url for the given datastream. * 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"; return $datastream->controlGroup == 'R' ? $datastream->url : "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/$type";
} }
/** /**
* Gets the delete link. * Gets the delete link.
* *
* @param FedoraDatastream $datastream * @param AbstractDatastream $datastream
* The datastream to generated the url to. * 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); $message = islandora_deprecated('7.x-1.2', 'Use the "islandora_datastream_delete_link" theme implementation.');
$can_delete = !in_array($datastream->id, $datastreams); trigger_error(filter_xss($message), E_USER_DEPRECATED);
return $can_delete ? l(t('delete'), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/delete") : '';
return theme('islandora_datastream_delete_link', array(
'datastream' => $datastream,
));
} }
/** /**
* Gets the edit link. * Gets the edit link.
* *
* @param FedoraDatastream $datastream * @param AbstractDatastream $datastream
* The datastream to generated the url to. * 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); $message = islandora_deprecated('7.x-1.2', 'Use the "islandora_datastream_edit_link" theme implementation.');
$can_edit = count($edit_registry) > 0 && user_access(FEDORA_METADATA_EDIT); trigger_error(filter_xss($message), E_USER_DEPRECATED);
return $can_edit ? l(t('edit'), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/edit") : '';
return theme('islandora_datastream_edit_link', array(
'datastream' => $datastream,
));
} }
/** /**
* Display the edit datastream page. * Display the edit datastream page.
* *
* @param FedoraDatastream $datastream * @param AbstractDatastream $datastream
* The datastream to edit. * 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_registry = module_invoke_all('islandora_edit_datastream_registry', $datastream->parent, $datastream);
$edit_count = count($edit_registry); $edit_count = count($edit_registry);
switch ($edit_count) { switch ($edit_count) {
@ -144,3 +150,41 @@ function islandora_edit_datastream_registry_render(array $edit_registry) {
'#markup' => $markup, '#markup' => $markup,
); );
} }
/**
* Get markup for a download link.
*
* @param AbstractDatastream $datastream
* The datastream for which to generate a link.
*
* @return string
* Either the link markup if the user has access or an empty string if the
* user is not allowed to see the given datastream.
*/
function islandora_datastream_get_download_link(AbstractDatastream $datastream) {
$message = islandora_deprecated('7.x-1.2', 'Use the "islandora_datastream_download_link" theme implementation.');
trigger_error(filter_xss($message), E_USER_DEPRECATED);
return theme('islandora_datastream_download_link', array(
'datastream' => $datastream,
));
}
/**
* Get markup for a view link.
*
* @param AbstractDatastream $datastream
* The datastream for which to generate a link.
*
* @return string
* Either the link markup if the user has access or a string containing the
* datastream ID if the user is not allowed to see the given datastream.
*/
function islandora_datastream_get_view_link(AbstractDatastream $datastream) {
$message = islandora_deprecated('7.x-1.2', 'Use the "islandora_datastream_view_link" theme implementation.');
trigger_error(filter_xss($message), E_USER_DEPRECATED);
return theme('islandora_datastream_view_link', array(
'datastream' => $datastream,
));
}

6
includes/delete_datastream.form.inc

@ -12,13 +12,13 @@
* The Drupal form. * The Drupal form.
* @param array $form_state * @param array $form_state
* The Drupal form state. * The Drupal form state.
* @param FedoraDatastream $datastream * @param AbstractDatastream $datastream
* The datastream to be deleted. * The datastream to be deleted.
* *
* @return array * @return array
* The drupal form definition. * 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; $form_state['datastream'] = $datastream;
return confirm_form($form, return confirm_form($form,
t('Are you sure you want to delete the %dsid datastream?', array('%dsid' => $datastream->id)), 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. * 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 * The ISLANDORA_PRE_PURGE_DATASTREAM_HOOK will query other modules as to
* whether the given FedoraDatastream * whether the given FedoraDatastream

4
includes/delete_object.form.inc

@ -12,13 +12,13 @@
* The Drupal form. * The Drupal form.
* @param array $form_state * @param array $form_state
* The Drupal form state. * The Drupal form state.
* @param FedoraObject $object * @param AbstractObject $object
* The object to be deleted. * The object to be deleted.
* *
* @return array * @return array
* The drupal form definition. * 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; $form_state['object'] = $object;
return confirm_form($form, return confirm_form($form,
t('Are you sure you want to delete %title?', array('%title' => $object->label)), t('Are you sure you want to delete %title?', array('%title' => $object->label)),

485
includes/ingest.form.inc

@ -5,6 +5,25 @@
* Defines the multi-page ingest form and any relevant hooks and functions. * 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. * Ingest form build function.
* *
@ -26,6 +45,8 @@
* be related. * be related.
* - models: An array of content model PIDs, to which the new object might * - models: An array of content model PIDs, to which the new object might
* subscribe * subscribe
* - parent: The parent of the child to be ingested. This is needed for XACML
* to correctly apply the parent's POLICY to children.
* *
* @return array * @return array
* The form definition of the current step. * The form definition of the current step.
@ -35,33 +56,13 @@ function islandora_ingest_form(array $form, array &$form_state, array $configura
islandora_ingest_form_init_form_state_storage($form_state, $configuration); islandora_ingest_form_init_form_state_storage($form_state, $configuration);
return islandora_ingest_form_execute_step($form, $form_state); return islandora_ingest_form_execute_step($form, $form_state);
} }
catch(Exception $e) { catch (Exception $e) {
drupal_set_message($e->getMessage(), 'error'); drupal_set_message($e->getMessage(), 'error');
return array(array( return array(array(
'#markup' => l(t('Back'), 'javascript:window.history.back();', array('external' => TRUE)))); '#markup' => l(t('Back'), 'javascript:window.history.back();', array('external' => TRUE))));
} }
} }
/**
* 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. * Initializes the form_state storage for use in the ingest multi-page forms.
* *
@ -73,18 +74,62 @@ function islandora_ingest_form_validate_configuration(array $configuration) {
*/ */
function islandora_ingest_form_init_form_state_storage(array &$form_state, array $configuration) { function islandora_ingest_form_init_form_state_storage(array &$form_state, array $configuration) {
if (empty($form_state['islandora'])) { if (empty($form_state['islandora'])) {
// Validate the configuration before we use it. $objects = isset($configuration['objects']) ? $configuration['objects'] : array();
islandora_ingest_form_validate_configuration($configuration); if (empty($objects)) {
$object = islandora_ingest_form_prepare_new_object($configuration); $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( $form_state['islandora'] = array(
'step_id' => NULL, 'step_id' => NULL,
'objects' => array($object), 'objects' => $objects,
'shared_storage' => $configuration, 'shared_storage' => $configuration,
'step_storage' => array(), 'step_storage' => array(),
); );
// Must be called after $form_state['islandora'] is initialized, otherwise,
// the values in 'islandora' would not be availible to the step hooks.
$form_state['islandora']['step_id'] = islandora_ingest_form_get_first_step_id($form_state);
} }
} }
/**
* Get the first step ID.
*
* @param array $form_state
* The Drupal form state.
*
* @return string
* The 'id' of the very first step.
*/
function islandora_ingest_form_get_first_step_id(array &$form_state) {
$steps = islandora_ingest_form_get_steps($form_state);
$keys = array_keys($steps);
return array_shift($keys);
}
/**
* Get the last step ID.
*
* @param array $form_state
* The Drupal form state.
*
* @return string
* The 'id' of the very last step.
*/
function islandora_ingest_form_get_last_step_id(array &$form_state) {
$steps = islandora_ingest_form_get_steps($form_state);
$keys = array_keys($steps);
return array_pop($keys);
}
/** /**
* Prepares a new object based on the given configuration. * Prepares a new object based on the given configuration.
* *
@ -96,27 +141,31 @@ function islandora_ingest_form_init_form_state_storage(array &$form_state, array
*/ */
function islandora_ingest_form_prepare_new_object(array $configuration) { function islandora_ingest_form_prepare_new_object(array $configuration) {
module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('inc', 'islandora', 'includes/utilities');
// ID is more specific than namespace so it will take precedence. if (empty($configuration['object'])) {
$id = isset($configuration['namespace']) ? $configuration['namespace'] : 'islandora'; $message = islandora_deprecated('7.x-1.2', t('Please use "objects" as the default ingest form configuration property.'));
$id = isset($configuration['id']) ? $configuration['id'] : $id; trigger_error(filter_xss($message), E_USER_DEPRECATED);
$label = isset($configuration['label']) ? $configuration['label'] : 'New Object'; // ID is more specific than namespace so it will take precedence.
$relationship_map = function($o) { $id = isset($configuration['namespace']) ? $configuration['namespace'] : 'islandora';
return array('relationship' => 'isMemberOfCollection', 'pid' => $o); $id = isset($configuration['id']) ? $configuration['id'] : $id;
}; $label = isset($configuration['label']) ? $configuration['label'] : 'New Object';
$relationships = empty($configuration['collections']) ? array() : array_map($relationship_map, $configuration['collections']); $relationship_map = function($o) {
return islandora_prepare_new_object($id, $label, array(), array(), $relationships); return array('relationship' => 'isMemberOfCollection', 'pid' => $o);
};
$relationships = empty($configuration['collections']) ? array() : array_map($relationship_map, $configuration['collections']);
return islandora_prepare_new_object($id, $label, array(), array(), $relationships);
}
return $configuration['object'];
} }
/** /**
* Gets the given/current step. * Gets the given/current step.
* *
* The current step is returned if no step ID is given. If the current step is * If the current step is not defined it's assumed that all steps have executed.
* not defined it's assume to be the first step.
* *
* @param array $form_state * @param array $form_state
* The Drupal form state. * The Drupal form state.
* @param string $step_id * @param string $step_id
* The ID of the step. * The ID of the step. The current step is returned if no step ID is given.
* *
* @return array * @return array
* The given/current step if found, NULL otherwise. * The given/current step if found, NULL otherwise.
@ -130,10 +179,48 @@ function islandora_ingest_form_get_step(array &$form_state, $step_id = NULL) {
return NULL; return NULL;
} }
/**
* Gets the next step.
*
* If the current step is not defined it's assumed that all steps have executed.
*
* @param array $form_state
* The Drupal form state.
* @param string $step
* The step relative to the result, if not provided the current step is used.
*
* @return string
* The next step if found, NULL otherwise.
*/
function islandora_ingest_form_get_next_step(array &$form_state, array $step = NULL) {
$step = isset($step) ? $step : islandora_ingest_form_get_step($form_state);
$next_step_id = islandora_ingest_form_get_next_step_id($form_state, $step['id']);
return isset($next_step_id) ? islandora_ingest_form_get_step($form_state, $next_step_id) : NULL;
}
/**
* Gets the previous step.
*
* If the current step is not defined it's assumed that all steps have executed.
*
* @param array $form_state
* The Drupal form state.
* @param string $step
* The step relative to the result, if not provided the current step is used.
*
* @return string
* The next step if found, NULL otherwise.
*/
function islandora_ingest_form_get_previous_step(array &$form_state, array $step = NULL) {
$step = isset($step) ? $step : islandora_ingest_form_get_step($form_state);
$previous_step_id = islandora_ingest_form_get_previous_step_id($form_state, $step['id']);
return isset($previous_step_id) ? islandora_ingest_form_get_step($form_state, $previous_step_id) : NULL;
}
/** /**
* Gets the ID of the current step. * Gets the ID of the current step.
* *
* If a current step is not defined, its assumed to be the first step. * If the current step is not defined it's assumed that all steps have executed.
* *
* @param array $form_state * @param array $form_state
* The Drupal form state. * The Drupal form state.
@ -142,26 +229,25 @@ function islandora_ingest_form_get_step(array &$form_state, $step_id = NULL) {
* The step ID. * The step ID.
*/ */
function islandora_ingest_form_get_current_step_id(array &$form_state) { function islandora_ingest_form_get_current_step_id(array &$form_state) {
if (empty($form_state['islandora']['step_id'])) {
$steps = islandora_ingest_form_get_steps($form_state);
return array_shift(array_keys($steps));
}
return $form_state['islandora']['step_id']; return $form_state['islandora']['step_id'];
} }
/** /**
* Gets the ID of the next step. * Gets the ID of the next step.
* *
* If a current step is not defined, its assumed to be the first step. * If the current step is not defined it's assumed that all steps have executed.
* *
* @param array $form_state * @param array $form_state
* The Drupal form state. * The Drupal form state.
* @param string $step_id
* The ID of the step relative to the result, if not provided the current
* step_id is used.
* *
* @return string * @return string
* The next step ID if found, NULL otherwise. * The next step ID if found, NULL otherwise.
*/ */
function islandora_ingest_form_get_next_step_id(array &$form_state) { function islandora_ingest_form_get_next_step_id(array &$form_state, $step_id = NULL) {
$step_id = islandora_ingest_form_get_current_step_id($form_state); $step_id = isset($step_id) ? $step_id : islandora_ingest_form_get_current_step_id($form_state);
$step_ids = array_keys(islandora_ingest_form_get_steps($form_state)); $step_ids = array_keys(islandora_ingest_form_get_steps($form_state));
$index = array_search($step_id, $step_ids); $index = array_search($step_id, $step_ids);
$count = count($step_ids); $count = count($step_ids);
@ -174,16 +260,25 @@ function islandora_ingest_form_get_next_step_id(array &$form_state) {
/** /**
* Gets the ID of the previous step. * Gets the ID of the previous step.
* *
* If a current step is not defined, its assumed to be the first step. * If the current step is not defined it's assumed that all steps have executed.
* In such cases the last step will be returned.
* *
* @param array $form_state * @param array $form_state
* The Drupal form state. * The Drupal form state.
* @param string $step_id
* The ID of the step relative to the result, if not provided the current
* step_id is used.
* *
* @return string * @return string
* The previous step ID if found, NULL otherwise. * The previous step ID if found, NULL otherwise.
*/ */
function islandora_ingest_form_get_previous_step_id(array &$form_state) { function islandora_ingest_form_get_previous_step_id(array &$form_state, $step_id = NULL) {
$step_id = islandora_ingest_form_get_current_step_id($form_state); $step_id = isset($step_id) ? $step_id : islandora_ingest_form_get_current_step_id($form_state);
// If the current step is not defined it's assumed that all steps have
// executed. So return the very last step.
if ($step_id == NULL) {
return islandora_ingest_form_get_last_step_id($form_state);
}
$step_ids = array_keys(islandora_ingest_form_get_steps($form_state)); $step_ids = array_keys(islandora_ingest_form_get_steps($form_state));
$index = array_search($step_id, $step_ids); $index = array_search($step_id, $step_ids);
if ($index !== FALSE && --$index >= 0) { if ($index !== FALSE && --$index >= 0) {
@ -203,11 +298,9 @@ function islandora_ingest_form_increment_step(array &$form_state) {
// of the current step could have added/removed a step. // of the current step could have added/removed a step.
drupal_static_reset('islandora_ingest_form_get_steps'); drupal_static_reset('islandora_ingest_form_get_steps');
$next_step_id = islandora_ingest_form_get_next_step_id($form_state); $next_step_id = islandora_ingest_form_get_next_step_id($form_state);
if (isset($next_step_id)) { islandora_ingest_form_stash_info($form_state);
islandora_ingest_form_stash_info($form_state); $form_state['islandora']['step_id'] = $next_step_id;
$form_state['islandora']['step_id'] = $next_step_id; islandora_ingest_form_grab_info($form_state);
islandora_ingest_form_grab_info($form_state);
}
} }
/** /**
@ -218,6 +311,7 @@ function islandora_ingest_form_increment_step(array &$form_state) {
*/ */
function islandora_ingest_form_decrement_step(array &$form_state) { function islandora_ingest_form_decrement_step(array &$form_state) {
$previous_step_id = islandora_ingest_form_get_previous_step_id($form_state); $previous_step_id = islandora_ingest_form_get_previous_step_id($form_state);
// Don't decrement passed the first step.
if (isset($previous_step_id)) { if (isset($previous_step_id)) {
islandora_ingest_form_stash_info($form_state); islandora_ingest_form_stash_info($form_state);
$form_state['islandora']['step_id'] = $previous_step_id; $form_state['islandora']['step_id'] = $previous_step_id;
@ -225,33 +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 list of content models.
*
* @param array $configuration
* The list of key/value pairs of configuration.
*/
function islandora_ingest_get_approximate_steps(array $configuration) {
try {
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. * Executes the current step.
* *
@ -266,16 +333,19 @@ function islandora_ingest_get_approximate_steps(array $configuration) {
* @return array * @return array
* The form definition of the current step. * The form definition of the current step.
*/ */
function islandora_ingest_form_execute_step(array $form, array &$form_state) { function islandora_ingest_form_execute_step(array $form, array &$form_state, $step_id = NULL) {
// Load any required files for the current step. // Load any required files for the current step.
islandora_ingest_form_load_include($form_state); islandora_ingest_form_load_include($form_state);
$step = islandora_ingest_form_get_step($form_state); $step = isset($step_id) ? islandora_ingest_form_get_step($form_state) : islandora_ingest_form_get_step($form_state, $step_id);
switch ($step['type']) { switch ($step['type']) {
case 'callback':
// Execute all the consecutive callbacks, and move then attempt to process
// the next step.
islandora_ingest_form_execute_consecutive_callback_steps($form, $form_state, $step);
return islandora_ingest_form_execute_step($form, $form_state);
case 'form': case 'form':
$args = array($form, &$form_state); return islandora_ingest_form_execute_form_step($form, $form_state, $step);
$args = isset($step['args']) ? array_merge($args, $step['args']) : $args;
$form = call_user_func_array($step['form_id'], $args);
return islandora_ingest_form_stepify($form, $form_state, $step);
case 'batch': case 'batch':
// @todo Implement if possible. // @todo Implement if possible.
@ -284,6 +354,102 @@ function islandora_ingest_form_execute_step(array $form, array &$form_state) {
return array(); return array();
} }
/**
* Execute the given 'form' step.
*
* Assumes the given step is a 'form' step.
*
* @param array $form
* The Drupal form.
* @param array $form_state
* The Drupal form state.
*
* @return array
* The form definition of the given step.
*/
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);
}
/**
* Execute the given 'callback' step and any consecutive 'callback' steps.
*
* Assumes the given step is a 'callback' step.
*
* @param array $form
* The Drupal form.
* @param array $form_state
* The Drupal form state.
*/
function islandora_ingest_form_execute_consecutive_callback_steps(array $form, array &$form_state, array $step) {
do {
islandora_ingest_form_execute_callback_step($form, $form_state, $step);
islandora_ingest_form_increment_step($form_state);
$step = islandora_ingest_form_get_step($form_state);
} while (isset($step) && $step['type'] == 'callback');
}
/**
* Execute the given 'callback' step.
*
* Assumes the given step is a 'callback' step.
*
* @param array $form
* The Drupal form.
* @param array $form_state
* The Drupal form state.
*/
function islandora_ingest_form_execute_callback_step(array $form, array &$form_state, array $step) {
$args = array(&$form_state);
$args = isset($step['do_function']['args']) ? array_merge($args, $step['do_function']['args']) : $args;
call_user_func_array($step['do_function']['function'], $args);
}
/**
* Undo the given 'callback' step and any consecutive 'callback' steps.
*
* Assumes the given $step is a 'callback' step.
*
* @param array $form
* The Drupal form.
* @param array $form_state
* The Drupal form state.
*/
function islandora_ingest_form_undo_consecutive_callback_steps(array $form, array &$form_state, array $step) {
do {
islandora_ingest_form_undo_callback_step($form, $form_state, $step);
islandora_ingest_form_decrement_step($form_state);
$step = islandora_ingest_form_get_step($form_state);
} while (isset($step) && $step['type'] == 'callback');
}
/**
* Undo the given 'callback' step.
*
* Assumes the given $step is a 'callback' step.
*
* @param array $form
* The Drupal form.
* @param array $form_state
* The Drupal form state.
*/
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;
call_user_func_array($step['undo_function']['function'], $args);
}
/** /**
* Append Prev/Next buttons submit/validation handlers etc. * Append Prev/Next buttons submit/validation handlers etc.
* *
@ -293,18 +459,24 @@ function islandora_ingest_form_execute_step(array $form, array &$form_state) {
* The Drupal form state. * The Drupal form state.
* *
* @return array * @return array
* The stepified drupal form definition for the given step. * The stepified Drupal form definition for the given step.
*/ */
function islandora_ingest_form_stepify(array $form, array &$form_state) { function islandora_ingest_form_stepify(array $form, array &$form_state, $step) {
$first_step = islandora_ingest_form_on_first_step($form_state); $first_form_step = islandora_ingest_form_on_first_form_step($form_state);
$last_step = islandora_ingest_form_on_last_step($form_state); $last_form_step = islandora_ingest_form_on_last_form_step($form_state);
$form['prev'] = $first_step ? NULL : islandora_ingest_form_previous_button($form_state); $form['form_step_id'] = array(
$form['next'] = $last_step ? islandora_ingest_form_ingest_button($form_state) : islandora_ingest_form_next_button($form_state); '#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().
drupal_alter(array('form_' . $step['form_id'], 'form'), $form, $form_state, $step['form_id']);
return $form; return $form;
} }
/** /**
* Checks if we are on the first step. * Checks if we are on the first form step.
* *
* @param array $form_state * @param array $form_state
* The Drupal form state. * The Drupal form state.
@ -312,14 +484,12 @@ function islandora_ingest_form_stepify(array $form, array &$form_state) {
* @return bool * @return bool
* TRUE if we are currently on the first step, FALSE otherwise. * TRUE if we are currently on the first step, FALSE otherwise.
*/ */
function islandora_ingest_form_on_first_step(array &$form_state) { function islandora_ingest_form_on_first_form_step(array &$form_state) {
$step_id = islandora_ingest_form_get_current_step_id($form_state); return !islandora_ingest_form_get_previous_form_step($form_state);
$step_ids = array_keys(islandora_ingest_form_get_steps($form_state));
return array_search($step_id, $step_ids) == 0;
} }
/** /**
* Checks if we are on the last step. * Checks if we are on the last form step.
* *
* @param array $form_state * @param array $form_state
* The Drupal form state. * The Drupal form state.
@ -327,11 +497,42 @@ function islandora_ingest_form_on_first_step(array &$form_state) {
* @return bool * @return bool
* TRUE if we are currently on the last step, FALSE otherwise. * TRUE if we are currently on the last step, FALSE otherwise.
*/ */
function islandora_ingest_form_on_last_step(array &$form_state) { function islandora_ingest_form_on_last_form_step(array &$form_state) {
$step_id = islandora_ingest_form_get_current_step_id($form_state); return !islandora_ingest_form_get_next_form_step($form_state);
$step_ids = array_keys(islandora_ingest_form_get_steps($form_state)); }
$count = count($step_ids);
return array_search($step_id, $step_ids) == --$count; /**
* Get the previous form step relative to the current step.
*
* @param array $form_state
* The Drupal form state.
*
* @return array
* The previous form step if one exists, NULL otherwise.
*/
function islandora_ingest_form_get_previous_form_step(array &$form_state) {
$step = NULL;
do {
$step = islandora_ingest_form_get_previous_step($form_state, $step);
} while (isset($step) && $step['type'] != 'form');
return $step;
}
/**
* Get the next form step relative to the current step.
*
* @param array $form_state
* The Drupal form state.
*
* @return array
* The next form step if one exists, NULL otherwise.
*/
function islandora_ingest_form_get_next_form_step(array &$form_state) {
$step = NULL;
do {
$step = islandora_ingest_form_get_next_step($form_state, $step);
} while (isset($step) && $step['type'] != 'form');
return $step;
} }
/** /**
@ -346,13 +547,12 @@ function islandora_ingest_form_on_last_step(array &$form_state) {
* The previous button for the ingest form. * The previous button for the ingest form.
*/ */
function islandora_ingest_form_previous_button(array &$form_state) { function islandora_ingest_form_previous_button(array &$form_state) {
// Before we move back to the previous step we should tell the previous step // Before we move back to the previous step we should tell the previous steps
// to undo whatever its submit handler did. // to undo whatever its submit handler did.
$prev_step_id = islandora_ingest_form_get_previous_step_id($form_state); $prev_form_step = islandora_ingest_form_get_previous_form_step($form_state);
$prev_step = islandora_ingest_form_get_step($form_state, $prev_step_id); $form_id = $prev_form_step['form_id'];
$form_id = $prev_step['form_id'];
$submit_callback = $form_id . '_undo_submit'; $submit_callback = $form_id . '_undo_submit';
$submit = function_exists($submit_callback) ? array($submit_callback, 'islandora_ingest_form_previous_submit') : array('islandora_ingest_form_undo_submit'); $submit = function_exists($submit_callback) ? array('islandora_ingest_form_previous_submit', $submit_callback) : array('islandora_ingest_form_previous_submit');
return array( return array(
'#type' => 'submit', '#type' => 'submit',
'#value' => t('Previous'), '#value' => t('Previous'),
@ -383,6 +583,11 @@ function islandora_ingest_form_previous_button(array &$form_state) {
*/ */
function islandora_ingest_form_previous_submit(array $form, array &$form_state) { function islandora_ingest_form_previous_submit(array $form, array &$form_state) {
islandora_ingest_form_decrement_step($form_state); islandora_ingest_form_decrement_step($form_state);
$step = islandora_ingest_form_get_step($form_state);
// Undo all callbacks that occured after the previous step.
if ($step['type'] == 'callback') {
islandora_ingest_form_undo_consecutive_callback_steps($form, $form_state, $step);
}
$form_state['rebuild'] = TRUE; $form_state['rebuild'] = TRUE;
} }
@ -438,8 +643,10 @@ function islandora_ingest_form_next_submit(array $form, array &$form_state) {
*/ */
function islandora_ingest_form_stash_info(array &$form_state) { function islandora_ingest_form_stash_info(array &$form_state) {
$storage = &islandora_ingest_form_get_step_storage($form_state); $storage = &islandora_ingest_form_get_step_storage($form_state);
$storage['values'] = $form_state['values']; if ($storage && isset($form_state['values'])) {
unset($form_state['values']); $storage['values'] = $form_state['values'];
unset($form_state['values']);
}
} }
/** /**
@ -485,12 +692,17 @@ function islandora_ingest_form_ingest_button(array &$form_state) {
* *
* Attempts to ingest every object built by the previous steps. * Attempts to ingest every object built by the previous steps.
* *
* @param array $form
* The Drupal form.
* @param array $form_state * @param array $form_state
* The Drupal form state. * The Drupal form state.
*/ */
function islandora_ingest_form_submit(array $form, array &$form_state) { function islandora_ingest_form_submit(array $form, array &$form_state) {
// Execute any remaining callbacks.
islandora_ingest_form_increment_step($form_state);
$step = islandora_ingest_form_get_step($form_state);
if (isset($step) && $step['type'] == 'callback') {
islandora_ingest_form_execute_consecutive_callback_steps($form, $form_state, $step);
}
// Ingest the objects.
foreach ($form_state['islandora']['objects'] as $object) { foreach ($form_state['islandora']['objects'] as $object) {
try { try {
islandora_add_object($object); islandora_add_object($object);
@ -499,7 +711,7 @@ function islandora_ingest_form_submit(array $form, array &$form_state) {
catch (Exception $e) { catch (Exception $e) {
// If post hooks throws it may already exist at this point but may be // If post hooks throws it may already exist at this point but may be
// invalid, so don't say failed. // invalid, so don't say failed.
watchdog('islandora', $e->getMessage(), NULL, WATCHDOG_ERROR); watchdog('islandora', 'Exception Message: @exception.', array('@exception' => $e->getMessage()), WATCHDOG_ERROR);
drupal_set_message(t('A problem occured while ingesting "@label" (ID: @pid), please notifiy the administrator.', array('@label' => $object->label, '@pid' => $object->id)), 'error'); drupal_set_message(t('A problem occured while ingesting "@label" (ID: @pid), please notifiy the administrator.', array('@label' => $object->label, '@pid' => $object->id)), 'error');
} }
} }
@ -537,7 +749,7 @@ function &islandora_ingest_form_get_objects(array &$form_state) {
*/ */
function islandora_ingest_form_get_object(array &$form_state) { function islandora_ingest_form_get_object(array &$form_state) {
$objects = &islandora_ingest_form_get_objects($form_state); $objects = &islandora_ingest_form_get_objects($form_state);
return current($objects); return reset($objects);
} }
/** /**
@ -559,7 +771,8 @@ function &islandora_ingest_form_get_step_storage(array &$form_state, $step_id =
} }
return $form_state['islandora']['step_storage'][$step_id]; return $form_state['islandora']['step_storage'][$step_id];
} }
return NULL; $undefined_step_storage = array();
return $undefined_step_storage;
} }
/** /**
@ -617,6 +830,8 @@ function islandora_ingest_form_get_steps(array &$form_state) {
$shared_storage = &islandora_ingest_form_get_shared_storage($form_state); $shared_storage = &islandora_ingest_form_get_shared_storage($form_state);
foreach (islandora_build_hook_list(ISLANDORA_INGEST_STEP_HOOK, $shared_storage['models']) as $hook) { foreach (islandora_build_hook_list(ISLANDORA_INGEST_STEP_HOOK, $shared_storage['models']) as $hook) {
// Required for pass by reference. // Required for pass by reference.
// @todo Change this around so that it isn't passed by reference, there
// Is an alter below that can handle that requirement.
foreach (module_implements($hook) as $module) { foreach (module_implements($hook) as $module) {
$function = $module . '_' . $hook; $function = $module . '_' . $hook;
$module_steps = (array) $function($form_state); $module_steps = (array) $function($form_state);
@ -627,6 +842,46 @@ function islandora_ingest_form_get_steps(array &$form_state) {
foreach (islandora_build_hook_list(ISLANDORA_INGEST_STEP_HOOK, $shared_storage['models']) as $hook) { foreach (islandora_build_hook_list(ISLANDORA_INGEST_STEP_HOOK, $shared_storage['models']) as $hook) {
drupal_alter($hook, $steps, $form_state); drupal_alter($hook, $steps, $form_state);
} }
// Add any defaults.
foreach ($steps as $key => &$step) {
$step['id'] = $key;
}
uasort($steps, 'drupal_sort_weight'); uasort($steps, 'drupal_sort_weight');
return $steps; 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);
}

49
includes/ingest.menu.inc

@ -1,49 +0,0 @@
<?php
/**
* @file
* Ingest Menu callback hooks.
*/
/**
* Menu callback, Renders the multi-page ingest form if possible.
*
* @return string
* HTML representing the mult-page ingest form.
*/
function islandora_ingest_callback() {
module_load_include('inc', 'islandora', 'includes/ingest.form');
try {
$configuration = islandora_ingest_get_configuration();
return drupal_get_form('islandora_ingest_form', $configuration);
}
catch(Exception $e) {
$redirect = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '<front>';
// Redirect back to referer or top level collection.
drupal_goto($redirect);
}
}
/**
* Fetches the ingest configuration from the $_GET parameters.
*
* Generic parameters as accepted by all ingest processes, other modules may
* add to this list.
* id -> The pid of the object to create. optional.
* models -> Comma delimited list of all the content models the created object
* should have.
* collections -> Comma delimited list of all the collections the created
* object should belong to.
*
* @return array
* The configuration options used to build the multi-paged ingest process.
*/
function islandora_ingest_get_configuration() {
$configuration = $_GET;
unset($configuration['q']);
$convert_to_array_keys = array_intersect(array('models', 'collections'), array_keys($configuration));
foreach ($convert_to_array_keys as $key) {
$configuration[$key] = explode(',', $configuration[$key]);
}
return $configuration;
}

18
includes/mime_detect.inc

@ -148,7 +148,7 @@ class MimeDetect {
"jp2" => "image/jp2", "jp2" => "image/jp2",
"png" => "image/png", "png" => "image/png",
"tiff" => "image/tiff", "tiff" => "image/tiff",
"tif" => "image/tif", "tif" => "image/tiff",
"djvu" => "image/vnd.djvu", "djvu" => "image/vnd.djvu",
"djv" => "image/vnd.djvu", "djv" => "image/vnd.djvu",
"wbmp" => "image/vnd.wap.wbmp", "wbmp" => "image/vnd.wap.wbmp",
@ -194,6 +194,11 @@ class MimeDetect {
'bin' => 'application/octet-stream', 'bin' => 'application/octet-stream',
); );
protected $protectedFileExtensions; 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 $systemTypes;
protected $systemExts; protected $systemExts;
protected $etcMimeTypes = '/etc/mime.types'; protected $etcMimeTypes = '/etc/mime.types';
@ -205,6 +210,7 @@ class MimeDetect {
// Populate the reverse shortlist: // Populate the reverse shortlist:
$this->protectedFileExtensions = array_flip($this->protectedMimeTypes); $this->protectedFileExtensions = array_flip($this->protectedMimeTypes);
$this->protectedFileExtensions += $this->extensionExceptions;
// Pick up a local mime.types file if it is available. // Pick up a local mime.types file if it is available.
if (is_readable('mime.types')) { if (is_readable('mime.types')) {
@ -366,4 +372,14 @@ class MimeDetect {
return $out; return $out;
} }
/**
* Gets MIME type array.
*
* @return array
* Returns associative array with exts and mimetypes.
*/
public function getMimeTypes() {
return $this->protectedMimeTypes;
}
} }

11
includes/object_properties.form.inc

@ -12,13 +12,13 @@
* The Drupal form. * The Drupal form.
* @param array $form_state * @param array $form_state
* The Drupal form state. * The Drupal form state.
* @param FedoraObject $object * @param AbstractObject $object
* The object whose properties this form will modify. * The object whose properties this form will modify.
* *
* @return array * @return array
* The drupal form definition. * 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); drupal_set_title($object->label);
$form_state['object'] = $object; $form_state['object'] = $object;
return array( return array(
@ -30,7 +30,7 @@ function islandora_object_properties_form(array $form, array &$form_state, Fedor
'#title' => t('Item Label'), '#title' => t('Item Label'),
'#default_value' => $object->label, '#default_value' => $object->label,
'#required' => 'TRUE', '#required' => 'TRUE',
'#description' => t('A Human readable label'), '#description' => t('A human-readable label'),
// Double the normal length. // Double the normal length.
'#size' => 120, '#size' => 120,
// Max length for a Fedora Label. // Max length for a Fedora Label.
@ -43,14 +43,14 @@ function islandora_object_properties_form(array $form, array &$form_state, Fedor
'#title' => t('Owner'), '#title' => t('Owner'),
'#default_value' => $object->owner, '#default_value' => $object->owner,
'#required' => FALSE, '#required' => FALSE,
'#description' => t('The owner id'), '#description' => t("The owner's account name"),
'#type' => 'textfield', '#type' => 'textfield',
), ),
'object_state' => array( 'object_state' => array(
'#title' => t('State'), '#title' => t('State'),
'#default_value' => $object->state, '#default_value' => $object->state,
'#required' => TRUE, '#required' => TRUE,
'#description' => t('The items state one of active, inactive or deleted'), '#description' => t("The object's state (active, inactive or deleted)"),
'#type' => 'select', '#type' => 'select',
'#options' => array('A' => 'Active', 'I' => 'Inactive', 'D' => 'Deleted'), '#options' => array('A' => 'Active', 'I' => 'Inactive', 'D' => 'Deleted'),
), ),
@ -60,6 +60,7 @@ function islandora_object_properties_form(array $form, array &$form_state, Fedor
), ),
'delete' => array( 'delete' => array(
'#type' => 'submit', '#type' => 'submit',
'#access' => islandora_object_access(FEDORA_PURGE, $object),
'#value' => t('Delete'), '#value' => t('Delete'),
'#submit' => array('islandora_object_properties_form_delete'), '#submit' => array('islandora_object_properties_form_delete'),
'#limit_validation_errors' => array(array('pid')), '#limit_validation_errors' => array(array('pid')),

125
includes/solution_packs.inc

@ -180,37 +180,55 @@ function islandora_solution_pack_form_submit(array $form, array &$form_state) {
/** /**
* Batch operation to ingest/reingest required object(s). * Batch operation to ingest/reingest required object(s).
* *
* @param NewFedoraObject $object * @param AbstractObject $object
* The object to ingest/reingest. * The object to ingest/reingest.
* @param array $context * @param array $context
* The context of this batch operation. * 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); $existing_object = islandora_object_load($object->id);
$deleted = FALSE;
if ($existing_object) { if ($existing_object) {
$deleted = islandora_delete_object($existing_object); $deleted = islandora_delete_object($existing_object);
if (!$deleted) { if (!$deleted) {
$object_link = l($existing_object->label, "islandora/object/{$existing_object->id}"); $object_link = l($existing_object->label, "islandora/object/{$existing_object->id}");
drupal_set_message(t('Failed to purge existing object !object_link.', array( drupal_set_message(filter_xss(t('Failed to purge existing object !object_link.', array(
'!object_link' => $object_link, '!object_link' => $object_link,
)), 'error'); ))), 'error');
// Failed to purge don't attempt to ingest. // Failed to purge don't attempt to ingest.
return; return;
} }
} }
// Object was deleted or did not exist. // Object was deleted or did not exist.
$pid = $object->id; $pid = $object->id;
$label = $object->label; $label = $object->label;
$action = $deleted ? 'reinstalled' : 'installed';
$object_link = l($label, "islandora/object/{$pid}"); $object_link = l($label, "islandora/object/{$pid}");
$object = islandora_add_object($object); $object = islandora_add_object($object);
$msg = $object ? "Successfully $action !object_link." : "Failed to $action @label identified by @pid."; $params = array(
'@pid' => $pid,
'@label' => $label,
'!object_link' => $object_link,
);
$msg = '';
if ($object) {
if ($deleted) {
$msg = t('Successfully reinstalled !object_link.', $params);
}
else {
$msg = t('Successfully installed !object_link.', $params);
}
}
elseif ($deleted) {
$msg = t('Failed to reinstall @label, identified by @pid.', $params);
}
else {
$msg = t('Failed to install @label, identified by @pid.', $params);
}
$status = $object ? 'status' : 'error'; $status = $object ? 'status' : 'error';
drupal_set_message(t($msg, array( drupal_set_message(filter_xss($msg), $status);
'@pid' => $pid,
'@label' => $label,
'!object_link' => $object_link,
)), $status);
} }
/** /**
@ -237,33 +255,37 @@ function islandora_install_solution_pack($module, $op = 'install') {
islandora_uninstall_solution_pack($module); islandora_uninstall_solution_pack($module);
return; return;
} }
$t = get_t();
// Some general replacements.
$admin_link = l($t('Solution Pack admin'), 'admin/islandora/solution_packs');
$config_link = l($t('Islandora configuration'), 'admin/islandora/configure');
$t_params = array(
'@module' => $module,
'!config_link' => $config_link,
'!admin_link' => $admin_link,
);
module_load_include('module', 'islandora', 'islandora'); module_load_include('module', 'islandora', 'islandora');
module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('inc', 'islandora', 'includes/utilities');
module_load_include('module', $module, $module); module_load_include('module', $module, $module);
$info_file = drupal_get_path('module', $module) . "/{$module}.info"; $info_file = drupal_get_path('module', $module) . "/{$module}.info";
$info_array = drupal_parse_info_file($info_file); $info_array = drupal_parse_info_file($info_file);
$module_name = $info_array['name']; $module_name = $info_array['name'];
$admin_link = l(t('Solution Pack admin'), 'admin/islandora/solution_packs');
$config_link = l(t('Islandora configuration'), 'admin/islandora/configure');
if (!islandora_describe_repository()) { if (!islandora_describe_repository()) {
$msg = '@module: Did not install any objects. Could not connect to the '; $msg = $t('@module: Did not install any objects. Could not connect to the repository. Please check the settings on the !config_link page and install the required objects manually on the !admin_link page.', $t_params);
$msg .= 'repository. Please check the settings on the !config_link page '; drupal_set_message(filter_xss($msg), 'error');
$msg .= 'and install the required objects manually on the !admin_link page.';
drupal_set_message(st($msg, array(
'@module' => $module_name,
'!config_link' => $config_link,
'@admin_link' => $admin_link,
)), 'error');
return; return;
} }
$connection = islandora_get_tuque_connection(); $connection = islandora_get_tuque_connection();
$required_objects = module_invoke($module, 'islandora_required_objects', $connection); $required_objects = module_invoke($module, 'islandora_required_objects', $connection);
$objects = $required_objects[$module]['objects']; $objects = $required_objects[$module]['objects'];
$status_messages = array( $status_messages = array(
'up_to_date' => 'The object already exists and is up-to-date', 'up_to_date' => $t('The object already exists and is up-to-date.', $t_params),
'missing_datastream' => 'The object already exists but is missing a datastream. Please reinstall the object on the !admin_link page', 'missing_datastream' => $t('The object already exists but is missing a datastream. Please reinstall the object on the !admin_link page.', $t_params),
'out_of_date' => 'The object already exists but is out-of-date. Please update the object on the !admin_link page', 'out_of_date' => $t('The object already exists but is out-of-date. Please update the object on the !admin_link page.', $t_params),
'modified_datastream' => 'The object already exists but datastreams are modified. Please reinstall the object on the !admin_link page', 'modified_datastream' => $t('The object already exists but datastreams are modified. Please reinstall the object on the !admin_link page.', $t_params),
); );
foreach ($objects as $object) { foreach ($objects as $object) {
$query = $connection->api->a->findObjects('query', 'pid=' . $object->id); $query = $connection->api->a->findObjects('query', 'pid=' . $object->id);
@ -272,26 +294,25 @@ function islandora_install_solution_pack($module, $op = 'install') {
$object_link = l($label, "islandora/object/{$object->id}"); $object_link = l($label, "islandora/object/{$object->id}");
if ($already_exists) { if ($already_exists) {
$object_status = islandora_check_object_status($object); $object_status = islandora_check_object_status($object);
$status_msg = $status_messages[$object_status['status']]; $here_params = array(
drupal_set_message(st("@module: Did not install !object_link. $status_msg.", array( '!summary' => $t("@module: Did not install !object_link.", array(
'@module' => $module_name,
'!object_link' => $object_link, '!object_link' => $object_link,
'!admin_link' => $admin_link, ) + $t_params),
)), 'warning'); '!description' => $status_messages[$object_status['status']],
);
drupal_set_message(filter_xss(format_string('!summary !description', $here_params)), 'warning');
} }
else { else {
$object = islandora_add_object($object); $object = islandora_add_object($object);
if ($object) { if ($object) {
drupal_set_message(t('@module: Successfully installed. !object_link.', array( drupal_set_message(filter_xss($t('@module: Successfully installed. !object_link.', array(
'@module' => $module_name,
'!object_link' => $object_link, '!object_link' => $object_link,
)), 'status'); ) + $t_params)), 'status');
} }
else { else {
drupal_set_message(t('@module: Failed to install. @label.', array( drupal_set_message($t('@module: Failed to install. @label.', array(
'@module' => $module_name,
'@label' => $label, '@label' => $label,
)), 'warning'); ) + $t_params), 'warning');
} }
} }
} }
@ -307,21 +328,20 @@ function islandora_install_solution_pack($module, $op = 'install') {
* directly for each solution pack. * directly for each solution pack.
*/ */
function islandora_uninstall_solution_pack($module) { function islandora_uninstall_solution_pack($module) {
$t = get_t();
module_load_include('module', 'islandora', 'islandora'); module_load_include('module', 'islandora', 'islandora');
module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('inc', 'islandora', 'includes/utilities');
module_load_include('module', $module, $module); module_load_include('module', $module, $module);
$config_link = l(t('Islandora configuration'), 'admin/islandora/configure'); $config_link = l($t('Islandora configuration'), 'admin/islandora/configure');
$info_file = drupal_get_path('module', $module) . "/{$module}.info"; $info_file = drupal_get_path('module', $module) . "/{$module}.info";
$info_array = drupal_parse_info_file($info_file); $info_array = drupal_parse_info_file($info_file);
$module_name = $info_array['name']; $module_name = $info_array['name'];
if (!islandora_describe_repository()) { if (!islandora_describe_repository()) {
$msg = '@module: Did not uninstall any objects. Could not connect to the '; $msg = $t('@module: Did not uninstall any objects. Could not connect to the repository. Please check the settings on the !config_link page and uninstall the required objects manually if necessary.', array(
$msg .= 'repository. Please check the settings on the !config_link page '; '@module' => $module_name,
$msg .= 'and uninstall the required objects manually if necessary.'; '!config_link' => $config_link,
drupal_set_message(st($msg, array( ));
'@module' => $module_name, drupal_set_message(filter_xss($msg), 'error');
'!config_link' => $config_link,
)), 'error');
return; return;
} }
$connection = islandora_get_tuque_connection(); $connection = islandora_get_tuque_connection();
@ -334,19 +354,20 @@ function islandora_uninstall_solution_pack($module) {
}; };
$existing_objects = array_filter($objects, $filter); $existing_objects = array_filter($objects, $filter);
foreach ($existing_objects as $object) { foreach ($existing_objects as $object) {
$msg = '@module: Did not remove !object_link. It may be used by other sites.';
$object_link = l($object->label, "islandora/object/{$object->id}"); $object_link = l($object->label, "islandora/object/{$object->id}");
drupal_set_message(st($msg, array( $msg = $t('@module: Did not remove !object_link. It may be used by other sites.', array(
'!object_link' => $object_link, '!object_link' => $object_link,
'@module' => $module_name, '@module' => $module_name,
)), 'warning'); ));
drupal_set_message(filter_xss($msg), 'warning');
} }
} }
/** /**
* Function to check the status of an object against an object model array. * 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. * A new fedora object that defines what the object should contain.
* *
* @return string * @return string
@ -357,7 +378,7 @@ function islandora_uninstall_solution_pack($module) {
* @see islandora_solution_pack_form() * @see islandora_solution_pack_form()
* @see islandora_install_solution_pack() * @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); $existing_object = islandora_object_load($object_definition->id);
if (!$existing_object) { if (!$existing_object) {
return array('status' => 'missing', 'status_friendly' => t('Missing')); return array('status' => 'missing', 'status_friendly' => t('Missing'));
@ -606,7 +627,7 @@ function theme_islandora_viewers_table($variables) {
* Array or string with data the module needs in order to render a full viewer * Array or string with data the module needs in order to render a full viewer
* @param string $variable_id * @param string $variable_id
* The id of the Drupal variable the viewer settings are saved in * 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 * The tuque object representing the fedora object being displayed
* *
* @return string * @return string

26
includes/tuque_wrapper.inc

@ -34,23 +34,21 @@ $islandora_module_path = drupal_get_path('module', 'islandora');
/** /**
* Allow modules to alter an object before a mutable event occurs. * 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) {
$types = array('islandora_object'); module_load_include('inc', 'islandora', 'includes/utilities');
foreach ($object->models as $model) { drupal_alter(islandora_build_hook_list('islandora_object', $object->models), $object, $context);
$types[] = "{$model}_islandora_object";
}
drupal_alter($types, $object, $context);
} }
/** /**
* Allow modules to alter a datastream before a mutable event occurs. * 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) {
$types = array('islandora_datastream'); module_load_include('inc', 'islandora', 'includes/utilities');
$types = array();
foreach ($object->models as $model) { foreach ($object->models as $model) {
$types[] = "{$model}_{$datastream->id}_islandora_datastream"; $types[] = "{$model}_{$datastream->id}";
} }
drupal_alter($types, $object, $datastream, $context); drupal_alter(islandora_build_hook_list('islandora_datastream', $types), $object, $datastream, $context);
} }
/** /**
@ -207,7 +205,7 @@ class IslandoraFedoraApiM extends FedoraApiM {
} }
return $ret; return $ret;
} }
catch(Exception $e) { catch (Exception $e) {
watchdog('islandora', 'Failed to modify datastream @dsid from @pid</br>code: @code<br/>message: @msg', array( watchdog('islandora', 'Failed to modify datastream @dsid from @pid</br>code: @code<br/>message: @msg', array(
'@pid' => $pid, '@pid' => $pid,
'@dsid' => $dsid, '@dsid' => $dsid,
@ -241,7 +239,7 @@ class IslandoraFedoraApiM extends FedoraApiM {
} }
return $ret; return $ret;
} }
catch(Exception $e) { catch (Exception $e) {
watchdog('islandora', 'Failed to modify object: @pid</br>code: @code<br/>message: @msg', array( watchdog('islandora', 'Failed to modify object: @pid</br>code: @code<br/>message: @msg', array(
'@pid' => $pid, '@pid' => $pid,
'@code' => $e->getCode(), '@code' => $e->getCode(),
@ -283,7 +281,7 @@ class IslandoraFedoraApiM extends FedoraApiM {
return $ret; return $ret;
} }
} }
catch(Exception $e) { catch (Exception $e) {
watchdog('islandora', 'Failed to purge datastream @dsid from @pid</br>code: @code<br/>message: @msg', array( watchdog('islandora', 'Failed to purge datastream @dsid from @pid</br>code: @code<br/>message: @msg', array(
'@pid' => $pid, '@pid' => $pid,
'@dsid' => $dsid, '@dsid' => $dsid,
@ -327,7 +325,7 @@ class IslandoraFedoraApiM extends FedoraApiM {
return $ret; return $ret;
} }
} }
catch(Exception $e) { catch (Exception $e) {
watchdog('islandora', 'Failed to purge object @pid</br>code: @code<br/>message: @msg', array( watchdog('islandora', 'Failed to purge object @pid</br>code: @code<br/>message: @msg', array(
'@pid' => $pid, '@pid' => $pid,
'@code' => $e->getCode(), '@code' => $e->getCode(),

263
includes/utilities.inc

@ -204,13 +204,13 @@ function islandora_escape_pid_for_function($pid) {
// Apparently, case doesn't matter for function calls in PHP, so let's not // Apparently, case doesn't matter for function calls in PHP, so let's not
// really worry about changing the case. // really worry about changing the case.
return str_replace( return str_replace(
// Any PID characters which are not valid in the name of a PHP function. // Any PID characters which are not valid in the name of a PHP function.
array( array(
':', ':',
'-', '-',
), ),
'_', '_',
$pid $pid
); );
} }
@ -256,8 +256,8 @@ function islandora_get_namespace($id) {
*/ */
function islandora_namespace_accessible($id) { function islandora_namespace_accessible($id) {
if (variable_get('islandora_namespace_restriction_enforced', FALSE)) { if (variable_get('islandora_namespace_restriction_enforced', FALSE)) {
$namespace = islandora_get_namespace($id) . ':'; $namespace = islandora_get_namespace($id);
$allowed_namespaces = explode(" ", variable_get('islandora_pids_allowed', 'default: demo: changeme: islandora: ilives: islandora-book: books: newspapers: ')); $allowed_namespaces = islandora_get_allowed_namespaces();
return in_array($namespace, $allowed_namespaces); return in_array($namespace, $allowed_namespaces);
} }
return TRUE; 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 * This function gets its info from the RELS-EXT directly rather than through an
* risearch. * risearch.
* *
* @param FedoraObject $object * @param AbstractObject $object
* The object whose parents will be returned. * The object whose parents will be returned.
* *
* @return array * @return array
* An array of FedoraObject's that the given object has a * An array of FedoraObject's that the given object has a
* (isMemberOf, isMemberOfCollection) relationship with. * (isMemberOf, isMemberOfCollection) relationship with.
*/ */
function islandora_get_parents_from_rels_ext(FedoraObject $object) { function islandora_get_parents_from_rels_ext(AbstractObject $object) {
try { try {
$collections = array_merge( $collections = array_merge(
$object->relationships->get(FEDORA_RELS_EXT_URI, 'isMemberOfCollection'), $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. * 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 * The object which models will be used to determine what datastreams it
* should have. * 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 * The DS-COMPOSITE-MODEL defined datastreams that are required for the given
* object, but not already present. * 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'); module_load_include('inc', 'islandora', 'includes/utilities');
$datastreams = islandora_get_datastreams_requirements($object); $datastreams = islandora_get_datastreams_requirements($object);
foreach ($datastreams as $dsid => $requirements) { 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() * @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 * The object which models will be used to determine what datastreams it
* should have. * 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 * The DS-COMPOSITE-MODEL defined datastreams that are required for the given
* object. * object.
*/ */
function islandora_get_datastreams_requirements(FedoraObject $object) { function islandora_get_datastreams_requirements(AbstractObject $object) {
return islandora_get_datastreams_requirements_from_models($object->models); return islandora_get_datastreams_requirements_from_models($object->models);
} }
@ -375,26 +375,21 @@ function islandora_get_datastreams_requirements_from_models(array $models) {
* *
* @todo Add support for fetching the schema information. * @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 * The content model whose DS-COMPOSITE-MODEL datastream will be used to
* determine what datastreams are required. * determine what datastreams are required.
* *
* @return array * @return array
* The DS-COMPOSITE-MODEL defined datastreams that are required for the given * An associative array mapping datastream IDs to associative arrays
* object. * containing the values parsed from the DS-COMPOSITE-MODEL on the given
* * object--of the form:
* @code * - DSID: A datastream ID being described.
* array( * - "id": A string containing ID of the datastream.
* 'DC' => array( * - "mime": A array containing MIME-types the stream may have.
* 'id' => 'DC', * - "optional": A boolean indicating if the given stream is optional.
* 'mime' => 'text/xml',
* 'optional' => FALSE,
* )
* )
* @endcode
*/ */
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])) { if (empty($object[DS_COMP_STREAM]) || !islandora_datastream_access(FEDORA_VIEW_OBJECTS, $object[DS_COMP_STREAM])) {
return array(); return array();
} }
$xml = new SimpleXMLElement($object[DS_COMP_STREAM]->content); $xml = new SimpleXMLElement($object[DS_COMP_STREAM]->content);
@ -465,20 +460,43 @@ function islandora_prepare_new_object($namespace = NULL, $label = NULL, $datastr
if (isset($ds['control_group']) && in_array($ds['control_group'], $groups)) { if (isset($ds['control_group']) && in_array($ds['control_group'], $groups)) {
$control_group = $ds['control_group']; $control_group = $ds['control_group'];
} }
$ds_uri = FALSE;
$as_file = FALSE;
if (file_valid_uri($ds['datastream_file'])) { if (file_valid_uri($ds['datastream_file'])) {
// A local file with as a Drupal file/stream wrapper URI.
$datastream_file = $ds['datastream_file']; $datastream_file = $ds['datastream_file'];
$ds_uri = TRUE; $as_file = TRUE;
}
elseif (is_readable($ds['datastream_file'])) {
// A local file as a filesystem path.
$datastream_file = drupal_realpath($ds['datastream_file']);
$as_file = TRUE;
} }
else { else {
$datastream_file = url($ds['datastream_file'], array('absolute' => TRUE)); $scheme = parse_url($ds['datastream_file'], PHP_URL_SCHEME);
if (in_array($scheme, stream_get_wrappers())) {
// A URI which gets handled by one of the PHP-native stream wrappers.
$datastream_file = $ds['datastream_file'];
$as_file = TRUE;
}
else {
// Schema does not match available php stream wrapper. Attempt to
// set datastream_file by url for the given scheme. Https (SSL) can
// cause this to fail, and trigger an output log in watchdog.
$datastream_file = url($ds['datastream_file'], array('absolute' => TRUE));
watchdog('islandora',
'Attempting to ingest %file in islandora_prepare_new_object(), but it does not appear to be readable. We will pass the path through url(), and pass along as such.',
array('%file' => $datastream_file),
WATCHDOG_WARNING);
}
} }
$datastream = $object->constructDatastream($dsid, $control_group); $datastream = $object->constructDatastream($dsid, $control_group);
$datastream->label = $label; $datastream->label = $label;
$datastream->mimetype = $mimetype; $datastream->mimetype = $mimetype;
switch ($control_group) { switch ($control_group) {
case 'M': case 'M':
if ($ds_uri) { if ($as_file) {
$datastream->setContentFromFile($datastream_file); $datastream->setContentFromFile($datastream_file);
} }
else { else {
@ -490,8 +508,10 @@ function islandora_prepare_new_object($namespace = NULL, $label = NULL, $datastr
$datastream->setContentFromString(file_get_contents($datastream_file)); $datastream->setContentFromString(file_get_contents($datastream_file));
break; break;
} }
$object->ingestDatastream($datastream); $object->ingestDatastream($datastream);
} }
return $object; return $object;
} }
@ -505,8 +525,9 @@ function islandora_display_repository_inaccessible_message() {
$text = t('Islandora configuration'); $text = t('Islandora configuration');
$link = l($text, 'admin/islandora/configure', array('attributes' => array('title' => $text))); $link = l($text, 'admin/islandora/configure', array('attributes' => array('title' => $text)));
$message = t('Could not connect to the repository. Please check the settings on the !link page.', $message = t('Could not connect to the repository. Please check the settings on the !link page.',
array('!link' => $link)); array('!link' => $link));
drupal_set_message($message, 'error', FALSE); drupal_set_message(check_plain($message), 'error', FALSE);
} }
/** /**
@ -595,35 +616,29 @@ function islandora_system_settings_form_default_value($name, $default_value, arr
/** /**
* Returns basic information about DS-COMPOSITE-MODEL. * Returns basic information about DS-COMPOSITE-MODEL.
* *
* @deprecated
* The pre-existing--and more flexible--
* islandora_get_datastreams_requirements_from_content_model() should be
* preferred, as it addresses the case where a stream can be allowed to have
* one of a set of mimetypes (this functions appears to only return the last
* declared mimetype for a given datastream).
*
* @param string $pid * @param string $pid
* PID of content model containing DS_COMP stream. * The PID of content model containing DS_COMP stream.
* *
* @return array * @return array
* array of values in the following form * An associative array mapping datastream IDs to an associative array
* * representing the parsed DS-COMPOSITE-MODEL of the form:
* [DC] => Array * - DSID: A string containing the datastream ID.
* ( * - "mimetype": A string containing the last mimetype declared for the
* [mimetype] => text/xml * given datastream ID.
* ) * - "optional": An optional boolean indicating that the given datastream
* * is optional.
* [MODS] => Array
* (
* [optional] => true
* [mimetype] => text/xml
* )
*
* [RELS-EXT] => Array
* (
* [mimetype] => application/rdf+xml
* )
*
* [RELS-INT] => Array
* (
* [optional] => true
* [mimetype] => application/rdf+xml
* )
*/ */
function islandora_get_comp_ds_mappings($pid) { 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); $cm_object = islandora_object_load($pid);
if (!isset($cm_object) || !isset($cm_object['DS-COMPOSITE-MODEL'])) { if (!isset($cm_object) || !isset($cm_object['DS-COMPOSITE-MODEL'])) {
return FALSE; return FALSE;
@ -658,6 +673,9 @@ function islandora_get_comp_ds_mappings($pid) {
* TRUE if the account has all the given permissions, FALSE otherwise. * TRUE if the account has all the given permissions, FALSE otherwise.
*/ */
function islandora_user_access_all(array $perms, $account = NULL) { function islandora_user_access_all(array $perms, $account = NULL) {
$message = islandora_deprecated('7.x-1.2', 'Roll your own code or use islandora_user_access().');
trigger_error(filter_xss($message), E_USER_DEPRECATED);
foreach ($perms as $perm) { foreach ($perms as $perm) {
if (!user_access($perm, $account)) { if (!user_access($perm, $account)) {
return FALSE; return FALSE;
@ -679,6 +697,9 @@ function islandora_user_access_all(array $perms, $account = NULL) {
* otherwise. * otherwise.
*/ */
function islandora_user_access_any(array $perms, $account = NULL) { function islandora_user_access_any(array $perms, $account = NULL) {
$message = islandora_deprecated('7.x-1.2', 'Roll your own code or use islandora_user_access().');
trigger_error(filter_xss($message), E_USER_DEPRECATED);
foreach ($perms as $perm) { foreach ($perms as $perm) {
if (user_access($perm, $account)) { if (user_access($perm, $account)) {
return TRUE; return TRUE;
@ -697,7 +718,13 @@ function islandora_get_allowed_namespaces() {
$matches = array(); $matches = array();
$allowed_namespaces = variable_get('islandora_pids_allowed', 'default: demo: changeme: islandora:'); $allowed_namespaces = variable_get('islandora_pids_allowed', 'default: demo: changeme: islandora:');
preg_match_all('/([A-Za-z0-9-\.]+):/', $allowed_namespaces, $matches); 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;
} }
/** /**
@ -718,14 +745,24 @@ function islandora_get_allowed_namespaces() {
function islandora_get_content_models($ignore_system_namespace = TRUE) { function islandora_get_content_models($ignore_system_namespace = TRUE) {
module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('inc', 'islandora', 'includes/utilities');
$tuque = islandora_get_tuque_connection(); $tuque = islandora_get_tuque_connection();
$query = 'select $object $label from <#ri> $query = "PREFIX fm: <" . FEDORA_MODEL_URI . ">
where ($object <fedora-model:label> $label PREFIX fr: <" . FEDORA_RELS_EXT_URI . ">
and ($object <fedora-model:hasModel> <info:fedora/fedora-system:ContentModel-3.0> SELECT ?object ?label
or $object <fedora-rels-ext:isMemberOfCollection> <info:fedora/islandora:ContentModelsCollection>) FROM <#ri>
and $object <fedora-model:state> <info:fedora/fedora-system:def/model#Active>) WHERE {
order by $label'; {?object fm:hasModel <info:fedora/fedora-system:ContentModel-3.0>;
fm:state fm:Active
}
UNION{
?object fr:isMemberOfCollection <info:fedora/islandora:ContentModelsCollection>;
fm:state fm:Active
}
OPTIONAL{
?object fm:label ?label
}
}";
$content_models = array(); $content_models = array();
$results = $tuque->repository->ri->itqlQuery($query, 'unlimited'); $results = $tuque->repository->ri->sparqlQuery($query, 'unlimited');
foreach ($results as $result) { foreach ($results as $result) {
$content_model = $result['object']['value']; $content_model = $result['object']['value'];
$label = $result['label']['value']; $label = $result['label']['value'];
@ -738,3 +775,93 @@ function islandora_get_content_models($ignore_system_namespace = TRUE) {
} }
return $content_models; return $content_models;
} }
/**
* Returns Drupal tableselect element allowing selection of Content Models.
*
* @param string $drupal_variable
* the name of the Drupal variable holding selected content models
* Content models held in this variable will appear at the top of
* the displayed list
* @param array $default_values_array
* default values to display if $drupal_variable is unset
*
* @return array
* Drupal form element allowing content model selection
*/
function islandora_content_model_select_table_form_element($drupal_variable, $default_values_array = array('')) {
$defaults = array();
$rows = array();
$content_models = array();
$options = islandora_get_content_models(TRUE);
foreach ($options as $option) {
$content_models[$option['pid']] = $option['label'];
}
$selected = array_values(variable_get($drupal_variable, $default_values_array));
$comparator = function ($a, $b) use ($selected) {
$a_val = $b_val = 0;
if (in_array($a, $selected)) {
$a_val = 1;
}
if (in_array($b, $selected)) {
$b_val = 1;
}
return $b_val - $a_val;
};
uksort($content_models, $comparator);
foreach ($content_models as $pid => $label) {
$rows[$pid] = array(
'pid' => $pid,
'title' => $label,
);
$defaults[$pid] = in_array($pid, $selected);
}
$header = array(
'pid' => array('data' => t('PID')),
'title' => array('data' => t('Content Model')),
);
// Build and return table element.
$element = array(
'#type' => 'tableselect',
'#header' => $header,
'#options' => $rows,
'#default_value' => $defaults,
'#empty' => t("There are no content models in this Fedora Repository."),
);
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 .= "<br/>\n" . $solution;
}
return $message;
}

192
islandora.api.php

@ -8,7 +8,7 @@
/** /**
* Generate a repository objects view. * Generate a repository objects view.
* *
* @param FedoraObject $object * @param AbstractObject $object
* The object to display * The object to display
* @param object $user * @param object $user
* The user accessing the object. * 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 * Content models PIDs have colons and hyphens changed to underscores, to
* create the hook name. * create the hook name.
* *
* @param FedoraObject $object * @param AbstractObject $object
* A Tuque FedoraObject * A Tuque FedoraObject
* *
* @return array * @return array
@ -42,18 +42,31 @@ function hook_CMODEL_PID_islandora_view_object($object) {
/** /**
* Alter display output after it has been generated. * Alter display output after it has been generated.
* *
* @param FedoraObject $object * @param AbstractObject $object
* A Tuque FedoraObject being operated on. * A Tuque AbstractObject being operated on.
* @param array $rendered * @param array $rendered
* An arr of rendered views. * The array of rendered views.
*/ */
function hook_islandora_view_object_alter(&$object, &$rendered) { function hook_islandora_view_object_alter(&$object, &$rendered) {
} }
/**
* Alter display output if the object has the given model.
*
* @see hook_islandora_view_object_alter()
*
* @param AbstractObject $object
* A Tuque AbstractObject being operated on.
* @param array $rendered
* The array of rendered views.
*/
function hook_CMODEL_PID_islandora_view_object_alter(&$object, &$rendered) {
}
/** /**
* Generate an object's management display. * Generate an object's management display.
* *
* @param FedoraObject $object * @param AbstractObject $object
* A Tuque FedoraObject * A Tuque FedoraObject
* *
* @return array * @return array
@ -68,7 +81,7 @@ function hook_islandora_edit_object($object) {
* Content models PIDs have colons and hyphens changed to underscores, to * Content models PIDs have colons and hyphens changed to underscores, to
* create the hook name. * create the hook name.
* *
* @param FedoraObject $object * @param AbstractObject $object
* A Tuque FedoraObject * A Tuque FedoraObject
* *
* @return array * @return array
@ -80,7 +93,7 @@ function hook_CMODEL_PID_islandora_edit_object($object) {
/** /**
* Allow management display output to be altered. * Allow management display output to be altered.
* *
* @param FedoraObject $object * @param AbstractObject $object
* A Tuque FedoraObject * A Tuque FedoraObject
* @param array $rendered * @param array $rendered
* an arr of rendered views * an arr of rendered views
@ -97,7 +110,7 @@ function hook_islandora_edit_object_alter(&$object, &$rendered) {
* Changing object properties such as "label", or "state", are considered * Changing object properties such as "label", or "state", are considered
* modifications, where as manipulating an object's datstreams are not. * modifications, where as manipulating an object's datstreams are not.
* *
* @param AbstractFedoraObject $object * @param AbstractObject $object
* The object to alter. * The object to alter.
* @param array $context * @param array $context
* An associative array containing: * An associative array containing:
@ -117,7 +130,7 @@ function hook_islandora_edit_object_alter(&$object, &$rendered) {
* *
* @see FedoraApiM::modifyObject() * @see FedoraApiM::modifyObject()
*/ */
function hook_islandora_object_alter(AbstractFedoraObject $object, array &$context) { function hook_islandora_object_alter(AbstractObject $object, array &$context) {
} }
/** /**
@ -125,7 +138,7 @@ function hook_islandora_object_alter(AbstractFedoraObject $object, array &$conte
* *
* @see hook_islandora_object_alter() * @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) {
} }
/** /**
@ -138,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 * immediately, instead it will be triggered for all datastreams at the time
* of the NewFedoraObject's ingest. * 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. * at all.
* *
* Changing datastream's properties such as "label", or "state", are considered * Changing datastream's properties such as "label", or "state", are considered
* modifications, as well as changing the datastreams content. * modifications, as well as changing the datastreams content.
* *
* @param AbstractFedoraObject $object * @param AbstractObject $object
* The object to the datastream belong to. * The object to the datastream belong to.
* @param AbstractFedoraDatastream $datastream * @param AbstractDatastream $datastream
* The datastream to alter. * The datastream to alter.
* @param array $context * @param array $context
* An associative array containing: * An associative array containing:
@ -166,7 +179,7 @@ function hook_CMODEL_PID_islandora_object_alter(AbstractFedoraObject $object, ar
* *
* @see FedoraApiM::modifyDatastream() * @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) {
} }
/** /**
@ -174,7 +187,7 @@ function hook_islandora_datastream_alter(AbstractFedoraObject $object, AbstractF
* *
* @see hook_islandora_datastream_alter() * @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) {
} }
/** /**
@ -187,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 * 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. * don't have access to the ingested object at that time.
* *
* @param FedoraObject $object * @param AbstractObject $object
* The object that was ingested. * The object that was ingested.
*/ */
function hook_islandora_object_ingested(FedoraObject $object) { function hook_islandora_object_ingested(AbstractObject $object) {
} }
/** /**
@ -198,7 +211,7 @@ function hook_islandora_object_ingested(FedoraObject $object) {
* *
* @see hook_islandora_object_ingested() * @see hook_islandora_object_ingested()
*/ */
function hook_CMODEL_PID_islandora_object_ingested(FedoraObject $object) { function hook_CMODEL_PID_islandora_object_ingested(AbstractObject $object) {
} }
/** /**
@ -209,13 +222,13 @@ function hook_CMODEL_PID_islandora_object_ingested(FedoraObject $object) {
* Changing object properties such as "label", or "state", are considered * Changing object properties such as "label", or "state", are considered
* modifications, where as manipulating an object's datstreams are not. * modifications, where as manipulating an object's datstreams are not.
* *
* @param FedoraObject $object * @param AbstractObject $object
* The object that was ingested. * The object that was ingested.
* *
* @todo We should also include what changes were made in a additional * @todo We should also include what changes were made in a additional
* parameter. * parameter.
*/ */
function hook_islandora_object_modified(FedoraObject $object) { function hook_islandora_object_modified(AbstractObject $object) {
} }
/** /**
@ -223,7 +236,7 @@ function hook_islandora_object_modified(FedoraObject $object) {
* *
* @see hook_islandora_object_modified() * @see hook_islandora_object_modified()
*/ */
function hook_CMODEL_PID_islandora_object_modified(FedoraObject $object) { function hook_CMODEL_PID_islandora_object_modified(AbstractObject $object) {
} }
/** /**
@ -255,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 * 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. * don't have access to the ingested datastream at that time.
* *
* @param FedoraObject $object * @param AbstractObject $object
* The object the datastream belongs to. * The object the datastream belongs to.
* @param FedoraDatastream $datastream * @param AbstractDatastream $datastream
* The ingested datastream. * The ingested datastream.
*/ */
function hook_islandora_datastream_ingested(FedoraObject $object, FedoraDatastream $datastream) { function hook_islandora_datastream_ingested(AbstractObject $object, AbstractDatastream $datastream) {
} }
/** /**
@ -268,7 +281,7 @@ function hook_islandora_datastream_ingested(FedoraObject $object, FedoraDatastre
* *
* @see hook_islandora_object_ingested() * @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) {
} }
/** /**
@ -279,23 +292,23 @@ function hook_CMODEL_PID_DSID_islandora_datastream_ingested(FedoraObject $object
* Changing datastream properties such as "label", or "state", are considered * Changing datastream properties such as "label", or "state", are considered
* modifications, as well as the datastreams content. * modifications, as well as the datastreams content.
* *
* @param FedoraObject $object * @param AbstractObject $object
* The object the datastream belongs to. * The object the datastream belongs to.
* @param FedoraDatastream $datastream * @param AbstractDatastream $datastream
* The datastream that was ingested. * The datastream that was ingested.
* *
* @todo We should also include what changes were made in a additional * @todo We should also include what changes were made in a additional
* parameter. * parameter.
*/ */
function hook_islandora_datastream_modified(FedoraObject $object, FedoraDatastream $datastream) { function hook_islandora_datastream_modified(AbstractObject $object, AbstractDatastream $datastream) {
} }
/** /**
* Notify modules that the given datastream was ingested. * Notify modules that the given datastream was modified.
* *
* @see hook_islandora_datastream_modified() * @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) {
} }
/** /**
@ -304,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 * This hook is called after an datastream has been successfully purged, or
* when its state has been changed to "Deleted". * when its state has been changed to "Deleted".
* *
* @param FedoraObject $object * @param AbstractObject $object
* The object the datastream belonged to. * The object the datastream belonged to.
* @param string $dsid * @param string $dsid
* The ID of the datastream that was purged/deleted. * 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) {
} }
/** /**
@ -317,13 +330,13 @@ function hook_islandora_datastream_purged(FedoraObject $object, $dsid) {
* *
* @see hook_islandora_datastream_purged() * @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. * Register a datastream edit route/form.
* *
* @param FedoraObject $object * @param AbstractObject $object
* The object to check. * The object to check.
* @param string $dsid * @param string $dsid
* todo * todo
@ -373,15 +386,26 @@ function hook_islandora_undeletable_datastreams(array $models) {
* @return array * @return array
* An associative array of associative arrays which define each step in the * An associative array of associative arrays which define each step in the
* ingest process. Each step should consist of a unique name mapped to an * ingest process. Each step should consist of a unique name mapped to an
* array of properties (keys) including: * array of properties (keys) which take different paramaters based upon type:
* - type: The type of step. Currently, only "form" is implemented. * - type: Type of step. Only "form" and "callback" are implemented so far.
* - weight: The "weight" of this step--heavier(/"larger") values sink to the * Required "form" type specific parameters:
* end of the process while smaller(/"lighter") values are executed first.
* - form_id: The form building function to call to get the form structure * - form_id: The form building function to call to get the form structure
* for this step. * for this step.
* - args: An array of arguments to pass to the form building function. * - args: An array of arguments to pass to the form building function.
* And may optionally include both: * Required "callback" type specific parameters:
* - do_function: An associate array including:
* - 'function': The callback function to be called.
* - 'args': An array of arguments to pass to the callback function.
* - undo_function: An associate 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.
* Shared parameters between both types:
* - weight: The "weight" of this step--heavier(/"larger") values sink to the
* end of the process while smaller(/"lighter") values are executed first.
* Both types may optionally include:
* - module: A module from which we want to load an include. * - module: A module from which we want to load an include.
* "Form" type may optionally include:
* - file: A file to include (relative to the module's path, including the * - file: A file to include (relative to the module's path, including the
* file's extension). * file's extension).
*/ */
@ -393,6 +417,18 @@ function hook_islandora_ingest_steps(array $form_state) {
'form_id' => 'my_cool_form', 'form_id' => 'my_cool_form',
'args' => array('arg_one', 'numero deux'), 'args' => array('arg_one', 'numero deux'),
), ),
'my_cool_step_callback' => array(
'type' => 'callback',
'weight' => 2,
'do_function' => array(
'function' => 'my_cool_execute_function',
'args' => array('arg_one', 'numero deux'),
),
'undo_function' => array(
'function' => 'my_cool_undo_function',
'args' => array('arg_one', 'numero deux'),
),
),
); );
} }
/** /**
@ -407,3 +443,79 @@ function hook_islandora_ingest_steps(array $form_state) {
*/ */
function hook_CMODEL_PID_islandora_ingest_steps(array $form_state) { function hook_CMODEL_PID_islandora_ingest_steps(array $form_state) {
} }
/**
* Object-level access callback hook.
*
* @param string $op
* A string define an operation to check. Should be defined via
* hook_permission().
* @param AbstractObject $object
* An object to check the operation on.
* @param object $user
* A loaded user object, as the global $user variable might contain.
*
* @return bool|NULL
* Either boolean TRUE or FALSE to explicitly allow or deny the operation on
* the given object, or NULL to indicate that we are making no assertion
* about the outcome.
*/
function hook_islandora_object_access($op, $object, $user) {
switch ($op) {
case 'create stuff':
return TRUE;
case 'break stuff':
return FALSE;
case 'do a barrel roll!':
return NULL;
}
}
/**
* Content model specific version of hook_islandora_object_access().
*
* @see hook_islandora_object_access()
*/
function hook_CMODEL_PID_islandora_object_access($op, $object, $user) {
}
/**
* Datastream-level access callback hook.
*
* @param string $op
* A string define an operation to check. Should be defined via
* hook_permission().
* @param AbstractDatastream $object
* An object to check the operation on.
* @param object $user
* A loaded user object, as the global $user variable might contain.
*
* @return bool|NULL
* Either boolean TRUE or FALSE to explicitly allow or deny the operation on
* the given object, or NULL to indicate that we are making no assertion
* about the outcome.
*/
function hook_islandora_datastream_access($op, $object, $user) {
switch ($op) {
case 'create stuff':
return TRUE;
case 'break stuff':
return FALSE;
case 'do a barrel roll!':
return NULL;
}
}
/**
* Content model specific version of hook_islandora_datastream_access().
*
* @see hook_islandora_datastream_access()
*/
function hook_CMODEL_PID_islandora_datastream_access($op, $object, $user) {
}

4
islandora.info

@ -11,8 +11,10 @@ files[] = includes/dublin_core.inc
files[] = includes/tuque.inc files[] = includes/tuque.inc
files[] = includes/tuque_wrapper.inc files[] = includes/tuque_wrapper.inc
files[] = includes/object.entity_controller.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/authtokens.test
files[] = tests/hooks.test files[] = tests/hooks.test
files[] = tests/ingest.test
files[] = tests/hooked_access.test
files[] = tests/islandora_manage_permissions.test files[] = tests/islandora_manage_permissions.test
php = 5.3 php = 5.3

5
islandora.install

@ -10,13 +10,14 @@
*/ */
function islandora_requirements($phase) { function islandora_requirements($phase) {
$requirements = array(); $requirements = array();
// Ensure translations don't break at install time
// Ensure translations don't break at install time.
$t = get_t(); $t = get_t();
if (!class_exists('XSLTProcessor', FALSE)) { if (!class_exists('XSLTProcessor', FALSE)) {
$requirements['islandora_xsltprocessor']['title'] = $t('Islandora XSLTProcessor Prerequisite'); $requirements['islandora_xsltprocessor']['title'] = $t('Islandora XSLTProcessor Prerequisite');
$requirements['islandora_xsltprocessor']['value'] = $t('Not installed'); $requirements['islandora_xsltprocessor']['value'] = $t('Not installed');
$link = l($t('PHP XSL extension'), 'http://us2.php.net/manual/en/book.xsl.php', array('attributes' => array('target'=>'_blank'))); $link = l($t('PHP XSL extension'), 'http://us2.php.net/manual/en/book.xsl.php', array('attributes' => array('target' => '_blank')));
$requirements['islandora_xsltprocessor']['description'] = $t('The !xsllink is required. Check your installed PHP extensions and php.ini file.', array('!xsllink' => $link)); $requirements['islandora_xsltprocessor']['description'] = $t('The !xsllink is required. Check your installed PHP extensions and php.ini file.', array('!xsllink' => $link));
$requirements['islandora_xsltprocessor']['severity'] = REQUIREMENT_ERROR; $requirements['islandora_xsltprocessor']['severity'] = REQUIREMENT_ERROR;
} }

491
islandora.module

@ -52,6 +52,9 @@ define('ISLANDORA_DATASTREAM_MODIFIED_HOOK', 'islandora_datastream_modified');
define('ISLANDORA_DATASTREAM_PURGED_HOOK', 'islandora_datastream_purged'); define('ISLANDORA_DATASTREAM_PURGED_HOOK', 'islandora_datastream_purged');
define('ISLANDORA_INGEST_STEP_HOOK', 'islandora_ingest_steps'); define('ISLANDORA_INGEST_STEP_HOOK', 'islandora_ingest_steps');
// Autocomplete paths.
define('ISLANDORA_CONTENT_MODELS_AUTOCOMPLETE', 'islandora/autocomplete/content-models');
/** /**
* Implements hook_menu(). * Implements hook_menu().
* *
@ -91,7 +94,8 @@ function islandora_menu() {
'access arguments' => array(FEDORA_VIEW_OBJECTS), 'access arguments' => array(FEDORA_VIEW_OBJECTS),
); );
$items['islandora/object/%islandora_object'] = array( $items['islandora/object/%islandora_object'] = array(
'title' => 'Repository', 'title callback' => 'islandora_drupal_title',
'title arguments' => array(2),
'page callback' => 'islandora_view_object', 'page callback' => 'islandora_view_object',
'page arguments' => array(2), 'page arguments' => array(2),
'type' => MENU_NORMAL_ITEM, 'type' => MENU_NORMAL_ITEM,
@ -120,7 +124,7 @@ function islandora_menu() {
FEDORA_METADATA_EDIT, FEDORA_METADATA_EDIT,
FEDORA_ADD_DS, FEDORA_ADD_DS,
FEDORA_PURGE, FEDORA_PURGE,
FEDORA_INGEST FEDORA_INGEST,
), 2), ), 2),
); );
@ -187,8 +191,8 @@ function islandora_menu() {
'page arguments' => array(4, FALSE), 'page arguments' => array(4, FALSE),
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
'file' => 'includes/datastream.inc', 'file' => 'includes/datastream.inc',
'access callback' => 'islandora_object_datastream_access_callback', 'access callback' => 'islandora_datastream_access',
'access arguments' => array(FEDORA_VIEW_OBJECTS, 2, 4), 'access arguments' => array(FEDORA_VIEW_OBJECTS, 4),
'load arguments' => array(2), 'load arguments' => array(2),
); );
// This menu item uses token authentication in islandora_tokened_object. // This menu item uses token authentication in islandora_tokened_object.
@ -205,8 +209,8 @@ function islandora_menu() {
'page arguments' => array(4), 'page arguments' => array(4),
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
'file' => 'includes/datastream.inc', 'file' => 'includes/datastream.inc',
'access callback' => 'islandora_object_datastream_access_callback', 'access callback' => 'islandora_datastream_access',
'access arguments' => array(FEDORA_VIEW_OBJECTS, 2, 4), 'access arguments' => array(FEDORA_VIEW_OBJECTS, 4),
'load arguments' => array(2), 'load arguments' => array(2),
); );
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/edit'] = array( $items['islandora/object/%islandora_object/datastream/%islandora_datastream/edit'] = array(
@ -215,8 +219,8 @@ function islandora_menu() {
'page arguments' => array(4), 'page arguments' => array(4),
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
'file' => 'includes/datastream.inc', 'file' => 'includes/datastream.inc',
'access callback' => 'islandora_object_datastream_access_callback', 'access callback' => 'islandora_datastream_access',
'access arguments' => array(FEDORA_METADATA_EDIT, 2, 4), 'access arguments' => array(FEDORA_METADATA_EDIT, 4),
'load arguments' => array(2), 'load arguments' => array(2),
); );
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/delete'] = array( $items['islandora/object/%islandora_object/datastream/%islandora_datastream/delete'] = array(
@ -225,8 +229,8 @@ function islandora_menu() {
'page arguments' => array('islandora_delete_datastream_form', 4), 'page arguments' => array('islandora_delete_datastream_form', 4),
'file' => 'includes/delete_datastream.form.inc', 'file' => 'includes/delete_datastream.form.inc',
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
'access callback' => 'islandora_object_datastream_access_callback', 'access callback' => 'islandora_datastream_access',
'access arguments' => array(FEDORA_PURGE, 2, 4), 'access arguments' => array(FEDORA_PURGE, 4),
'load arguments' => array(2), 'load arguments' => array(2),
); );
$items['islandora/object/%islandora_object/print'] = array( $items['islandora/object/%islandora_object/print'] = array(
@ -234,16 +238,26 @@ function islandora_menu() {
'page callback' => 'islandora_print_object', 'page callback' => 'islandora_print_object',
'page arguments' => array(2), 'page arguments' => array(2),
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
'access callback' => 'islandora_object_access_callback', 'access callback' => 'islandora_object_access',
'access arguments' => array(FEDORA_VIEW_OBJECTS, 2), 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2),
'load arguments' => array(2), 'load arguments' => array(2),
); );
$items['islandora/ingest'] = array( $items['islandora/object/%islandora_object/download_clip'] = array(
'title' => 'Add an Object', 'page callback' => 'islandora_download_clip',
'page callback' => 'islandora_ingest_callback', 'page arguments' => array(2),
'file' => 'includes/ingest.menu.inc', 'type' => MENU_CALLBACK,
'type' => MENU_SUGGESTED_ITEM, 'access callback' => 'islandora_object_access',
'access arguments' => array(FEDORA_INGEST), '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; return $items;
} }
@ -286,6 +300,45 @@ function islandora_theme() {
'file' => 'theme/theme.inc', 'file' => 'theme/theme.inc',
'variables' => array('object' => NULL, 'content' => array()), 'variables' => array('object' => NULL, 'content' => array()),
), ),
// Render a bunch of objects as either a grid or a list.
'islandora_objects' => array(
'file' => 'theme/theme.inc',
'template' => 'theme/islandora-objects',
'variables' => array(
'objects' => NULL,
'display' => NULL,
'page_size' => 20,
'limit' => 10,
),
),
// Render a bunch of objects as a grid.
'islandora_objects_grid' => array(
'file' => 'theme/theme.inc',
'template' => 'theme/islandora-objects-grid',
'variables' => array('objects' => NULL),
),
// Render a bunch of objects as a list.
'islandora_objects_list' => array(
'file' => 'theme/theme.inc',
'template' => 'theme/islandora-objects-list',
'variables' => array('objects' => NULL),
),
'islandora_datastream_edit_link' => array(
'file' => 'theme/theme.inc',
'variables' => array('datastream' => NULL),
),
'islandora_datastream_delete_link' => array(
'file' => 'theme/theme.inc',
'variables' => array('datastream' => NULL),
),
'islandora_datastream_view_link' => array(
'file' => 'theme/theme.inc',
'variables' => array('datastream' => NULL),
),
'islandora_datastream_download_link' => array(
'file' => 'theme/theme.inc',
'variables' => array('datastream' => NULL),
),
); );
} }
@ -334,6 +387,120 @@ function islandora_forms($form_id) {
return $forms; return $forms;
} }
/**
* Checks whether the user can access the given object.
*
* Checks for repository access, object/datastream existance, namespace access,
* user permissions, content models.
*
* Will check the given user or the user repersented by the GET token parameter,
* failing that it will use the global user.
*
* @global $user
*
* @param mixed $object_or_datastream
* 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.
* @param array $content_models
* The required content models.
* @param bool $access_any
* (optional) TRUE to grant access if any single requirement is met from both
* the permissions and content models parameters. FALSE if all requirements
* must be met from both the permissions and content model parameters.
* @param object $user
* (optional) The account to check, if not given check the GET parameters for
* a token to restore the user. If no GET parameter is present use currently
* logged in user.
*
* @return bool
* TRUE if the user is allowed to access this object/datastream, FALSE
* otherwise.
*/
function islandora_user_access($object_or_datastream, array $permissions, $content_models = array(), $access_any = TRUE, $user = NULL) {
module_load_include('inc', 'islandora', 'includes/utilities');
$is_repository_accessible = &drupal_static(__FUNCTION__);
// If the repository is inaccessible then access always fails.
if (!isset($is_repository_accessible)) {
$is_repository_accessible = islandora_describe_repository();
if (!$is_repository_accessible) {
// Only display the inaccessible message once.
islandora_display_repository_inaccessible_message();
return FALSE;
}
}
if (!$is_repository_accessible || !is_object($object_or_datastream) || empty($permissions)) {
return FALSE;
}
// Determine what has been passed as $object.
if (is_subclass_of($object_or_datastream, 'AbstractObject')) {
$object = $object_or_datastream;
$datastream = NULL;
}
elseif (is_subclass_of($object_or_datastream, 'AbstractDatastream')) {
$datastream = $object_or_datastream;
$object = $datastream->parent;
}
// Determine the user account to test against.
if (!isset($user)) {
$token = filter_input(INPUT_GET, 'token', FILTER_SANITIZE_STRING);
if ($token) {
module_load_include('inc', 'islandora', 'includes/authtokens');
$token_user = islandora_validate_object_token($object->id, $datastream->id, $token);
if ($user) {
$user = user_load($token_user->uid);
}
}
else {
global $user;
}
}
// Check for access.
if ($access_any) {
$has_required_content_models = empty($content_models) ? TRUE : count(array_intersect($object->models, $content_models)) > 0;
if ($has_required_content_models) {
foreach ($permissions as $p) {
if ($datastream !== NULL) {
$check = islandora_datastream_access($p, $datastream, $user);
}
else {
$check = islandora_object_access($p, $object, $user);
}
if ($check) {
return TRUE;
}
}
return FALSE;
}
}
else {
$has_required_content_models = count(array_diff($content_models, $object->models)) == 0;
if ($has_required_content_models) {
foreach ($permissions as $p) {
if ($datastream !== NULL) {
$check = islandora_datastream_access($p, $datastream, $user);
}
else {
$check = islandora_object_access($p, $object, $user);
}
if (!$check) {
return FALSE;
}
}
// Should already have failed if there are no $permissions.
return TRUE;
}
}
return FALSE;
}
/** /**
* Checks whether the user can access the given object. * Checks whether the user can access the given object.
* *
@ -342,7 +509,7 @@ function islandora_forms($form_id) {
* *
* @param string $perm * @param string $perm
* User permission to test for. * 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 * The object to test, if NULL given the object doesn't exist or is
* inaccessible. * inaccessible.
* *
@ -357,7 +524,7 @@ function islandora_object_access_callback($perm, $object = NULL) {
return FALSE; return FALSE;
} }
return user_access($perm) && is_object($object) && islandora_namespace_accessible($object->id); return islandora_object_access($perm, $object);
} }
/** /**
@ -368,10 +535,10 @@ function islandora_object_access_callback($perm, $object = NULL) {
* *
* @param string $perm * @param string $perm
* The user permission to test for. * 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 * The object to test, if NULL given the object doesn't exist or is
* inaccessible. * inaccessible.
* @param FedoraDatastream $datastream * @param AbstractDatastream $datastream
* The datastream to test, if NULL given the datastream doesn't exist * The datastream to test, if NULL given the datastream doesn't exist
* or is inaccessible. * or is inaccessible.
* @param StdObject $account * @param StdObject $account
@ -382,7 +549,10 @@ function islandora_object_access_callback($perm, $object = NULL) {
*/ */
function islandora_object_datastream_access_callback($perm, $object = NULL, $datastream = NULL, $account = NULL) { function islandora_object_datastream_access_callback($perm, $object = NULL, $datastream = NULL, $account = NULL) {
module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('inc', 'islandora', 'includes/utilities');
return user_access($perm, $account) && is_object($object) && islandora_namespace_accessible($object->id) && is_object($datastream); $message = islandora_deprecated('7.x-1.2', 'Use islandora_datastream_access().');
trigger_error(filter_xss($message), E_USER_DEPRECATED);
return islandora_datastream_access($perm, $datastream, $account);
} }
/** /**
@ -390,10 +560,8 @@ function islandora_object_datastream_access_callback($perm, $object = NULL, $dat
* *
* This function will validate and use a token if present in the GET parameters. * This function will validate and use a token if present in the GET parameters.
* *
* Checks for object existance, accessiblitly, namespace permissions, * Checks for object existance, accessibility, namespace permissions,
* and user permissions * and user permissions
*
* @see islandora_object_datastream_tokened_access_callback()
*/ */
function islandora_object_datastream_tokened_access_callback($perm, $object = NULL, $datastream = NULL) { function islandora_object_datastream_tokened_access_callback($perm, $object = NULL, $datastream = NULL) {
module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('inc', 'islandora', 'includes/utilities');
@ -408,7 +576,7 @@ function islandora_object_datastream_tokened_access_callback($perm, $object = NU
} }
} }
return islandora_object_datastream_access_callback($perm, $object, $datastream, $token_account); return islandora_datastream_access($perm, $datastream, $token_account);
} }
/** /**
@ -419,7 +587,7 @@ function islandora_object_datastream_tokened_access_callback($perm, $object = NU
* *
* @param array $perms * @param array $perms
* Array of user permission to test for. * 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 * The object to test, if NULL given the object doesn't exist or is
* inaccessible. * inaccessible.
* *
@ -436,22 +604,22 @@ function islandora_object_manage_access_callback($perms, $object = NULL) {
$has_access = FALSE; $has_access = FALSE;
for ($i = 0; $i < count($perms) && !$has_access; $i++) { for ($i = 0; $i < count($perms) && !$has_access; $i++) {
$has_access = $has_access || user_access($perms[$i]); $has_access = $has_access || islandora_object_access($perms[$i], $object);
} }
return $has_access && is_object($object) && islandora_namespace_accessible($object->id); return $has_access;
} }
/** /**
* Renders the given objects manage overview page. * Renders the given objects manage overview page.
* *
* @param FedoraObject $object * @param AbstractObject $object
* The object to manage. * The object to manage.
* *
* @return string * @return string
* The HTML repersentation of the manage object page. * 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'); module_load_include('inc', 'islandora', 'includes/utilities');
$output = array(); $output = array();
foreach (islandora_build_hook_list(ISLANDORA_OVERVIEW_HOOK, $object->models) as $hook) { foreach (islandora_build_hook_list(ISLANDORA_OVERVIEW_HOOK, $object->models) as $hook) {
@ -472,14 +640,14 @@ function islandora_manage_overview_object(FedoraObject $object) {
/** /**
* Renders the default manage object page for the given 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. * The object used to render the manage object page.
* *
* @return array * @return array
* The default rendering of the object manage page, indexed at * The default rendering of the object manage page, indexed at
* 'Default Edit output'. * '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)); $output = theme('islandora_default_overview', array('islandora_object' => $object));
return array('Default overview output' => $output); return array('Default overview output' => $output);
} }
@ -493,13 +661,13 @@ function islandora_default_islandora_manage_overview_object(FedoraObject $object
* If no modules implement 'ISLANDORA_EDIT_HOOK' then this function returns the * If no modules implement 'ISLANDORA_EDIT_HOOK' then this function returns the
* default manage view. * default manage view.
* *
* @param FedoraObject $object * @param AbstractObject $object
* The object to manage. * The object to manage.
* *
* @return string * @return string
* The HTML repersentation of the manage object page. * 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/breadcrumb');
module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('inc', 'islandora', 'includes/utilities');
drupal_set_title($object->label); drupal_set_title($object->label);
@ -523,14 +691,14 @@ function islandora_edit_object(FedoraObject $object) {
/** /**
* Renders the default manage object page for the given 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. * The object used to render the manage object page.
* *
* @return array * @return array
* The default rendering of the object manage page, indexed at * The default rendering of the object manage page, indexed at
* 'Default Edit output'. * '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)); $output = theme('islandora_default_edit', array('islandora_object' => $object));
return array('Default Edit output' => $output); return array('Default Edit output' => $output);
} }
@ -555,13 +723,13 @@ function islandora_view_default_object() {
* If no modules implement the hook then the default view object page * If no modules implement the hook then the default view object page
* will be rendered. * will be rendered.
* *
* @param FedoraObject $object * @param AbstractObject $object
* The object to view. * The object to view.
* *
* @return string * @return string
* The html repersentation of this object. * 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/breadcrumb');
module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('inc', 'islandora', 'includes/utilities');
drupal_set_title($object->label); drupal_set_title($object->label);
@ -570,7 +738,8 @@ function islandora_view_object(FedoraObject $object) {
$page_number = (empty($_GET['page'])) ? '1' : $_GET['page']; $page_number = (empty($_GET['page'])) ? '1' : $_GET['page'];
$page_size = (empty($_GET['pagesize'])) ? '10' : $_GET['pagesize']; $page_size = (empty($_GET['pagesize'])) ? '10' : $_GET['pagesize'];
$output = array(); $output = array();
foreach (islandora_build_hook_list(ISLANDORA_VIEW_HOOK, $object->models) as $hook) { $hooks = islandora_build_hook_list(ISLANDORA_VIEW_HOOK, $object->models);
foreach ($hooks as $hook) {
// @todo Remove page number and size from this hook, implementers of the // @todo Remove page number and size from this hook, implementers of the
// hook should use drupal page handling directly. // hook should use drupal page handling directly.
$temp = module_invoke_all($hook, $object, $page_number, $page_size); $temp = module_invoke_all($hook, $object, $page_number, $page_size);
@ -583,14 +752,33 @@ function islandora_view_object(FedoraObject $object) {
$output = islandora_default_islandora_view_object($object); $output = islandora_default_islandora_view_object($object);
} }
arsort($output); arsort($output);
drupal_alter(ISLANDORA_VIEW_HOOK, $object, $output); drupal_alter($hooks, $object, $output);
return implode('', $output); return implode('', $output);
} }
/**
* Title callback for drupal title.
*
* Changes the drupal title to be the objects label.
* models that their modules want to provide a view for.
*
* @param AbstractObject $object
* The object to view.
*
* @return string
* The objects label.
*/
function islandora_drupal_title(AbstractObject $object) {
module_load_include('inc', 'islandora', 'includes/breadcrumb');
drupal_set_breadcrumb(islandora_get_breadcrumbs($object));
return $object->label;
}
/** /**
* Renders the default view object page for the given 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. * The object used to render the view object page.
* *
* @return array * @return array
@ -742,7 +930,7 @@ function islandora_tokened_datastream_load($datastream_id, $map) {
* *
* @param mixed $object_id * @param mixed $object_id
* The object to load the datastream from. This can be a Fedora PID or * 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. * returning the PID.
* *
* @return FedoraDatastream * @return FedoraDatastream
@ -765,7 +953,7 @@ function islandora_datastream_load($datastream_id, $object_id) {
* attribute, as in: * attribute, as in:
* <content_model name="Collection" version="2" ... * <content_model name="Collection" version="2" ...
* *
* @param FedoraObject $object * @param AbstractObject $object
* The Object the datastream belongs to. * The Object the datastream belongs to.
* @param string $dsid * @param string $dsid
* The ID of the datastream. * The ID of the datastream.
@ -834,32 +1022,76 @@ function islandora_islandora_undeletable_datastreams(array $models) {
/** /**
* Ingest the given object. * Ingest the given object.
* *
* @param NewFedoraObject $object * @param AbstractObject $object
* An ingestable FedoraObject. * An ingestable FedoraObject.
* *
* @return FedoraObject * @return FedoraObject
* The ingested FedoraObject. * The ingested FedoraObject.
*/ */
function islandora_add_object(NewFedoraObject &$object) { function islandora_add_object(AbstractObject &$object) {
return $object->repository->ingestObject($object); return $object->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. * Delete's or purges the given object.
* *
* @param FedoraObject $object * @param AbstractObject $object
* An object to delete. * An object to delete.
* *
* @return bool * @return bool
* TRUE if successful, FALSE otherwise. * TRUE if successful, FALSE otherwise.
*/ */
function islandora_delete_object(FedoraObject &$object) { function islandora_delete_object(AbstractObject &$object) {
try { try {
$object->repository->purgeObject($object->id); $object->repository->purgeObject($object->id);
$object = NULL; $object = NULL;
return TRUE; return TRUE;
} }
catch(Exception $e) { catch (Exception $e) {
// Exception message gets logged in Tuque Wrapper. // Exception message gets logged in Tuque Wrapper.
return FALSE; return FALSE;
} }
@ -872,13 +1104,13 @@ function islandora_delete_object(FedoraObject &$object) {
* Which types are undefined, but more than likely because of the hooks * Which types are undefined, but more than likely because of the hooks
* there will be several kinds. * there will be several kinds.
* *
* @param FedoraDatastream $datastream * @param AbstractDatastream $datastream
* The datastream to delete. * The datastream to delete.
* *
* @return bool * @return bool
* TRUE if successful, FALSE otherwise. * TRUE if successful, FALSE otherwise.
*/ */
function islandora_delete_datastream(FedoraDatastream &$datastream) { function islandora_delete_datastream(AbstractDatastream &$datastream) {
$object = $datastream->parent; $object = $datastream->parent;
return $object->purgeDatastream($datastream->id); return $object->purgeDatastream($datastream->id);
} }
@ -958,13 +1190,166 @@ function islandora_entity_property_info() {
* Modules can either implement preprocess functions to append content onto the * Modules can either implement preprocess functions to append content onto the
* 'content' variable, or override the display by providing a theme suggestion. * 'content' variable, or override the display by providing a theme suggestion.
* *
* @param FedoraObject $object * @param AbstractObject $object
* The object. * The object.
* *
* @return array * @return array
* A renderable array. * A renderable array.
*/ */
function islandora_print_object(FedoraObject $object) { function islandora_print_object(AbstractObject $object) {
drupal_set_title($object->label); drupal_set_title($object->label);
return theme('islandora_object_print', array('object' => $object)); return theme('islandora_object_print', array('object' => $object));
} }
/**
* Menu callback downloads the given clip.
*/
function islandora_download_clip(AbstractObject $object) {
if (isset($_GET['clip'])) {
$is_https = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on';
$http_protocol = $is_https ? 'https' : 'http';
$url = $http_protocol . '://' . $_SERVER['HTTP_HOST'] . $_GET['clip'];
$filename = $object->label;
header("Content-Disposition: attachment; filename=\"{$filename}.jpg\"");
header("Content-type: image/jpeg");
header("Content-Transfer-Encoding: binary");
$ch = curl_init();
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_URL, $url);
$response = curl_exec($ch);
curl_close($ch);
}
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']);
}
}
/**
* Hookable object access callback.
*
* @param string $op
* String identifying an operation to check. Should correspond to a
* permission declared via hook_permission().
* @param AbstractObject $object
* An object to check for permissions.
* @param object $user
* An optional loaded user object. Defaults to the global $user.
*
* @return bool
* TRUE if at least one implementation of hook_islandora_object_access()
* returned TRUE, and no implementation return FALSE; FALSE otherwise.
*/
function islandora_object_access($op, $object, $user = NULL) {
$cache = &drupal_static(__FUNCTION__);
if (!is_object($object)) {
// The object could not be loaded... Presumably, we don't have
// permission.
return FALSE;
}
if ($user === NULL) {
global $user;
}
// Populate the cache on a miss.
if (!isset($cache[$op][$object->id][$user->uid])) {
module_load_include('inc', 'islandora', 'includes/utilities');
$results = islandora_invoke_hook_list('islandora_object_access', $object->models, array(
$op,
$object,
$user,
));
// Nothing returned FALSE, and something returned TRUE.
$cache[$op][$object->id][$user->uid] = (!in_array(FALSE, $results, TRUE) && in_array(TRUE, $results, TRUE));
}
return $cache[$op][$object->id][$user->uid];
}
/**
* Implements hook_islandora_object_access().
*
* Denies according to PID namespace restrictions, then passes or denies
* according to core Drupal permissions according to user_access().
*/
function islandora_islandora_object_access($op, $object, $user) {
module_load_include('inc', 'islandora', 'includes/utilities');
return islandora_namespace_accessible($object->id) && user_access($op, $user);
}
/**
* Hookable access callback for datastreams.
*
* Requires the equivalent permissions on the object.
*/
function islandora_datastream_access($op, $datastream, $user = NULL) {
$cache = &drupal_static(__FUNCTION__);
if (!is_object($datastream)) {
// The object could not be loaded... Presumably, we don't have
// permission.
return NULL;
}
if ($user === NULL) {
global $user;
}
// Populate the cache on a miss.
if (!isset($cache[$op][$datastream->parent->id][$datastream->id][$user->uid])) {
module_load_include('inc', 'islandora', 'includes/utilities');
$object_results = islandora_invoke_hook_list('islandora_object_access', $datastream->parent->models, array(
$op,
$datastream->parent,
$user,
));
$datastream_results = islandora_invoke_hook_list('islandora_datastream_access', $datastream->parent->models, array(
$op,
$datastream,
$user,
));
// Neither the object nor the datastream check returned FALSE, and one in
// the object or datastream checks returned TRUE.
$cache[$op][$datastream->parent->id][$datastream->id][$user->uid] = (
!in_array(FALSE, $object_results, TRUE) &&
!in_array(FALSE, $datastream_results, TRUE) &&
(in_array(TRUE, $object_results, TRUE) || in_array(TRUE, $datastream_results, TRUE))
);
}
return $cache[$op][$datastream->parent->id][$datastream->id][$user->uid];
}
/**
* Implements hook_islandora_basic_collection_get_query_filters().
*/
function islandora_islandora_basic_collection_get_query_filters() {
$enforced = variable_get('islandora_namespace_restriction_enforced', FALSE);
if ($enforced) {
$namespace_array = islandora_get_allowed_namespaces();
$namespace_sparql = implode('|', $namespace_array);
return format_string('regex(str(?object), "info:fedora/(!namespaces):")', array(
'!namespaces' => $namespace_sparql,
));
}
}

6
islandora.rules.inc

@ -80,7 +80,7 @@ function islandora_rules_action_info() {
/** /**
* Checks that there is a relationship match on the given object. * 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 * the parameters for FedoraRelsExt::get() or FedoraRelsInt::get(), to try to
* find a match. * 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. * 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 * the parameters for FedoraRelsExt::remove() or FedoraRelsInt::remove(), to
* try to find a match. * 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. * 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 parameters for FedoraRelsExt::add() or FedoraRelsInt::add(), and adds
* the represented relationship. * the represented relationship.
* *

3
tests/README.txt → tests/README.md

@ -1,3 +1,4 @@
You can define your own configurations specific to your enviroment by copying 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 default.test_config.ini to test_config.ini, making your changes in the copied
file. file. These test need write access to the system's $FEDORA_HOME/server/config
directory as well as the filter-drupal.xml file.

149
tests/hooked_access.test

@ -0,0 +1,149 @@
<?php
/**
* @file
* Tests to see if the hooks get called when appropriate.
*
* In the test module 'islandora_hooked_access_test' there are implementations
* of hooks being tested. These implementations modifies the session, and
* that's how we test if the hook gets called.
*
* To make sense of these tests reference islandora_hooked_access_test.module.
*/
class IslandoraHookedAccessTestCase extends IslandoraWebTestCase {
/**
* Gets info to display to describe this test.
*
* @see IslandoraWebTestCase::getInfo()
*/
public static function getInfo() {
return array(
'name' => 'Islandora Hooked Access Callback',
'description' => 'Ensure that the hooked access callback returns appropriate results.',
'group' => 'Islandora',
);
}
/**
* Creates an admin user and a connection to a fedora repository.
*
* @see IslandoraWebTestCase::setUp()
*/
public function setUp() {
parent::setUp('islandora_hooked_access_test');
$this->repository = $this->admin->repository;
$this->objects = array(
'test:testAccessHook',
);
$this->op = FEDORA_VIEW_OBJECTS;
$this->other_op = FEDORA_INGEST;
$this->denied_op = FEDORA_PURGE;
$this->purgeTestObjects();
$this->dsid = 'asdf';
$this->createTestObjects();
$this->object = $this->repository->getObject('test:testAccessHook');
}
/**
* Free any objects/resources created for this test.
*
* @see IslandoraWebTestCase::tearDown()
*/
public function tearDown() {
$this->purgeTestObjects();
unset($this->repository);
unset($_SESSION['islandora_hooked_access_test']);
parent::tearDown();
}
/**
* Create the test object(s) to use during the test.
*/
public function createTestObjects() {
foreach ($this->objects as $object_id) {
$object = $this->repository->constructObject($object_id);
$object->label = $object_id;
$datastream = $object->constructDatastream($this->dsid, 'M');
$datastream->label = 'fdsa';
$datastream->mimetype = 'text/plain';
$datastream->content = 'Some kinda awesome content stuffs...';
$object->ingestDatastream($datastream);
$this->repository->ingestObject($object);
}
}
/**
* Purge any objects created by the test's in this class.
*/
public function purgeTestObjects() {
foreach ($this->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.
}
}
}
/**
* Deny an object permission check without an object.
*/
public function testDenyBadObject() {
$this->assertFalse(islandora_object_access($this->op, 'this is not an object'), 'Deny bad objects.');
}
/**
* Deny a datastream permission check without a datastream.
*/
public function testDenyBadDatastream() {
$this->assertFalse(islandora_datastream_access($this->op, 'this is not a datastream'), 'Deny bad datastreams.');
}
/**
* Allow operation on object.
*/
public function testAllowObject() {
$user = $this->drupalCreateUser(array($this->op));
$_SESSION['islandora_hooked_access_test'] = array(
$this->op,
$this->object,
$user,
);
$this->assertTrue(islandora_object_access($this->op, $this->object, $user), 'Allow object access.');
}
/**
* Allow operation on datastream.
*/
public function testAllowDatastream() {
$user = $this->drupalCreateUser(array($this->op));
$_SESSION['islandora_hooked_access_test'] = array(
$this->op,
$this->object['asdf'],
$user,
);
$this->assertTrue(islandora_datastream_access($this->op, $this->object['asdf'], $user), 'Allow datastream access.');
}
/**
* Deny an operation which was not explicitly allowed on an object.
*/
public function testDenyObjectExplicit() {
$this->assertFalse(islandora_object_access($this->denied_op, $this->object), 'Explicit denial of object access.');
}
/**
* Deny an operation which was not explicitly allowed on a datastream.
*/
public function testDenyDatastreamExplicit() {
$this->assertFalse(islandora_datastream_access($this->denied_op, $this->object['asdf']), 'Explicit denial of datastream access.');
}
}

12
tests/hooks.test

@ -32,7 +32,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase {
* @see IslandoraWebTestCase::setUp() * @see IslandoraWebTestCase::setUp()
*/ */
public function setUp() { public function setUp() {
parent::setUp('islandora_hooks_test', 'devel'); parent::setUp('islandora_hooks_test');
$this->repository = $this->admin->repository; $this->repository = $this->admin->repository;
$this->purgeTestObjects(); $this->purgeTestObjects();
} }
@ -67,7 +67,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase {
$object->label = "Don't Block"; $object->label = "Don't Block";
$this->repository->purgeObject($object->id); $this->repository->purgeObject($object->id);
} }
catch(Exception $e) { catch (Exception $e) {
// Meh... Either it didn't exist or the purge failed. // Meh... Either it didn't exist or the purge failed.
} }
} }
@ -95,7 +95,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase {
$this->fail('Blocked ingest should throw an Exception.'); $this->fail('Blocked ingest should throw an Exception.');
$this->repository->purgeObject($object->id); $this->repository->purgeObject($object->id);
} }
catch(Exception $e) { catch (Exception $e) {
$this->pass('Ingest blocked and exception thrown.'); $this->pass('Ingest blocked and exception thrown.');
$this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_OBJECT_INGESTED_HOOK], 'Called "hook_islandora_object_alter" when blocking ingesting via FedoraRepository::ingestObject.'); $this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_OBJECT_INGESTED_HOOK], 'Called "hook_islandora_object_alter" when blocking ingesting via FedoraRepository::ingestObject.');
$this->assertFalse($_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_INGESTED_HOOK], 'Did not called ISLANDORA_OBJECT_INGESTED_HOOK when blocking ingesting via FedoraRepository::ingestObject.'); $this->assertFalse($_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_INGESTED_HOOK], 'Did not called ISLANDORA_OBJECT_INGESTED_HOOK when blocking ingesting via FedoraRepository::ingestObject.');
@ -115,7 +115,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase {
$object->label = 'block'; $object->label = 'block';
$this->fail('Blocked modify should throw an Exception.'); $this->fail('Blocked modify should throw an Exception.');
} }
catch(Exception $e) { catch (Exception $e) {
$this->pass('Modify blocked and exception thrown.'); $this->pass('Modify blocked and exception thrown.');
$this->assertNotEqual($object->label, 'block', 'Modification did not stick.'); $this->assertNotEqual($object->label, 'block', 'Modification did not stick.');
$this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_OBJECT_MODIFIED_HOOK], 'Called "hook_islandora_object_alter" when blocking modifying via set magic functions.'); $this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_OBJECT_MODIFIED_HOOK], 'Called "hook_islandora_object_alter" when blocking modifying via set magic functions.');
@ -149,7 +149,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase {
$this->repository->purgeObject($object->id); $this->repository->purgeObject($object->id);
$this->fail('Blocked modify should throw an Exception.'); $this->fail('Blocked modify should throw an Exception.');
} }
catch(Exception $e) { catch (Exception $e) {
$this->pass('Modify blocked and exception thrown.'); $this->pass('Modify blocked and exception thrown.');
$this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_OBJECT_PURGED_HOOK], 'Called "hook_islandora_object_alter" when blocking purge via FedoraRepository::purgeObject.'); $this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_OBJECT_PURGED_HOOK], 'Called "hook_islandora_object_alter" when blocking purge via FedoraRepository::purgeObject.');
$this->assertFalse($_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_PURGED_HOOK], 'Called ISLANDORA_OBJECT_PURGED_HOOK when blocking purge via FedoraRepository::purgeObject.'); $this->assertFalse($_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_PURGED_HOOK], 'Called ISLANDORA_OBJECT_PURGED_HOOK when blocking purge via FedoraRepository::purgeObject.');
@ -191,7 +191,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase {
$ds->label = 'block'; $ds->label = 'block';
$this->fail('Blocked modify should throw an Exception.'); $this->fail('Blocked modify should throw an Exception.');
} }
catch(Exception $e) { catch (Exception $e) {
$this->pass('Modify blocked and exception thrown.'); $this->pass('Modify blocked and exception thrown.');
$this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_DATASTREAM_MODIFIED_HOOK], 'Called "hook_islandora_datastream_alter" when blocking modifying via set magic functions.'); $this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_DATASTREAM_MODIFIED_HOOK], 'Called "hook_islandora_datastream_alter" when blocking modifying via set magic functions.');
$this->assertFALSE($_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_MODIFIED_HOOK], 'Called ISLANDORA_DATASTREAM_MODIFIED_HOOK when blocking modifying via set magic functions.'); $this->assertFALSE($_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_MODIFIED_HOOK], 'Called ISLANDORA_DATASTREAM_MODIFIED_HOOK when blocking modifying via set magic functions.');

118
tests/ingest.test

@ -0,0 +1,118 @@
<?php
/**
* @file
* Tests to see if the hooks get called when appropriate.
*
* In the test module 'islandora_hooks_test' there are implementations
* of hooks being tested. These implementations modifies the session, and
* that's how we test if the hook gets called.
*
* To make sense of these tests reference islandora_hooks_test.module.
*/
class IslandoraIngestsTestCase extends IslandoraWebTestCase {
/**
* Gets info to display to describe this test.
*
* @see IslandoraWebTestCase::getInfo()
*/
public static function getInfo() {
return array(
'name' => '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.');
}
}

7
tests/islandora_hooked_access_test.info

@ -0,0 +1,7 @@
name = Islandora Hooked Access Callback testing
description = Tests callback hooks. Do not enable.
core = 7.x
package = Testing
hidden = TRUE
files[] = islandora_hooks_test.module
dependencies[] = islandora

31
tests/islandora_hooked_access_test.module

@ -0,0 +1,31 @@
<?php
/**
* @file
* Hook implementations tested in hooked_access.test
*/
/**
* Implements hook_islandora_object_access().
*/
function islandora_hooked_access_test_islandora_object_access($op, $object, $user) {
if ($op == FEDORA_PURGE) {
return FALSE;
}
if (isset($_SESSION['islandora_hooked_access_test']) && $_SESSION['islandora_hooked_access_test'] === func_get_args()) {
return TRUE;
}
return NULL;
}
/**
* Implements hook_islandora_datastream_access().
*/
function islandora_hooked_access_test_islandora_datastream_access($op, $datastream, $user) {
if (isset($_SESSION['islandora_hooked_access_test']) && $_SESSION['islandora_hooked_access_test'] === func_get_args()) {
return TRUE;
}
return NULL;
}

3
tests/islandora_test.info → tests/islandora_hooks_test.info

@ -1,6 +1,7 @@
name = Islandora Test Module name = Islandora Hook testing
description = Tests Hooks. Do not enable. description = Tests Hooks. Do not enable.
core = 7.x core = 7.x
package = Testing package = Testing
hidden = TRUE hidden = TRUE
dependencies[] = islandora dependencies[] = islandora
files[] = islandora_hooks_test.module

14
tests/islandora_test.module → tests/islandora_hooks_test.module

@ -8,7 +8,7 @@
/** /**
* Implements hook_islandora_object_alter(). * 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']) { switch ($context['action']) {
case 'ingest': case 'ingest':
if ($object->id == 'test:testIngestedObjectHook') { if ($object->id == 'test:testIngestedObjectHook') {
@ -54,7 +54,7 @@ function islandora_hooks_test_islandora_object_alter(AbstractFedoraObject $objec
/** /**
* Implements hook_islandora_object_alter(). * 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']) { switch ($context['action']) {
case 'ingest': case 'ingest':
if ($object->id == 'test:testIngestedDatastreamHook') { if ($object->id == 'test:testIngestedDatastreamHook') {
@ -100,7 +100,7 @@ function islandora_hooks_test_islandora_datastream_alter(AbstractFedoraObject $o
/** /**
* Implements hook_islandora_object_ingested(). * 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') { if ($object->id == 'test:testIngestedObjectHook') {
$_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_INGESTED_HOOK] = TRUE; $_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(). * 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') { if ($object->id == 'test:testModifiedObjectHook') {
$_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_MODIFIED_HOOK] = TRUE; $_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(). * 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") { if ($object->id == 'test:testIngestedDatastreamHook' && $datastream->id == "TEST") {
$_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_INGESTED_HOOK] = TRUE; $_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(). * 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") { if ($object->id == 'test:testModifiedDatastreamHook' && $datastream->id == "TEST") {
$_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_MODIFIED_HOOK] = TRUE; $_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(). * 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") { if ($object->id == 'test:testPurgedDatastreamHook' && $dsid == "TEST") {
$_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_PURGED_HOOK] = TRUE; $_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_PURGED_HOOK] = TRUE;
} }

7
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

166
tests/islandora_ingest_test.module

@ -0,0 +1,166 @@
<?php
/**
* @file
* Implements hooks that get tested by islandora_hooks.test
*/
/**
* Implements hook menu.
*/
function islandora_ingest_test_menu() {
return array(
'test/ingest' => 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' => '<div id="islandora-select-content-model-wrapper">',
'#suffix' => '</div>',
'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) {
}

114
tests/islandora_manage_permissions.test

@ -1,7 +1,17 @@
<?php <?php
/**
* @file
* Tests islandora permissions, and permission related funcitons.
*/
class IslandoraPermissionsTestCase extends IslandoraWebTestCase { class IslandoraPermissionsTestCase extends IslandoraWebTestCase {
/**
* Gets info to display to describe this test.
*
* @see IslandoraWebTestCase::getInfo()
*/
public static function getInfo() { public static function getInfo() {
return array( return array(
'name' => 'Islandora Manage Permissions', 'name' => 'Islandora Manage Permissions',
@ -10,69 +20,117 @@ class IslandoraPermissionsTestCase extends IslandoraWebTestCase {
); );
} }
/**
* Prepares enviroment for testing.
*
* @see IslandoraWebTestCase::setUp()
*/
public function setUp() { public function setUp() {
parent::setUp(array('islandora')); parent::setUp(array('islandora'));
} }
/**
* Test manage permissions.
*/
public function testManagePermissions() { public function testManagePermissions() {
// Test permission FEDORA_VIEW_OBJECTS.
// Create a user with permission.
// permission FEDORA_VIEW_OBJECTS
// create a user with permission
$user = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS)); $user = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS));
// log the user in // Log the user in.
$this->drupalLogin($user); $this->drupalLogin($user);
$this->clickLink(t('Islandora Repository')); $this->clickLink(t('Islandora Repository'));
$this->assertNoLink('Manage', 'Manage tab is not on current page.'); $this->assertNoLink('Manage', 'Manage tab is not on current page.');
// Test permission FEDORA_VIEW_OBJECTS, FEDORA_MANAGE_PROPERTIES.
// permission FEDORA_VIEW_OBJECTS, FEDORA_MANAGE_PROPERTIES
$user = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS, FEDORA_MANAGE_PROPERTIES)); $user = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS, FEDORA_MANAGE_PROPERTIES));
// log the user in
$this->drupalLogin($user); $this->drupalLogin($user);
$this->clickLink(t('Islandora Repository')); $this->clickLink(t('Islandora Repository'));
$this->assertLink('Manage', 0, 'Manage tab is on current page.'); $this->assertLink('Manage', 0, 'Manage tab is on current page.');
$this->clickLink(t('Manage')); $this->clickLink(t('Manage'));
$this->assertLink('Properties', 0, 'Properties tab is on current page.'); $this->assertLink('Properties', 0, 'Properties tab is on current page.');
$this->assertNoLink('Datastreams', 'Datastreams tab is not on current page.'); $this->assertNoLink('Datastreams', 'Datastreams tab is not on current page.');
$this->assertNoLink('Collection','Collection tab is not on current page.'); $this->assertNoLink('Collection', 'Collection tab is not on current page.');
// Test permission FEDORA_VIEW_OBJECTS, FEDORA_ADD_DS.
// permission FEDORA_VIEW_OBJECTS, FEDORA_ADD_DS
$user = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS, FEDORA_ADD_DS)); $user = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS, FEDORA_ADD_DS));
// log the user in
$this->drupalLogin($user); $this->drupalLogin($user);
$this->clickLink(t('Islandora Repository')); $this->clickLink(t('Islandora Repository'));
$this->assertLink('Manage', 0, 'Manage tab is on current page.'); $this->assertLink('Manage', 0, 'Manage tab is on current page.');
$this->clickLink(t('Manage')); $this->clickLink(t('Manage'));
$this->assertLink('Datastreams', 0, 'Datastreams tab is on current page.'); $this->assertLink('Datastreams', 0, 'Datastreams tab is on current page.');
$this->assertNoLink('Properties', 'Properties tab is not on current page.'); $this->assertNoLink('Properties', 'Properties tab is not on current page.');
$this->assertNoLink('Collection','Collection tab is not on current page.'); $this->assertNoLink('Collection', 'Collection tab is not on current page.');
// Test permission FEDORA_VIEW_OBJECTS, FEDORA_METADATA_EDIT.
// permission FEDORA_VIEW_OBJECTS, FEDORA_METADATA_EDIT
$user = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS, FEDORA_METADATA_EDIT)); $user = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS, FEDORA_METADATA_EDIT));
// log the user in $this->drupalLogin($user);
$this->drupalLogin($user);
$this->clickLink(t('Islandora Repository')); $this->clickLink(t('Islandora Repository'));
$this->assertLink('Manage', 0, 'Manage tab is on current page.'); $this->assertLink('Manage', 0, 'Manage tab is on current page.');
$this->clickLink(t('Manage')); $this->clickLink(t('Manage'));
$this->assertLink('Datastreams', 0, 'Datastreams tab is on current page.'); $this->assertLink('Datastreams', 0, 'Datastreams tab is on current page.');
$this->assertNoLink('Properties', 'Properties tab is not on current page.'); $this->assertNoLink('Properties', 'Properties tab is not on current page.');
$this->assertNoLink('Collection','Collection tab is not on current page.'); $this->assertNoLink('Collection', 'Collection tab is not on current page.');
// Test permission FEDORA_VIEW_OBJECTS, FEDORA_PURGE.
// permission FEDORA_VIEW_OBJECTS, FEDORA_PURGE
$user = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS, FEDORA_PURGE)); $user = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS, FEDORA_PURGE));
// log the user in
$this->drupalLogin($user); $this->drupalLogin($user);
$this->clickLink(t('Islandora Repository')); $this->clickLink(t('Islandora Repository'));
$this->assertLink('Manage', 0, 'Manage tab is on current page.'); $this->assertLink('Manage', 0, 'Manage tab is on current page.');
$this->clickLink(t('Manage')); $this->clickLink(t('Manage'));
$this->assertLink('Datastreams', 0, 'Datastreams tab is on current page.'); $this->assertLink('Datastreams', 0, 'Datastreams tab is on current page.');
$this->assertNoLink('Properties', 'Properties tab is not on current page.'); $this->assertNoLink('Properties', 'Properties tab is not on current page.');
$this->assertNoLink('Collection','Collection tab is not on current page.'); $this->assertNoLink('Collection', 'Collection tab is not on current page.');
} }
} /**
* Test generic access functions.
*
* Note that we can't test with the Global user as SimpleTest doesn't support
* it. Therefore we can't test the authtoken support.
*/
public function testAccessFunctions() {
$object = islandora_object_load(variable_get('islandora_repository_pid', 'islandora:root'));
// Test islandora_user_access().
// Test no object/permissions.
$ret = islandora_user_access(NULL, array());
$this->assertFalse($ret, 'User access denied when no object/permissions are provided.');
// Test with object no permissions.
$ret = islandora_user_access($object, array());
$this->assertFalse($ret, 'User access denied when no permissions are provided.');
// Test access with matching permission.
$user = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS));
$ret = islandora_user_access($object, array(FEDORA_VIEW_OBJECTS), array(), TRUE, $user);
$this->assertTrue($ret, 'User access granted when permissions match.');
// Test access with matching permission but access any is FALSE.
$user = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS));
$ret = islandora_user_access($object, array(FEDORA_VIEW_OBJECTS, FEDORA_PURGE), array(), FALSE, $user);
$this->assertFalse($ret, 'User access denied for matching permission but with access any set to FALSE.');
// Test access with non-matching permission.
$user = $this->drupalCreateUser(array(FEDORA_PURGE));
$ret = islandora_user_access($object, array(FEDORA_VIEW_OBJECTS), array(), TRUE, $user);
$this->assertFalse($ret, 'User access denied when permissions did not match.');
// Test access with both permissions and content model.
$user = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS));
$model = $object->models;
$model = reset($model);
$ret = islandora_user_access($object, array(FEDORA_VIEW_OBJECTS), array($model), TRUE, $user);
$this->assertTrue($ret, 'User access granted for matching permission and model.');
// Test access with matching permissions and non-matching content model.
$user = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS));
$ret = islandora_user_access($object, array(FEDORA_VIEW_OBJECTS), array('islandora:obviouslyNotACModel'), TRUE, $user);
$this->assertFalse($ret, 'User access denied for matching permission and non-matching model.');
// Test access with all matching permissions and one matching model but
// access any is FALSE.
$user = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS, FEDORA_PURGE));
$model = $object->models;
$model = reset($model);
$ret = islandora_user_access($object, array(FEDORA_VIEW_OBJECTS, FEDORA_PURGE), array($model, 'islandora:obviouslyNotACModel'), FALSE, $user);
$this->assertFalse($ret, 'User access denied for all matching permissions and one matching model but with access any set to FALSE.');
$ret = islandora_user_access($object, array(FEDORA_VIEW_OBJECTS, FEDORA_PURGE), array($model), FALSE, $user);
$this->assertTrue($ret, 'User access granted for all matching permissions and matching models with access any set to FALSE.');
// Test passing in a Datastream.
$user = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS, FEDORA_PURGE));
$ret = islandora_user_access($object['DC'], array(FEDORA_VIEW_OBJECTS), array(), TRUE, $user);
$this->assertTrue($ret, 'User access granted for matching permissions, with a datastream given instead of an object.');
}
}

130
tests/web_test_case.inc → tests/islandora_web_test_case.inc

@ -18,12 +18,17 @@ class IslandoraWebTestCase extends DrupalWebTestCase {
// Always enable islandora. // Always enable islandora.
$args[] = 'islandora'; $args[] = 'islandora';
parent::setUp($args); parent::setUp($args);
// Its possible test are running before class autoloading.
module_load_include('inc', 'islandora', 'includes/tuque');
module_load_include('inc', 'islandora', 'includes/tuque_wrapper');
$this->configuration = $this->getTestConfiguration(); $this->configuration = $this->getTestConfiguration();
if ($this->configuration['use_drupal_filter']) { if ($this->configuration['use_drupal_filter']) {
$this->backUpDrupalFilter(); $this->backUpDrupalFilter();
$this->setUpDrupalFilter(); $this->setUpDrupalFilter();
} }
$this->createAdminUser(); $this->admin = $this->createAdminUser();
} }
/** /**
@ -85,15 +90,44 @@ class IslandoraWebTestCase extends DrupalWebTestCase {
* Creates the a full fedora admin user with a repository connection. * Creates the a full fedora admin user with a repository connection.
*/ */
protected function createAdminUser() { protected function createAdminUser() {
$this->admin = new stdClass(); $roles = user_roles();
$this->admin->uid = 1; $index = array_search('administrator', $roles);
$this->admin->name = $this->configuration['admin_user']; $user = $this->drupalCreateUser();
$this->admin->pass = $this->configuration['admin_pass']; $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']); $url = variable_get('islandora_base_url', $this->configuration['fedora_url']);
$connection = islandora_get_tuque_connection($this->admin, $url); $connection = islandora_get_tuque_connection($user, $url);
$this->admin->repository = $connection->repository; $user->repository = $connection->repository;
return $this->admin; 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. * Stores the content of the Drupal Filter for later restoration.
*/ */
@ -121,4 +155,84 @@ class IslandoraWebTestCase extends DrupalWebTestCase {
unset($this->configuration); unset($this->configuration);
parent::tearDown(); 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();
}
}
} }

14
tests/scripts/line_endings.sh

@ -0,0 +1,14 @@
#!/bin/bash
RETURN=0
FILES=`find -L $1 -name "*.info" -o -name "*.txt" -o -name "*.md"`
echo "Testing for files with DOS line endings..."
for FILE in $FILES
do
file $FILE | grep CRLF
if [ $? == 0 ]
then
RETURN=1
fi
done
exit $RETURN

40
tests/scripts/travis_setup.sh

@ -0,0 +1,40 @@
#!/bin/bash
mysql -u root -e 'create database drupal;'
mysql -u root -e "create database fedora;"
mysql -u root -e "GRANT ALL PRIVILEGES ON fedora.* To 'fedora'@'localhost' IDENTIFIED BY 'fedora';"
mysql -u root -e "GRANT ALL PRIVILEGES ON drupal.* To 'drupal'@'localhost' IDENTIFIED BY 'drupal';"
cd $HOME
git clone git://github.com/Islandora/tuque.git
git clone -b $FEDORA_VERSION git://github.com/Islandora/islandora_tomcat.git
cd islandora_tomcat
export CATALINA_HOME='.'
./bin/startup.sh
cd $HOME
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-*
drush si standard --db-url=mysql://drupal:drupal@localhost/drupal --yes
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
mkdir sites/all/libraries
ln -s $HOME/tuque sites/all/libraries/tuque
drush dl --yes coder
drush dl --yes potx
drush en --yes coder_review
drush en --yes simpletest
drush en --yes potx
drush en --user=1 --yes islandora
drush cc all
sleep 20

6
tests/travis.test_config.ini

@ -0,0 +1,6 @@
[fedora]
fedora_url = "http://localhost:8080/fedora"
use_drupal_filter = TRUE
drupal_filter_file = "/home/travis/islandora_tomcat/fedora/server/config/filter-drupal.xml"
admin_user = "fedoraAdmin"
admin_pass = "fedoraAdmin"

17
theme/islandora-objects-grid.tpl.php

@ -0,0 +1,17 @@
<?php
/**
* @file
* Render a bunch of objects in a list or grid view.
*/
?>
<div class="islandora-objects-grid clearfix">
<?php foreach($objects as $object): ?>
<div class="islandora-objects-grid-item clearfix">
<dl class="islandora-object <?php print $object['class']; ?>">
<dt class="islandora-object-thumb"><?php print $object['thumb']; ?></dt>
<dd class="islandora-object-caption"><?php print $object['link']; ?></dd>
</dl>
</div>
<?php endforeach; ?>
</div>

29
theme/islandora-objects-list.tpl.php

@ -0,0 +1,29 @@
<?php
/**
* @file
* Render a bunch of objects in a list or grid view.
*/
?>
<div class="islandora-objects-list">
<?php $row_field = 0; ?>
<?php foreach($objects as $object): ?>
<?php $first = ($row_field == 0) ? 'first' : ''; ?>
<div class="islandora-objects-list-item clearfix">
<dl class="islandora-object <?php print $object['class']; ?>">
<dt class="islandora-object-thumb">
<?php print $object['thumb']; ?>
</dt>
<dd class="islandora-object-caption <?php print $object['class']?> <?php print $first; ?>">
<strong>
<?php print $object['link']; ?>
</strong>
</dd>
<dd class="islandora-object-description">
<?php print $object['description']; ?>
</dd>
</dl>
</div>
<?php $row_field++; ?>
<?php endforeach; ?>
</div>

21
theme/islandora-objects.tpl.php

@ -0,0 +1,21 @@
<?php
/**
* @file
* Render a bunch of objects in a list or grid view.
*/
?>
<div class="islandora-objects clearfix">
<span class="islandora-objects-display-switch">
<?php
print theme('links', array(
'links' => $display_links,
'attributes' => array('class' => array('links', 'inline')),
)
);
?>
</span>
<?php print $pager; ?>
<?php print $content; ?>
<?php print $pager; ?>
</div>

161
theme/theme.inc

@ -29,7 +29,9 @@ function islandora_preprocess_islandora_default_edit(array &$variables) {
$rows[] = array( $rows[] = array(
array( array(
'class' => 'datastream-id', 'class' => 'datastream-id',
'data' => l($ds->id, islandora_datastream_get_url($ds, 'view')), 'data' => theme('islandora_datastream_view_link', array(
'datastream' => $ds,
)),
), ),
array( array(
'class' => 'datastream-label', 'class' => 'datastream-label',
@ -49,15 +51,21 @@ function islandora_preprocess_islandora_default_edit(array &$variables) {
), ),
array( array(
'class' => 'datastream-download', 'class' => 'datastream-download',
'data' => l(t('download'), islandora_datastream_get_url($ds, 'download')), 'data' => theme('islandora_datastream_download_link', array(
'datastream' => $ds,
)),
), ),
array( array(
'class' => 'datstream-edit', 'class' => 'datstream-edit',
'data' => islandora_datastream_edit_get_link($ds), 'data' => theme('islandora_datastream_edit_link', array(
'datastream' => $ds,
)),
), ),
array( array(
'class' => 'datastream-delete', 'class' => 'datastream-delete',
'data' => islandora_datastream_get_delete_link($ds), 'data' => theme('islandora_datastream_delete_link', array(
'datastream' => $ds,
)),
), ),
); );
} }
@ -95,7 +103,9 @@ function islandora_preprocess_islandora_default(&$variables) {
$download_path = islandora_datastream_get_url($ds, 'download'); $download_path = islandora_datastream_get_url($ds, 'download');
$datastreams[$id]['id'] = $id; $datastreams[$id]['id'] = $id;
$datastreams[$id]['label'] = $label; $datastreams[$id]['label'] = $label;
$datastreams[$id]['label_link'] = l($label, $download_path); $datastreams[$id]['label_link'] = islandora_datastream_access(FEDORA_VIEW_OBJECTS, $ds) ?
l($label, $download_path) :
$label;
$datastreams[$id]['download_url'] = $download_path; $datastreams[$id]['download_url'] = $download_path;
$datastreams[$id]['mimetype'] = $ds->mimetype; $datastreams[$id]['mimetype'] = $ds->mimetype;
$datastreams[$id]['size'] = islandora_datastream_get_human_readable_size($ds); $datastreams[$id]['size'] = islandora_datastream_get_human_readable_size($ds);
@ -108,14 +118,14 @@ function islandora_preprocess_islandora_default(&$variables) {
} }
$variables['datastreams'] = $datastreams; $variables['datastreams'] = $datastreams;
// Objects in fcrepo4 don't always contain a DC datastream. // Objects in fcrepo4 don't always contain a DC datastream.
if (isset($islandora_object['DC'])) { if (isset($islandora_object['DC']) && islandora_datastream_access(FEDORA_VIEW_OBJECTS, $islandora_object['DC'])) {
$dc_object = DublinCore::importFromXMLString($islandora_object['DC']->content); $dc_object = DublinCore::importFromXMLString($islandora_object['DC']->content);
$dc_array = $dc_object->asArray(); $dc_array = $dc_object->asArray();
} }
$variables['dc_array'] = isset($dc_array) ? $dc_array : array(); $variables['dc_array'] = isset($dc_array) ? $dc_array : array();
$variables['islandora_dublin_core'] = isset($dc_object) ? $dc_object : NULL; $variables['islandora_dublin_core'] = isset($dc_object) ? $dc_object : NULL;
$variables['islandora_object_label'] = $islandora_object->label; $variables['islandora_object_label'] = $islandora_object->label;
if (isset($islandora_object['TN'])) { if (isset($islandora_object['TN']) && islandora_datastream_access(FEDORA_VIEW_OBJECTS, $islandora_object['TN'])) {
$variables['islandora_thumbnail_url'] = url("islandora/object/{$islandora_object->id}/datastream/TN/view"); $variables['islandora_thumbnail_url'] = url("islandora/object/{$islandora_object->id}/datastream/TN/view");
} }
} }
@ -157,3 +167,140 @@ function islandora_preprocess_islandora_object_print(array &$variables) {
function theme_islandora_object_print(array &$variables) { function theme_islandora_object_print(array &$variables) {
return drupal_render($variables['content']); return drupal_render($variables['content']);
} }
/**
* Implements hook_preprocess_theme().
*/
function islandora_preprocess_islandora_objects(array &$variables) {
module_load_include('inc', 'islandora_paged_content', 'includes/utilities');
$display = (empty($_GET['display'])) ? 'grid' : $_GET['display'];
$grid_display = $display == 'grid';
$list_display = !$grid_display;
$query_params = drupal_get_query_parameters($_GET);
$variables['display_links'] = array(
array(
'title' => t('Grid view'),
'href' => url($_GET['q'], array('absolute' => TRUE)),
'attributes' => array(
'class' => $grid_display ? 'active' : '',
),
'query' => array('display' => 'grid') + $query_params,
),
array(
'title' => t('List view'),
'href' => url($_GET['q'], array('absolute' => TRUE)),
'attributes' => array(
'class' => $list_display ? 'active' : '',
),
'query' => array('display' => 'list') + $query_params,
),
);
// Pager.
$objects = $variables['objects'];
$limit = $variables['limit'];
$page_size = $variables['page_size'];
$page = pager_default_initialize(count($objects), $limit);
$objects = array_slice($objects, $page * $limit, $limit);
$variables['pager'] = theme('pager', array('quantity' => 10));
// Content.
$map_objects = function($o) {
$o = islandora_object_load($o);
$url = "islandora/object/{$o->id}";
$link_options = array('html' => TRUE, 'attributes' => array('title' => $o->label));
$img = islandora_datastream_access(FEDORA_VIEW_OBJECTS, $o['TN']) ?
theme('image', array('path' => url("$url/datastream/TN/view"), 'attributes' => array())) :
'';
$description = NULL;
if (isset($o['DC']) && islandora_datastream_access(FEDORA_VIEW_OBJECTS, $o['DC'])) {
$dc = DublinCore::importFromXMLString($o['DC']->content);
if ($dc) {
$dc = $dc->asArray();
$description = $dc['dc:description']['value'];
}
}
return array(
'label' => $o->label,
'class' => drupal_strtolower(preg_replace('/[^A-Za-z0-9]/', '-', $o->id)),
'link' => l($o->label, $url, $link_options),
'thumb' => l($img, $url, $link_options),
'description' => $description,
);
};
$objects = array_map($map_objects, $objects);
$theme = $grid_display ? 'islandora_objects_grid' : 'islandora_objects_list';
$variables['content'] = theme($theme, array('objects' => $objects));
$module_path = drupal_get_path('module', 'islandora');
drupal_add_css("$module_path/css/islandora.objects.css");
}
/**
* Renders a link to allow downloading of a datatream.
*
* @param array $vars
* An array containing:
* - datastream: An AbstractDatastream for which to generate a download link.
*/
function theme_islandora_datastream_download_link(array $vars) {
$datastream = $vars['datastream'];
module_load_include('inc', 'islandora', 'includes/utilities');
$label = t('download');
return islandora_datastream_access(FEDORA_VIEW_OBJECTS, $datastream) ?
l($label, islandora_datastream_get_url($datastream, 'download')) :
'';
}
/**
* Renders a link to allow viewing of a datatream.
*
* @param array $vars
* An array containing:
* - datastream: An AbstractDatastream for which to generate a view link.
*/
function theme_islandora_datastream_view_link(array $vars) {
$datastream = $vars['datastream'];
module_load_include('inc', 'islandora', 'includes/utilities');
$label = check_plain($datastream->id);
return islandora_datastream_access(FEDORA_VIEW_OBJECTS, $datastream) ?
l($label, islandora_datastream_get_url($datastream, 'view')) :
$label;
}
/**
* Renders a link to allow deleting of a datatream.
*
* @param array $vars
* An array containing:
* - datastream: An AbstractDatastream for which to generate a delete link.
*/
function theme_islandora_datastream_delete_link(array $vars) {
$datastream = $vars['datastream'];
$datastreams = module_invoke_all('islandora_undeletable_datastreams', $datastream->parent->models);
$can_delete = !in_array($datastream->id, $datastreams) && islandora_datastream_access(FEDORA_PURGE, $datastream);
return $can_delete ?
l(t('delete'), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/delete") :
'';
}
/**
* Renders a link to allow editing of a datatream.
*
* @param array $vars
* An array containing:
* - datastream: An AbstractDatastream for which to generate a edit link.
*/
function theme_islandora_datastream_edit_link(array $vars) {
$datastream = $vars['datastream'];
$edit_registry = module_invoke_all('islandora_edit_datastream_registry', $datastream->parent, $datastream);
$can_edit = count($edit_registry) > 0 && islandora_datastream_access(FEDORA_METADATA_EDIT, $datastream);
return $can_edit ?
l(t('edit'), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/edit") :
'';
}

Loading…
Cancel
Save