You are here

document.module in Document 7

Same filename and directory in other branches
  1. 6 document.module
  2. 8.x document.module

File

document.module
View source
<?php

require_once drupal_get_path('module', 'document') . '/document.inc';

/**
 * Implementation of hook_perm().
 */
function document_permission() {
  return array(
    'administer document' => array(
      'title' => 'Administer document settings',
    ),
    'moderate document' => array(
      'title' => 'Moderate documents',
    ),
    'access document' => array(
      'title' => 'Access documents',
    ),
    'download document' => array(
      'title' => 'Download documents',
    ),
    'create document content' => array(
      'title' => 'Create documents',
    ),
    'delete own document content' => array(
      'title' => 'Delete own documents',
    ),
    'delete any document content' => array(
      'title' => 'Delete any documents',
    ),
    'edit own document content' => array(
      'title' => 'Edit own documents',
    ),
    'edit any document content' => array(
      'title' => 'Edit any documents',
    ),
  );
}

/**
 * Views 2 Integration.
 * Implementation of hook_views_api().
 */
function document_views_api() {
  return array(
    'api' => 2.0,
  );
}

/**
 * Implementation of hook_mail().
 */
function document_mail($key, &$message, $params) {
  $language = $message['language'];
  $variables = document_mail_tokens($params['account'], $params['node'], $language);
  $message['subject'] .= document_mail_text($key . '_subject', $language, $variables);
  $message['body'][] = document_mail_text($key . '_body', $language, $variables);
}

/**
 * Implementation of hook_taxonomy().
 */
function document_taxonomy_term_presave($term) {

  //TODO: Clear cache only if Document vocabulary or its terms are affected.
  cache_clear_all('document_types', 'cache');
}
function document_taxonomy_term_delete($term) {

  //TODO: Clear cache only if Document vocabulary or its terms are affected.
  cache_clear_all('document_types', 'cache');
}
function document_node_access($node, $op, $account) {
  $type = node_type_get_name($node);
  if ($type == 'document') {
    switch ($op) {
      case 'create':

        // Anonymous users cannot post even if they have the permission.
        return user_access('create document content', $account) && $account->uid ? NODE_ACCESS_ALLOW : NODE_ACCESS_DENY;
      case 'update':
        return user_access('edit any document content', $account) || user_access('edit own document content', $account) && $node->uid == $account->uid ? NODE_ACCESS_ALLOW : NODE_ACCESS_DENY;
      case 'delete':
        return user_access('delete any document content', $account) || user_access('delete own document content', $account) && $node->uid == $account->uid ? NODE_ACCESS_ALLOW : NODE_ACCESS_DENY;
    }
  }
}
function document_node_info() {
  return array(
    'document' => array(
      'name' => t('Document'),
      'base' => 'document',
      'locked' => TRUE,
      'description' => t('Upload new document. Please note that the document would be visible after administrators have published it.'),
    ),
  );
}

/**
 * Implementation of hook_menu().
 */
function document_menu() {
  $items = array();
  $items['document'] = array(
    'title' => t('Documents'),
    'description' => t('Search & Download Documents.'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'document_search_form',
      NULL,
    ),
    'access arguments' => array(
      'access document',
    ),
    'file' => 'document.search.inc',
  );
  $items['document/search'] = array(
    'type' => MENU_CALLBACK,
    'page callback' => 'document_search',
    'access arguments' => array(
      'access document',
    ),
    'file' => 'document.callback.inc',
  );
  $items['document/change_doc_status'] = array(
    'type' => MENU_CALLBACK,
    'page callback' => 'document_change_doc_status',
    'access arguments' => array(
      'moderate document',
    ),
    'file' => 'document.callback.inc',
  );
  $items['document/delete_doc'] = array(
    'type' => MENU_CALLBACK,
    'page callback' => 'document_delete_doc',
    'access arguments' => array(
      'moderate document',
    ),
    'file' => 'document.callback.inc',
  );
  $items['admin/content/documents'] = array(
    'type' => MENU_LOCAL_TASK,
    'title' => t('Documents'),
    'description' => t('Moderate Documents.'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'document_moderate_form',
      NULL,
    ),
    'access arguments' => array(
      'moderate document',
    ),
    'file' => 'document.admin.inc',
  );
  $items['admin/structure/document'] = array(
    'title' => t('Documents'),
    'description' => t('Administer Documents module.'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'document_settings_form',
      NULL,
    ),
    'access arguments' => array(
      'administer document',
    ),
    'file' => 'document.admin.inc',
  );
  $items['document/add_type'] = array(
    'type' => MENU_CALLBACK,
    'page callback' => 'document_add_type',
    'access arguments' => array(
      'administer document',
    ),
    'file' => 'document.callback.inc',
  );
  $items['document/delete_types'] = array(
    'type' => MENU_CALLBACK,
    'page callback' => 'document_delete_types',
    'access arguments' => array(
      'administer document',
    ),
    'file' => 'document.callback.inc',
  );
  return $items;
}

/**
 * Implementation of hook_form().
 */
function document_form(&$node, $form_state) {
  $type = node_type_get_type($node);
  $form = array();
  $form['#attributes'] = array(
    'enctype' => 'multipart/form-data',
  );
  $form['title'] = array(
    '#type' => 'textfield',
    '#title' => check_plain($type->title_label),
    '#required' => TRUE,
    '#default_value' => $node->title,
    '#weight' => -5,
  );
  $form['document_abstract'] = array(
    '#type' => 'textarea',
    '#rows' => '5',
    '#title' => t('Abstract'),
    '#weight' => -4,
    '#default_value' => isset($node->document_abstract) ? $node->document_abstract : '',
    '#description' => 'Add Template',
  );
  $form['document_edit_fieldset'] = array(
    '#type' => 'fieldset',
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
    '#title' => t('Add Document'),
    '#weight' => -2,
    '#description' => t('Upload new document. Please note that the document will be visible after administrators have published it.'),
  );
  if (isset($node->nid) && $node->nid && user_access('moderate document')) {
    $form['document_edit_fieldset']['document_current'] = array(
      '#type' => 'item',
      '#title' => t('Current Document Path'),
      '#value' => $node->document_url,
      '#description' => t('Path to the document associated to this node for the current revision.'),
    );
  }
  $form['document_edit_fieldset']['document_author'] = array(
    '#type' => 'textfield',
    '#required' => TRUE,
    '#title' => t('Document Author(s)'),
    '#default_value' => isset($node->document_author) ? $node->document_author : '',
    '#description' => t('A comma separated list of Authors'),
  );
  $form['document_edit_fieldset']['document_year'] = array(
    '#type' => 'select',
    '#options' => drupal_map_assoc(array_reverse(document_get_years())),
    '#required' => TRUE,
    '#title' => t('Year of Publication'),
    '#default_value' => isset($node->document_year) ? $node->document_year : '',
    '#description' => t('Year of Publication'),
  );

  //  $form['document_edit_fieldset']['document_type'] = array(
  //      '#type' => 'select',
  //      '#options' => document_get_types(FALSE),
  //      '#required' => TRUE,
  //      '#title' => t('Document Type'),
  //      '#default_value' => isset($node->document_type) ? $node->document_type : '',
  //      '#description' => t('Document Type'));
  $form['document_edit_fieldset']['document_keywords'] = array(
    '#type' => 'textarea',
    '#rows' => 5,
    '#title' => t('Keywords'),
    '#description' => t('Comma separated list of key terms associated with the document.'),
    '#default_value' => isset($node->document_keywords) ? $node->document_keywords : '',
  );
  $form['document_edit_fieldset']['document_filepath'] = array(
    '#type' => 'file',
    '#title' => t('Select Document'),
    '#default_value' => isset($node->document_url) ? $node->document_url : '',
    '#description' => t('Document to upload. <b>This document should only be specified either while creating a new node, or while creating a revision for an existing node. The document will not be saved while updating an existing node, if a new revision is not created for the node.</b>'),
  );
  return $form;
}

/**
 * Implementation of hook_validate().
 */
function document_validate($node, $form, &$form_state) {
  if (isset($node->is_node_revision) && $node->is_node_revision) {

    //No validation should be performed when an earlier Revision is being reverted.
    return;
  }

  //A new document must be uploaded for a new node, or a new Revision for an existing node.
  $hasDoc = _document_is_uploaded();
  $external_url = isset($node->document_external_url) ? $node->document_external_url : '';
  $is_external = strlen($external_url) > 0;
  $existing = NULL;
  if ($hasDoc) {
    $filename = _document_get_upload_name();
    $ext = _document_get_allowed_extensions();

    //A dummy object to fool file_validate_extensions.
    $file = new stdClass();
    $file->filename = $filename;
    $errors = file_validate_extensions($file, $ext);
    if (count($errors) > 0) {

      //Error returned by file_validate_extensions has already passed a call to t().
      form_set_error('document_filepath', $errors[0]);
      return;
    }
  }
  if ($node->nid && !$node->revision) {

    //A switch from external to internal url or vice versa is only allowed while creating a revision.
    if ($existing == NULL) {
      $existing = node_load($node->nid);
    }
    $existing_external = $existing->document_external == DOCUMENT_EXTERNAL;
    if ($is_external != $existing_external) {
      form_set_error('document_filepath', t('A switch from an external document url to an internal file or vice versa is only allowed while creating a revision.'));
      return;
    }
  }
  if ($is_external) {
    if ($hasDoc) {
      form_set_error('document_external_url', t('You cannot specify an external Url and upload a document simultaneously.'));
    }
    if (!valid_url($external_url, TRUE)) {
      form_set_error('document_external_url', t('Invalid external url for document. You must specify a valid absolute url.'));
    }
    if ($node->nid && !$node->revision) {

      //A change in external url is not allowed without creating a revision.
      if ($existing == NULL) {
        $existing = node_load($node->nid);
      }
      if ($external_url != $existing->document_url) {
        form_set_error('document_external_url', t('A change in external url is only allowed while creating a revision.'));
      }
    }
  }
  else {

    //No external url specified. A document must have been uploaded while creating a node/new revision.
    if (!$node->nid || $node->revision) {
      if (!$hasDoc) {
        form_set_error('document_filepath', t('The document could not be uploaded. Neither did you specify an external url. Please try again. If the error persists, contact the administrator.'));
      }
    }
  }
  if ($hasDoc) {
    if ($node->nid && !$node->revision) {

      //A new document cannot be uploaded without creating a revision.
      form_set_error('document_filepath', t('A new document cannot be specified without creating a new Revision for an existing node.'));
    }
  }
}

/**
 * Implementation of hook_insert().
 */
function document_insert($node) {
  try {
    $external_url = isset($node->document_external_url) ? $node->document_external_url : '';
    $external = strlen($external_url) > 0 ? DOCUMENT_EXTERNAL : DOCUMENT_INTERNAL;
    $author = $node->document_author;
    $year = $node->document_year;
    $keywords = $node->document_keywords;
    $abstract = $node->document_abstract;
    $type = NULL;
    $fid = 0;
    $file = NULL;
    $doc_url = NULL;
    if (isset($node->is_node_revision) && $node->is_node_revision) {
      $type = $node->document_type;
      $fid = $node->document_fid;
      $doc_url = $node->document_url;
      $external = $node->document_external;
    }
    else {
      $type = _document_get_node_terms($node);
      if ($external == DOCUMENT_INTERNAL) {

        //Save the Document uploaded.

        //TODO: Need a better approach here.
        $validators = array(
          'file_validate_extensions' => array(
            _document_get_allowed_extensions(),
          ),
        );
        $file = file_save_upload('document_filepath', $validators, 'public://' . variable_get('document_path', ''), FILE_EXISTS_RENAME);
        if ($file) {
          $fid = $file->fid;
          $doc_url = variable_get('document_path', '') . '/' . $file->filename;

          // $doc_url = file_create_url($file->uri);

          //Set the status of the uploaded file.
          $file->status = FILE_STATUS_PERMANENT;
          file_save($file);
        }
        else {
          drupal_set_message(t('Please select a document to upload.'), 'error');
        }
      }
      else {
        $doc_url = $external_url;
      }
    }
    db_insert('document')
      ->fields(array(
      'nid' => $node->nid,
      'vid' => $node->vid,
      'fid' => $fid,
      'type' => $type,
      'author' => $author,
      'publish_year' => $year,
      'keywords' => $keywords,
      'abstract' => $abstract,
      'url' => $doc_url,
      'external' => $external,
    ))
      ->execute();
    if ($node->status == 0) {
      drupal_set_message(t('The document has been submitted. Please wait until administrators review and publish it.'), 'status');
    }
  } catch (Exception $ex) {
    drupal_set_message(t($ex
      ->getMessage()), 'error');
  }
}
function document_form_node_revision_revert_confirm_alter(&$form, &$form_state) {
  $node = $form['#node_revision'];
  if ($node->type == 'document') {

    //set a flag to indicate it is a reversion of an earlier revision.
    $form['#node_revision']->is_node_revision = TRUE;
  }
}

/**
 * Implementation of hook_update().
 */
function document_update($node) {

  //$revisions = node_revision_list($node);

  // if this is a new node or we're adding a new revision,
  if (property_exists($node, 'revision') && $node->revision) {
    document_insert($node);
  }
  else {
    if (!isset($node->document_publishing)) {

      //While publishing a document in the callback, other fields cannot change. But taxonomy is not available,

      //and hence we should not make any updations during async document publishing by the node.
      $author = $node->document_author;
      $year = $node->document_year;
      $type = _document_get_node_terms($node);
      $keywords = $node->document_keywords;
      $abstract = $node->document_abstract;

      //The Url/External status of a document cannot change without creating a revision.

      //A revision would lead to insertion code above. So, no need to update Url/External status.
      db_update('document')
        ->fields(array(
        'type' => $type,
        'author' => $author,
        'publish_year' => $year,
        'abstract' => $abstract,
        'keywords' => $keywords,
      ))
        ->condition('nid', $node->nid)
        ->condition('vid', $node->vid)
        ->execute();
    }
  }
}

/**
 * Implementation of hook_nodeapi().
 */
function document_node_revision_delete($node) {

  // Notice that we're matching a single revision based on the node's vid.
  _document_delete_revision($node->nid, $node->vid);
}

/**
 * Implementation of hook_delete().
 */
function document_delete($node) {

  //$revisions = node_revision_list($node);
  $results = db_query('SELECT * FROM {document} WHERE nid = :nid', array(
    ':nid' => $node->nid,
  ));
  foreach ($results as $rev) {
    _document_delete_revision($node->nid, $rev->vid);
  }
}

/**
 * Implementation of hook_load().
 */
function document_load($nodes) {
  $vids = array();
  foreach ($nodes as $node) {
    $vids[] = $node->vid;
  }
  $result = db_query('SELECT nid, fid AS document_fid, type AS document_type, author AS document_author, publish_year AS document_year, keywords AS document_keywords, abstract AS document_abstract, url AS document_url, external AS document_external FROM {document} d WHERE d.vid IN (:vids)', array(
    ':vids' => $vids,
  ));
  foreach ($result as $record) {
    $node = $nodes[$record->nid];
    $node->document_fid = $record->document_fid;
    $node->document_type = $record->document_type;
    $node->document_abstract = $record->document_abstract;
    $node->document_author = $record->document_author;
    $node->document_year = $record->document_year;
    $node->document_keywords = $record->document_keywords;
    $node->document_url = $record->document_url;
    $node->document_external = $record->document_external;
  }
}

/**
 * Implementation of hook_view().
 */
function document_view($node, $view_mode) {
  $node->content['document'] = array(
    '#type' => 'markup',
    '#markup' => theme('document_info', array(
      'node' => $node,
    )),
    '#weight' => -5,
  );
  return $node;
}

/**
 * Implementation of hook_theme().
 */
function document_theme($existing, $type, $theme, $path) {
  return array(
    'document_info' => array(
      'arguments' => array(
        'node' => NULL,
      ),
    ),
  );
}

/**
 * A custom theme function.
 *
 * By using this function to format our node-specific information, themes
 * can override this presentation if they wish. We also wrap the default
 * presentation in a CSS class that is prefixed by the module name. This
 * way, style sheets can modify the output without requiring theme code.
 */
function theme_document_info($variables) {
  $node = $variables['node'];
  $output = '<div class="document_info">';
  $output .= '<div class="document_info_type"><b>' . t('Type') . '</b>: %s</div>';
  $output .= '<div class="document_info_abstract"><b>' . t('Abstract') . '</b>: %s</div>';
  $output .= '<div class="document_info_author"><b>' . t('Author') . '</b>: %s</div>';
  $output .= '<div class="document_info_year"><b>' . t('Year of Publishing') . '</b>: %d</div>';
  $output .= '<div class="document_info_keywords"><b>' . t('Keywords') . '</b>: %s</div>';
  $output .= '<div class="document_info_download">%s</div>';
  $output .= '</div>';
  $fileurl = explode(":", $node->document_url, 2);
  if ($fileurl[0] == 'http' or $fileurl[0] == 'https') {
    $fileurl = explode("files/", $node->document_url);
    $uri = 'public://' . $fileurl[1];
  }
  else {
    $uri = 'public://' . $node->document_url;
  }
  $path = file_create_url($uri);
  $download_access = user_access('download document');
  if ($download_access) {
    $url = l(t('Download'), $path, array(
      'attributes' => array(
        'target' => '_blank',
      ),
    ));
  }
  else {
    $path = explode("/sites", $path);
    $path = $path[0];
    $url = l(t('Download'), $path, array(
      'attributes' => array(
        'onclick' => 'return alert("You must login to download")',
      ),
    ));
  }
  $output = sprintf($output, check_plain($node->document_type), check_plain($node->document_abstract), check_plain($node->document_author), $node->document_year, check_plain($node->document_keywords), $url);
  return $output;
}

/**
 * Implementation of hook_block().
 */
function document_block_info() {
  $blocks['document-search-block1'] = array(
    'info' => t('Document Search by author, keywords or type (radio selection)'),
  );
  $blocks['document-search-block2'] = array(
    'info' => t('Document Search by author, keywords or type (drop down type selection)'),
  );
  return $blocks;
}
function document_block_view($delta = '') {
  drupal_add_css(drupal_get_path('module', 'document') . '/document.css');
  switch ($delta) {
    case 'document-search-block1':
      $block['subject'] = t('');
      $block['content'] = drupal_get_form('document_block1_form');
      return $block;
    case 'document-search-block2':
      $block['subject'] = t('');
      $block['content'] = drupal_get_form('document_block2_form');
      return $block;
  }
}

////////////////////////////////////////////////////////////////////////////////////////

//Private Methods
function document_block1_form($form, $form_state) {
  $form = array();
  $action = url('document');
  $form['document_block1_label'] = array(
    '#type' => 'item',
    '#title' => t('Search for a document'),
    '#prefix' => '<div class="document-block-label">',
    '#suffix' => '</div>',
  );
  $form['document_block1_input'] = array(
    '#type' => 'textfield',
    '#attributes' => array(
      'class' => array(
        'document-block-input',
      ),
    ),
  );
  $form['document_block1_submit'] = array(
    '#type' => 'image_button',
    '#src' => document_image_url('doc-search.png'),
    '#attributes' => array(
      'class' => array(
        'document-block-submit',
      ),
    ),
  );
  $form['document_block1_fields'] = array(
    '#type' => 'radios',
    '#options' => array(
      DOCUMENT_SEARCH_AUTHOR => t('Author |'),
      DOCUMENT_SEARCH_KEYWORDS => t('Keywords |'),
      -1 => t('Type |'),
    ),
    '#default_value' => DOCUMENT_SEARCH_AUTHOR,
    '#attributes' => array(
      'class' => array(
        'document-block-fields',
      ),
    ),
  );
  $form['document_block1_advanced'] = array(
    '#type' => 'markup',
    '#markup' => "<div class='document-block-advanced'><a href='{$action}'>" . t('Advanced Search') . "</a></div>",
  );
  $form['#method'] = 'get';
  $form['#action'] = $action;
  return $form;
}
function document_block2_form($form, $form_state) {
  $form = array();
  $action = url('document');
  $form['document_block2_label'] = array(
    '#type' => 'item',
    '#title' => t('Search for a document'),
    '#prefix' => '<div class="document-block-label">',
    '#suffix' => '</div>',
  );
  $form['document_block2_input'] = array(
    '#type' => 'textfield',
    '#attributes' => array(
      'class' => array(
        'document-block-input',
      ),
    ),
  );
  $form['document_block2_submit'] = array(
    '#type' => 'image_button',
    '#src' => document_image_url('doc-search.png'),
    '#attributes' => array(
      'class' => array(
        'document-block-submit',
      ),
    ),
  );
  $types = document_get_types(FALSE);
  $types[''] = '--Select Type--';
  $form['document_block2_doctype'] = array(
    '#type' => 'select',
    '#options' => $types,
    '#required' => TRUE,
    '#attributes' => array(
      'class' => array(
        'document-block-doctype',
      ),
    ),
  );
  $form['document_block2_advanced'] = array(
    '#type' => 'markup',
    '#markup' => "<div class='document-block-advanced'><a href='{$action}'>" . t('Advanced Search') . "</a></div>",
  );
  $form['#method'] = 'get';
  $form['#action'] = $action;
  return $form;
}
function _document_delete_revision($nid, $vid) {

  // Notice that we're matching a single revision based on the node's vid.

  //For external url documents, there would be no file.
  $result = db_query('SELECT *
                        FROM {file_managed} AS f
                          INNER JOIN {document} AS d ON f.fid = d.fid
                        WHERE d.nid = :nid
                                AND d.vid = :vid
                                AND d.fid <> 0
                                AND d.fid NOT IN (SELECT d2.fid FROM {document} d2 WHERE d2.nid = :nid AND d2.vid <> :vid)', array(
    ':nid' => $nid,
    ':vid' => $vid,
  ));
  foreach ($result as $doc) {
    $fid = $doc->fid;
    file_delete($doc);
  }
  db_delete('document')
    ->condition('nid', $nid)
    ->condition('vid', $vid)
    ->execute();
}
function _document_is_uploaded() {
  $hasDoc = TRUE;
  if (array_key_exists('document_filepath', $_FILES)) {
    if ($_FILES['document_filepath']['error'] != UPLOAD_ERR_OK) {
      $hasDoc = FALSE;
    }
  }
  else {
    if (array_key_exists('error', $_FILES)) {
      if ($_FILES['error']['document_filepath'] != UPLOAD_ERR_OK) {
        $hasDoc = FALSE;
      }
    }
    else {
      if (array_key_exists('files', $_FILES)) {
        if ($_FILES['files']['error']['document_filepath'] != UPLOAD_ERR_OK) {
          $hasDoc = FALSE;
        }
      }
      else {
        $hasDoc = FALSE;
      }
    }
  }
  return $hasDoc;
}
function _document_get_upload_name() {
  $name = $_FILES['files']['name']['document_filepath'];
  return $name;
}
function _document_get_node_terms($node) {
  if (isset($node->document_types[$node->language])) {
    $input = $node->document_types[$node->language];
  }
  else {
    $input = $node->document_types['und'];
  }
  $term_ids = array();
  if (count($input) > 0) {
    foreach ($input as $term) {
      $term_ids[] = $term['tid'];
    }
  }
  else {
    return '';
  }
  $types = document_get_types(TRUE);
  $terms = array();
  foreach ($term_ids as $id) {
    $terms[] = $types[$id];
  }
  return implode($terms);
}
function _document_get_allowed_extensions() {
  $ext = variable_get('document_allowed_extensions', variable_get('upload_extensions_default', 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp'));
  return $ext;
}

Functions