Drupal modules for browsing and managing Fedora-based digital repositories.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

492 lines
19 KiB

<?php
// $Id$
/**
* Implementation of hook_perm()
*
* @return Array of permissions defined in this module.
*/
function fedora_attach_perm() {
return array(
'select file access by role',
);
}
/**
* Implementation of hook_nodeapi.
* On Update and Insert operations alters the file attach form to add option to ingest into fedora.
* On View option hilights files that are in the repository.
*/
function fedora_attach_nodeapi(&$node, $op, $teaser) {
module_load_include('inc', 'fedora_repository', 'api/fedora_item');
module_load_include('inc','fedora_repository','api/fedora_utils.inc');
switch ($op) {
case 'insert':
case 'update':
// ******************************************************
// *** INSERT/UPDATE
// *** Ingest a selected file into the repository.
// ******************************************************
if (user_access('upload files') && user_access('add fedora datastreams')) {
if (is_array($node->files)) {
foreach ($node->files as $fid => $file) {
$file = (object) $file; // Convert file to object type for compatibility.
$fid = $file->fid; // For the cases where we have temp fid for uplaoded files.
$success = FALSE;
$filepath = $file->filepath; // Need copy if file_move fails.
$public = file_directory_path();
$file_is_ingested = _fedora_attach_is_file_in_repository($filepath);
if (!empty($file->ingested) && !$file_is_ingested) {
// Attach flag is set, but file is not listed as being in the repository.
// so try and ingest it now.
if (user_access('select file access by role')) {
$roles = array();
if (!empty($file->roles)) {
foreach ($file->roles as $rolename => $rolevalue) {
if (!empty($rolevalue)) {
array_push($roles, $rolevalue);
}
}
}
// if (!empty($roles)) {
// Generate the security policy datastream.
$policy_stream = _fedora_attach_create_policy($roles);
// }
}
try {
$pid_namespace = variable_get('fedora_attach_pid_namespace','default:');
$pid_namespace = substr($pid_namespace, 0, strpos($pid_namespace, ":"));
$pid = fedora_item::get_next_PID_in_namespace( $pid_namespace );
$new_item = fedora_item::ingest_new_item($pid, 'A', $file->description); // PID will be generated using getNextPID
if (empty($new_item->objectProfile)) {
drupal_set_message("Unable to create fedora object. Check Watchdog log for details.", "error");
$success = FALSE;
}
else {
if (user_access('select file access by role')) {
$new_item->add_datastream_from_string($policy_stream, 'POLICY', "Security Policy", "text/xml", "X");
}
$new_item->add_datastream_from_file($file->filepath, 'OBJ', $file->filename, $file->filemime, 'M');
$new_item->add_relationship("hasModel","islandora:genericCModel",FEDORA_MODEL_URI);
module_load_include('inc', 'fedora_repository', 'api/dublin_core');
$dc = new Dublin_Core();
$dc->add_element('dc:title', $file->description);
$dc->add_element('dc:identifier', $new_item->pid);
$new_item->modify_datastream_by_value($dc->as_xml(), 'DC', 'Default Dublin Core Metadata', 'text/xml', 'X');
$success = TRUE;
}
}
catch (exception $e) {
drupal_set_message(t('An error occurred ingesting the file: ') . $e, 'error');
$new_item->purge();
drupal_set_message(t('The item has been removed from the repository'));
}
if ($success) { // We were able to ingest the file, so update the file path.
$new_filepath = '/fedora/repository/'. $new_item->pid . '/OBJ/'. $file->description;
_fedora_attach_update_filepath($new_filepath, $fid);
file_delete($filepath);
}
}
// Convert file to object for compatibility
// Remove file. Process removals first since no further processing
// will be required.
if (!empty($file->remove)) {
// If the file isn't used by any other revisions warn the user.
$count = db_result(db_query('SELECT COUNT(fid) FROM {upload} WHERE fid = %d', $fid));
if ($count < 1) {
file_delete($file->filepath);
db_query('DELETE FROM {files} WHERE fid = %d', $fid);
}
// Remove it from the session in the case of new uploads,
// that you want to disassociate before node submission.
unset($node->files[$fid]);
// Move on, so the removed file won't be added to new revisions.
continue;
}
}
}
}
break;
case 'view':
// ******************************************************
// *** VIEW
// Re-theme the file attachments table.
// Rebuild the files table and overwrite default.
// Using the rules from upload.module.
if (isset($node->files) && count($node->files) && user_access('view uploaded files') && !$teaser) {
$node->content['files']['#value'] = theme('fedora_attach_attachments', $node->files);
}
break;
}
}
/**
*Implementation of hook_menu().
*/
function fedora_attach_menu() {
$items['admin/settings/fedora_repository/attach'] = array(
'title' => 'Fedora Attach',
'page callback' => 'drupal_get_form',
'page arguments' => array('fedora_attach_admin'),
'access arguments' => array('administer site configuration'),
'type' => MENU_LOCAL_TASK,
'file' => 'fedora_attach.admin.inc',
);
return $items;
}
function fedora_attach_save(&$node) {
print ("FNARF!");
}
/**
* Implements hook_form_alter()
*
* Add a 'add to repository' checkbox to the file attach form.
*
* @param unknown_type $form
* @param unknown_type $form_state
* @param unknown_type $form_id
* Two paths, one for normal submit, one for JavaScript
*/
function fedora_attach_form_alter(&$form, $form_state, $form_id) {
$disabled = TRUE;
global $base_url;
if (isset($form['type'])) {
$node = $form['#node'];
if ($form['type']['#value'] . '_node_form' == $form_id && variable_get("upload_$node->type", TRUE)) {
$form['#submit'][] = 'fedora_attach_form_submit';
if (!empty($node->files) && is_array($node->files) && count($node->files)) { // Hijack theme function.
$form['attachments']['wrapper']['files']['#theme'] = 'fedora_attach_form';
$form['#validate']['private_upload_form_validate'] = array();
foreach ($node->files as $fid => $file) {
// Add ingest checkbox
if (is_array($file) && isset($file['ingest'])) { // Preview
$default_value = $file['ingest'];
}
else { // Node load
$default_value = _fedora_attach_is_file_in_repository($file->filepath);
$disabled = $default_value;
}
$form['attachments']['wrapper']['files'][$fid]['ingested'] = array(
'#type' => 'checkbox',
'#default_value' => $default_value,
'#disabled' => $disabled,
);
$form['attachments']['wrapper']['files'][$fid]['description']['#description'] = $base_url.$file->filepath;
}
if (user_access('select file access by role')) {
_fedora_attach_build_roles_form($form, FALSE);
}
}
}
}
elseif ($form_id == 'upload_js') {
$form['files']['#theme'] = 'fedora_attach_form';
foreach ($form['files'] as $fid => $file) {
if (!_fedora_attach_starts_with($fid, '#')) {// Ignore properties.
if (!empty($_POST['files'][$fid])) {
$ingested = (!empty($_POST['files'][$fid]['ingested']) ? $_POST['files'][$fid]['ingested'] : FALSE);
//$form['files'][$fid]['list']['#default_value'] = (!empty($_POST['files'][$fid]['[$_POST['files'][$fid]['list'];
//$form['files'][$fid]['remove']['#default_value'] = $_POST['files'][$fid]['remove'];
}
else {
$ingested = (variable_get('fedora_attach_default', 'ingested') == 'ingested');
}
$form['files'][$fid]['ingested'] = array(
'#type' => 'checkbox',
'#default_value' => $ingested,
);
$form['attachments']['wrapper']['files'][$fid]['description']['#description'] = $base_url.$file['filepath'];
if (user_access('select file access by role')) {
_fedora_attach_build_roles_form($form, TRUE);
}
}
}
}
}
/**
* Called to validate the attach form.
*
* @param string $formid
* @param array $form_values
*/
function fedora_attach_form_validate($formid, $form_values) {
if (is_array($form_values['files']) && count($form_values['files'])) {
$file = array_shift($form_values['files']);
if (!isset($file['ingested'])) {
drupal_set_message(t('Fedora Attach cannot find add repository settings.'), 'error');
// Be sure we are going after core upload module
$upload_weight = (int)db_result(db_query("SELECT weight FROM {system} WHERE name = 'upload'"));
$attach_weight = (int)db_result(db_query("SELECT weight FROM {system} WHERE name = 'fedora_attach'"));
if ($attach_weight <= $uplaod_weight) {
$new_weight = $upload_weight + 1;
drupal_set_message(t('Adjusting Fedora Attach module\'s weight to') . $new_weight, 'warning');
db_query("UPDATE {system} SET weight = '%d' WHERE name = 'fedora_attach'", $new_weight);;
}
else {
drupal_set_message(t('Please check for modules that conflict with Fedora Attach'), 'error');
}
}
}
}
/**
* Fixes edge case: When the node is first being created, the file->private info does not
* get moved automatically into the node. So we need to copy it by hand.
*
* @param array $form
* @param array $form_state
*/
function fedora_attach_form_submit($form, &$form_state) {
global $base_url;
if ($form_state['values'] && $form_state['values']['files']) {
foreach ($form_state['values']['files'] as $fid => $file) {
if ($file['remove'] && !empty($file['ingested']) && $file['ingested']) {
drupal_set_message("The attachment <a href=\"$base_url/". substr($file['filepath'], 0, strpos($file['filepath'], 'OBJ'))."\">${file['filename']}</a> was removed from this node but it will remain in the repository until it is purged it directly.");
}
if (!isset($file->ingested)) { // Newly-inserted file.
if (isset($form['attachments']['wrapper']['files'])) {
// I know it is naughty to look at the $_POST, but I can't find this value anywhere else.
// Seems like it should be in $form_state somewhere.
$ingested = !empty($_POST['files'][$fid]['ingested']);
}
else {
$ingested = (variable_get('fedora_attach_ingested', 'ingested') == 'ingested'); // Submit before attach
}
$form_state['values']['files'][$fid]['ingested'] = $ingested;
}
$form_state['values']['files'][$fid]['roles'] = (!empty($_POST['files']['roles']) ? $_POST['files']['roles'] : array());
}
}
}
// *****************************************************************************
// Theme functions ***********************************************************
// *****************************************************************************
/**
* hook_theme = Theme registry
*
* @return array
*/
function fedora_attach_theme() {
return array(
'fedora_attach_form' => array(
'arguments' => array('form' => NULL),
),
'fedora_attach_attachments' => array(
'arguments' => array('files' => NULL),
),
);
}
/**
* Based on theme_upload_form_current
* Adds the Ingest checkbox.
*
* @param array $form
*/
function theme_fedora_attach_form(&$form) {
$header = array(t('Delete'), t('List'), t('Add to Repository'), t('Label'), t('Weight'), t('Size'), '');
drupal_add_tabledrag('upload-attachments', 'order', 'sibling', 'upload-weight');
foreach (element_children($form) as $key) {
// Add class to group weight fields for drag and drop.
$form[$key]['weight']['#attributes']['class'] = 'upload-weight';
$row = array();
$row[] = drupal_render($form[$key]['remove']);
$row[] = drupal_render($form[$key]['list']);
$row[] = drupal_render($form[$key]['ingested']);
$row[] = drupal_render($form[$key]['description']);
$row[] = drupal_render($form[$key]['weight']);
$row[] = drupal_render($form[$key]['size']);
$row[] = drupal_render($form[$key]['msg']);
$rows[] = array('data' => $row, 'class' => 'draggable');
}
$output = theme('table', $header, $rows, array('id' => 'upload-attachments'));
$output .= drupal_render($form);
return $output;
}
/**
* Displays file attachments in table.
*
* @param array $files
*/
function theme_fedora_attach_attachments($files) {
$header = array(t('Attachment'), t('Size'));
$rows = array();
if (is_array($files)) {
foreach ($files as $file) {
$file = (object) $file;
if ($file->list && empty($file->remove)) {
$inspect_item = '';
if (_fedora_attach_is_file_in_repository($file->filepath)) {
$inspect_item = ' <a href="'. $GLOBALS['base_url'] . substr($file->filepath, 0, strpos($file->filepath, 'OBJ')) .
'">'. theme_image(drupal_get_path('module', 'Fedora_Repository') . '/images/view.gif', '', 'View the item\'s repository page' ) . '</a>';
}
$href = _fedora_attach_create_url($file); // this is the changed line
$text = $file->description ? $file->description : $file->filename;
$rows[] = array(l($text, $href) . $inspect_item, format_size($file->filesize));
}
}
if (count($rows)) {
return theme('table', $header, $rows, array('id' => 'attachments'));
}
}
}
function _fedora_attach_build_roles_form(&$form, $inside_js = FALSE) {
//$result = db_query("SELECT {name} from {role}");
global $user;
//while ($role = db_fetch_array($result)) {
foreach ($user->roles as $role) {
if ($role != 'anonymous user') {
$roles[] = $role;
}
}
if (empty($roles)) {
return '';
}
$new_form_elements = array(
'#type' => 'checkboxes',
'#title' => t('Roles which can view the attached items'),
'#options' => array_combine($roles, $roles),
'#description' => t('This only applies to files which you add to the repository. If no roles are checked the item will be public.'),
);
if ($inside_js) {
$form['files']['roles'] = $new_form_elements;
}
else {
$form['attachments']['wrapper']['roles'] = $new_form_elements;
}
// var_dump($form['files']);
//return $output;
}
function _fedora_attach_create_policy($roles) {
$policy_filename = !empty($roles) ? drupal_get_path('module', 'fedora_repository') . '/policies/viewANDeditbyrole.xml'
: drupal_get_path('module', 'fedora_repository') . '/policies/noObjectEditPolicy.xml';
$policy_document = new DOMDocument();
$policy_document->load($policy_filename);
$designators = $policy_document->getElementsByTagName("SubjectAttributeDesignator");
if (!empty($designators)) {
foreach ($designators as $designator) {
if ($designator->hasAttribute("AttributeId")) {
if ($designator->getAttribute('AttributeId') == 'fedoraRole') {
foreach ($roles as $role) {
//$apply = $designator->nextSibling;
foreach ($designator->parentNode->childNodes as $apply) {
if ($apply->nodeName == "Apply") {
$new_role_node = $policy_document->createElement('AttributeValue', $role);
$new_role_node->setAttribute('DataType', 'http://www.w3.org/2001/XMLSchema#string');
$apply->appendChild($new_role_node);
}
}
}
}
elseif ($designator->getAttribute('AttributeId') == 'urn:fedora:names:fedora:2.1:subject:loginId') {
// $apply = $designator->nextSibling;
foreach ($designator->parentNode->childNodes as $apply) {
if ($apply->nodeName == "Apply") {
global $user;
$new_user_node = $policy_document->createElement('AttributeValue', $user->name);
$new_user_node->setAttribute('DataType', 'http://www.w3.org/2001/XMLSchema#string');
$apply->appendChild($new_user_node);
}
}
}
}
}
}
return $policy_document->saveXML();
}
function fedora_attach_file_download($filepath) {
// Pass through if this isn't a repository item.
if (!strstr($filepath, 'fedora/repository')) {
return;
}
$result = db_query("SELECT DISTINCT(u.nid) FROM {upload} u INNER JOIN {files} f ON u.fid = f.fid ".
"WHERE f.filepath LIKE '%s'", $filepath.'%');
$has_results = FALSE;
while($row = db_fetch_array($result)) {
$has_results = TRUE;
$node = node_load($row['nid']);
if (node_access('view', $node)) {
return; // Access is ok as far as we are concerned.
}
}
if ($has_results) {
return -1;
}
else {
return;
}
}
/**
* Create a URL to a file that changes if the file is in the repository.
*
* @param file object $file
* @return str: the correct URL
*/
function _fedora_attach_create_url($file) {
if ( _fedora_attach_is_file_in_repository( $file->filepath)) {
$href = $GLOBALS['base_url'] . $file->filepath;
}
else {
$href = file_create_url((strpos($file->fid, 'upload') === FALSE ? $file->filepath : file_create_filename($file->filename, file_create_path())));
}
return $href;
}
/**
* Checks if the file path references a file in the repository.
*
* @param string $filepath
* @return boolean
*/
function _fedora_attach_is_file_in_repository($filepath) {
$repository_path = '/fedora/repository';
$is_in = _fedora_attach_starts_with($filepath, $repository_path);
return $is_in;
}
function _fedora_attach_starts_with($str, $start) {
if (count($str) == 0) { // Avoid FALSE positives.
return FALSE;
}
return strstr($str, $start) == $str;
}
/**
* Alters the file's path in the files table to point to the repository datastream.
*
* @param string $filepath
* @param int $fid
*/
function _fedora_attach_update_filepath( $filepath, $fid ) {
db_query("UPDATE {files} SET filepath = '%s' WHERE fid=%d", $filepath, $fid);
}