You are here

patron.module in Library 6

Same filename and directory in other branches
  1. 5.2 patron/patron.module
  2. 6.2 patron/patron.module

File

patron/patron.module
View source
<?php

/**
 * Library patrons do not have barcodes.
 */
define('PATRON_NO_BARCODES', 0);

/**
 * Library Patrons have barcodes.
 */
define('PATRON_BARCODES', 1);

/**
 * Library Patrons are not users.
 */
define('PATRON_NOT_USER', 0);

/**
 * Library Patrons may be users.
 */
define('PATRON_USER', 1);

/**
 * Patron may use the library
 */
define('PATRON_ENABLED', 0);

/**
 * Patron may not currently use the library
 */
define('PATRON_DISABLED', 1);

/**
* Valid permissions for this module
* @return array An array of valid permissions for this module
*/
function patron_perm() {
  return array(
    'create patron content',
    'edit own patron content',
    'edit any patron content',
    'delete patron content',
    'view patron content',
    'administer patrons',
  );
}

/**
 * Implementation of hook_help()
 */
function patron_help($path, $arg) {
  switch ($path) {
    case 'patrons/email':
      if ($arg[2]) {
        return t('<p>The form below will send an email to the patron specified. If no patron is specified, the email will be sent to all active patrons.</p>', array());
      }
      else {
        return t('<p>The form below will send an email to all active patrons.</p>', array());
      }
  }
}

/**
 * Implementation of hook_node_info().
 */
function patron_node_info() {
  return array(
    'patron' => array(
      'name' => t('Library Patron'),
      'module' => 'patron',
      'description' => t('Library patrons are individuals with whom library items may be associated.'),
      'has_title' => TRUE,
      'title_label' => t('Complete Name'),
      'has_body' => FALSE,
    ),
  );
}

/**
 * Implemenation of hook_access().
 */
function patron_access($op, $node, $account) {
  if ($op == 'view') {

    //Come back and change this to change patron_uid
    if (user_access('view patron content', $account) || variable_get('patron_is_user', PATRON_NOT_USER) == PATRON_USER && $account->uid == $node->patron_uid) {
      return TRUE;
    }
    else {
      return FALSE;
    }
  }
  if ($op == 'create') {
    return user_access('create patron content', $account);
  }
  if ($op == 'update') {
    if (user_access('edit any patron content', $account) || variable_get('patron_is_user', PATRON_NOT_USER) == PATRON_USER && user_access('edit own patron content', $account) && $account->uid == $node->patron_uid) {
      return TRUE;
    }
  }
  if ($op == 'delete') {
    return user_access('delete patron content', $account);
  }
}

/** 
 * Implementation of hook_db_rewrite_sql().
 */
function patron_db_rewrite_sql($query, $primary_table, $primary_field, $args) {
  if ($query == '' && $primary_table == 'n' && ($primary_field = 'nid' && empty($args))) {
    $excluded_types = array(
      'patron',
    );
    if (!empty($excluded_types)) {
      $where = " n.type NOT IN ('" . join("','", $excluded_types) . "') ";
      return array(
        'where' => $where,
      );
    }
  }
}

/**
 * Implemenation of hook_insert().
 */
function patron_insert($node) {
  if (empty($node->patron_uid)) {
    db_query("INSERT INTO {library_patrons} (nid, name_last, name_first, email, patron_uid, barcode, disabled) VALUES (%d, '%s', '%s', '%s', NULL, '%s', %d)", $node->nid, $node->name_last, $node->name_first, $node->email, $node->barcode, $node->disabled);
  }
  else {
    db_query("INSERT INTO {library_patrons} (nid, name_last, name_first, email, patron_uid, barcode, disabled) VALUES (%d, '%s', '%s', '%s', %d, '%s', %d)", $node->nid, $node->name_last, $node->name_first, $node->email, $node->patron_uid, $node->barcode, $node->disabled);
  }
}

/**
 * Implemenation of hook_update().
 */
function patron_update($node) {
  if (empty($node->patron_uid)) {
    db_query("UPDATE {library_patrons} SET name_last = '%s', name_first = '%s', email = '%s', patron_uid = NULL, barcode = '%s', disabled = %d WHERE nid = %d", $node->name_last, $node->name_first, $node->email, $node->barcode, $node->disabled, $node->nid);
  }
  else {
    db_query("UPDATE {library_patrons} SET name_last = '%s', name_first = '%s', email = '%s', patron_uid = %d, barcode = '%s', disabled = %d WHERE nid = %d", $node->name_last, $node->name_first, $node->email, $node->patron_uid, $node->barcode, $node->disabled, $node->nid);
  }
}

/**
 * Implemenation of hook_delete().
 */
function patron_delete($node) {
  if (module_exists('library')) {
    db_query("DELETE FROM {library_transactions} WHERE patron_id = %d", $node->nid);
  }
  db_query("DELETE FROM {library_patrons} WHERE nid = %d", $node->nid);
}

/**
 * Implemenation of hook_nodeapi().
 */
function patron_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
  if ($node->type == 'patron') {
    switch ($op) {
      case 'view':
        $node->title = $node->name_first . ' ' . $node->name_last;
        if (user_access('view patron content')) {
          $node->content['email'] = array(
            '#value' => '<div class="field-patron-email">' . patron_email_link($node) . '</div>',
            '#weight' => 0,
          );
        }
        if ($node->disabled == PATRON_DISABLED) {
          $node->content['disabled'] = array(
            '#value' => '<div class="field-patron-disabled">Disabled</div>',
            '#weight' => 2,
          );
        }
        if (variable_get('patron_is_user', PATRON_NOT_USER) == PATRON_USER && !empty($node->patron_uid) && user_access('access user profiles')) {
          $patron_user = user_load($node->patron_uid);
          if ($patron_user) {
            $node->content['patron_uid'] = array(
              '#value' => '<div class="field-patron-user"><label>Drupal User: </label>' . l($patron_user->name, 'user/' . $patron_user->uid) . '</div>',
              '#weight' => -3,
            );
          }
        }
        if (variable_get('patron_use_barcodes', PATRON_NO_BARCODES) == PATRON_BARCODES) {
          $node->content['barcode'] = array(
            '#value' => '<div class="field-patron-barcode"><label>Card Number: </label>' . $node->barcode . '</div>',
            '#weight' => -1,
          );
        }
        global $user;
        watchdog('library', '%user viewed patron %name', array(
          '%user' => $user->name,
          '%name' => $node->title,
        ));
        break;
      case 'presave':
        if (!empty($node->email) && variable_get('patron_is_user', PATRON_NOT_USER) == PATRON_USER) {
          $patron_uid = db_result(db_query_range("SELECT uid from {users} where mail= '%s'", $node->email, 0, 1));
          if ($patron_uid) {
            $node->patron_uid = $patron_uid;
            $node->uid = $patron_uid;
          }
          else {
            $node->patron_uid = NULL;
          }
        }
        break;
    }
  }
}

/**
 * Implemenation of hook_load().
 */
function patron_load($node) {
  $additions = db_fetch_object(db_query("SELECT * FROM {library_patrons} WHERE nid = %d", $node->nid));
  return $additions;
}

/**
 * Implementation of hook_form().
 */
function patron_form(&$node) {
  $type = node_get_types('type', $node);
  $patrons_are_users = variable_get('patron_is_user', PATRON_NOT_USER) == PATRON_USER;
  $patron_uid = NULL;
  if ($patrons_are_users && !empty($node->email)) {
    $exists = db_result(db_query_range("SELECT uid from {users} where mail= '%s'", $node->email, 0, 1));
    if ($exists) {
      $patron_uid = $exists;
    }
  }

  // We need to define form elements for the node's title and body.
  if ($type->has_title) {
    $form['title'] = array(
      '#type' => 'textfield',
      '#title' => 'Patron Identifier (ID or Complete Name)',
      '#required' => TRUE,
      '#default_value' => $node->title,
      '#description' => t('This must be unique.'),
      '#weight' => -5,
    );
  }
  if ($type->has_body) {
    $form['body_field'] = node_body_field($node, $type->body_label, $type->min_word_count);
  }
  $form['required_for_library'] = array(
    '#type' => 'fieldset',
    '#title' => t('Required Library Fields'),
    '#collapsed' => FALSE,
    '#weight' => -3,
  );

  // Now we define the form elements specific to our node type.
  $form['required_for_library']['name_first'] = array(
    '#type' => 'textfield',
    '#title' => t('First Name'),
    '#default_value' => $node->name_first,
    '#size' => 10,
    '#maxlength' => 30,
    '#weight' => -4,
    '#required' => TRUE,
  );
  $form['required_for_library']['name_last'] = array(
    '#type' => 'textfield',
    '#title' => t('Last Name'),
    '#default_value' => $node->name_last,
    '#size' => 10,
    '#maxlength' => 30,
    '#weight' => -3,
    '#required' => TRUE,
  );
  $form['required_for_library']['email'] = array(
    '#type' => 'textfield',
    '#title' => t('E-mail'),
    '#default_value' => $node->email,
    '#size' => 20,
    '#maxlength' => 30,
    '#weight' => -1,
    '#required' => TRUE,
  );
  if ($patrons_are_users) {
    $form['required_for_library']['email']['#autocomplete_path'] = 'patrons/js/email';
    if (!user_access('administer patrons') || !user_access('access user profiles')) {
      $form['required_for_library']['email']['#access'] = FALSE;
    }
    $form['required_for_library']['email']['#description'] = t('If this email address matches an existing Drupal user, that user will be associated with this patron. Similar user emails will be suggested when you begin entering a value.');
    $form['required_for_library']['patron_uid'] = array(
      '#type' => 'value',
      '#value' => $patron_uid,
    );
  }
  if (variable_get('patron_use_barcodes', PATRON_NO_BARCODES) == PATRON_BARCODES) {
    $form['required_for_library']['barcode'] = array(
      '#type' => 'textfield',
      '#size' => 30,
      '#maxlength' => 60,
      '#title' => t('Patron Card Number/Barcode'),
      '#default_value' => $node->barcode,
      '#weight' => 0,
      '#required' => TRUE,
    );
  }
  $form['required_for_library']['disabled'] = array(
    '#type' => 'checkbox',
    '#title' => t('Disabled'),
    '#default_value' => $node->disabled,
    '#return_value' => PATRON_DISABLED,
    '#description' => t('Disabled patrons will not appear in patron lists and may not use the library'),
    '#weight' => 6,
  );
  return $form;
}

/**
 * Implementation of hook_validate().
 */
function patron_validate(&$node) {

  //Validate email
  if (!empty($node->email)) {
    if (!valid_email_address($node->email)) {
      form_set_error('email', t('Invalid email address.'));
    }
    else {
      $result = db_result(db_query_range("SELECT nid from {library_patrons} where email= '%s' and nid <> '%d'", $node->email, $node->nid, 0, 1));
      if ($result) {
        form_set_error('email', t("Duplicate email address. " . l('View existing entry with this email address.', 'node/' . $result)));
      }
    }
  }

  //Validate identifier
  $dup_result = db_result(db_query_range("SELECT nid FROM {node} WHERE title= '%s' AND nid <> %d AND type='patron'", $node->title, $node->nid, 0, 1));
  if ($dup_result) {
    form_set_error('title', t("A Patron with that identifier already exists. " . l('View existing entry.', 'node/' . $dup_result)));
  }

  //Validate that barcode is unique
  if (variable_get('patron_use_barcodes', PATRON_NO_BARCODES) == PATRON_BARCODES) {
    if (!empty($node->barcode)) {
      $node->barcode = check_plain($node->barcode);
      $not_unique = db_result(db_query("SELECT COUNT(*) FROM {library_patrons} WHERE barcode = '%s' AND barcode <> '' AND nid <> %d", $node->barcode, $node->nid));
      if ($result) {
        form_set_error('barcode', t('The barcode %barcode already exists. Please enter a different barcode.', array(
          '%barcode' => $node->barcode,
        )));
      }
    }
  }
}

/**
* Retrieve a pipe delimited string of autocomplete suggestions for existing patron
*/
function patron_autocomplete($string) {
  $matches = array();
  $result = db_query_range("SELECT n.nid, lp.barcode, n.title FROM {node} n, {library_patrons} lp WHERE lp.nid = n.nid AND n.type = 'patron' AND lp.disabled = %d AND (LOWER(n.title) LIKE LOWER('%%%s%%') OR lp.barcode = '%s')", PATRON_ENABLED, check_plain($string), check_plain($string), 0, 10);
  $barcodes = variable_get('patron_use_barcodes', PATRON_NO_BARCODES);
  while ($patron = db_fetch_object($result)) {
    if ($barcodes == PATRON_BARCODES && !empty($patron->barcode)) {
      $matches[$patron->title . ' [nid:' . $patron->nid . ']'] = check_plain($patron->barcode) . ' (' . check_plain($patron->title) . ')';
    }
    else {
      $matches[$patron->title . ' [nid:' . $patron->nid . ']'] = check_plain($patron->title);
    }
  }
  print drupal_to_js($matches);
  exit;
}

/**
* Retrieve a pipe delimited string of autocomplete suggestions for existing patron
*/
function patron_email_autocomplete($string) {
  $matches = array();
  $result = db_query_range("SELECT mail from {users} where status = 1 AND LOWER(mail) LIKE LOWER('%s%%')", check_plain($string), 0, 10);
  while ($patron = db_fetch_object($result)) {
    $matches[$patron->mail] = check_plain($patron->mail);
  }
  print drupal_to_js($matches);
  exit;
}

/**
 * Retrieve a list of patrons
 * @param $nid 
 *  If this is blank, only active patrons are returned.  If 'all', all are returned.  If a number, a specific patron is returned. 
 */
function patron_get_patrons($nid = NULL) {
  if (!$nid) {
    $result = db_query("SELECT * FROM {node} n, {library_patrons} lp WHERE lp.nid = n.nid AND n.type = 'patron' AND lp.disabled = %d ORDER BY lp.name_last, lp.name_first", PATRON_ENABLED);
  }
  elseif (is_numeric($nid)) {
    $result = db_query_range("SELECT * FROM {node} n, {library_patrons} lp WHERE lp.nid = n.nid AND n.type = 'patron' AND n.nid = %d ORDER BY lp.name_last, lp.name_first", $nid, 0, 1);
  }
  else {
    $result = db_query("SELECT * FROM {node} n, {library_patrons} lp WHERE lp.nid = n.nid AND n.type = 'patron' ORDER BY lp.name_last, lp.name_first");
  }
  $patrons = array();
  while ($patron = db_fetch_object($result)) {
    $patrons[] = $patron;
  }
  return empty($patrons) ? FALSE : $patrons;
}

/**
 * Implementation of hook_menu()
 */
function patron_menu() {
  $items = array();
  $items['patrons/autocomplete'] = array(
    'title' => t('Patron Autocomplete'),
    'page callback' => 'patron_autocomplete',
    'access arguments' => array(
      'access content',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['patrons'] = array(
    'title' => 'Patrons',
    'page callback' => 'patron_list_patrons',
    'access arguments' => array(
      'view patron content',
    ),
    'file' => 'patron.pages.inc',
  );
  $items['patrons/email'] = array(
    'title' => 'Send Email',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'patron_email_form',
    ),
    'access arguments' => array(
      'edit any patron content',
    ),
    'file' => 'patron.pages.inc',
  );
  $items['admin/settings/library/patrons'] = array(
    'title' => 'Patron Settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'patron_admin_settings',
    ),
    'access arguments' => array(
      'administer patrons',
    ),
  );
  $items['patrons/js/email'] = array(
    'page callback' => 'patron_email_autocomplete',
    'type' => MENU_CALLBACK,
    'access arguments' => array(
      'access content',
    ),
  );
  return $items;
}
function patron_email_js() {
  $email = $_POST['email'];
  if ($email != '' && !is_null($email)) {
    $exists = db_query_range("SELECT uid, name from {users} where mail= '%s'", $node->email, 0, 1);
    if ($exists) {
      while ($patron = db_fetch_object($exists)) {

        // Build the new form.
        $form_state = array(
          'submitted' => FALSE,
        );
        $form_build_id = $_POST['form_build_id'];

        // We retreive the cached form, change the value, and resave.
        $form = form_get_cache($form_build_id, $form_state);
        form_set_value($form['required_for_library']['patron_uid'], $patron->uid, $form_state);
        $output = 'Matching Drupal user found. Username: ' . $patron->name;
        print drupal_json(array(
          'data' => $output,
        ));
      }
    }
  }
}

/**
 * Menu callback: Edit Patron Settings.
 */
function patron_admin_settings() {
  $form = array();
  $form['patron_use_barcodes'] = array(
    '#type' => 'checkbox',
    '#title' => t('Use Library Cards (with Barcodes) for Library Patrons'),
    '#default_value' => variable_get('patron_use_barcodes', 0),
    '#return_value' => 1,
    '#description' => t('This will allow you to use library cards.  However, you must have a unique barcode for every patron.'),
  );
  $form['user_settings'] = array(
    '#type' => 'fieldset',
    '#title' => t('User Settings'),
  );
  $form['user_settings']['patron_is_user'] = array(
    '#type' => 'checkbox',
    '#title' => t('Associate Library Patrons with Drupal Users'),
    '#default_value' => variable_get('patron_is_user', 0),
    '#return_value' => 1,
    '#description' => t('You must create the user account first, and the Drupal user and library patron must have the same email address.'),
  );

  /* Only allow if patrons do NOT have library cards!! */
  if (variable_get('patron_use_barcodes', PATRON_NO_BARCODES) == PATRON_NO_BARCODES) {
    $form['user_settings']['patron_autocreate'] = array(
      '#type' => 'checkbox',
      '#title' => t('Autocreate Library Patron on User Registration and Delete on User Deletion'),
      '#default_value' => variable_get('patron_autocreate', 0),
      '#return_value' => 1,
      '#description' => t('You must associate library patrons with drupal users first.'),
    );
  }
  return system_settings_form($form);
}

/**
 * Implementation of hook_mail()
 */
function patron_mail($key, &$message, $params) {
  $language = $message['language'];
  switch ($key) {
    case 'email_form':
      $message['subject'] .= $params['subject'];
      $message['body'][] = $params['message'];
      break;
  }
}
function patron_email_link($patron) {
  $output = '';
  if ($patron->email) {
    $output = l('E-mail', 'patrons/email/' . $patron->nid);
  }
  return $output;
}

/**
 * Implementation of hook_user().
 */
function patron_user($op, &$edit, &$user, $category = NULL) {
  if (variable_get('patron_is_user', PATRON_NOT_USER) == PATRON_USER) {
    switch ($op) {
      case 'load':
        $user->patron = patron_load_by_uid($user->uid);
        break;
      case 'after_update':

        //If the user email has changed, update the patron email to match
        $node = patron_load_by_uid($user->uid);
        if (!empty($node) && $node->email != $user->mail) {
          $node->email = $user->mail;
          node_save($node);
        }
        break;
      case 'view':
        $patron = patron_load_by_uid($user->uid);
        $cur_user = $GLOBALS['user'];
        if (variable_get('patron_is_user', PATRON_NOT_USER) == PATRON_USER && !empty($patron) && (node_access('view', 'patron') || $cur_user->uid == $user->uid)) {
          $user->content['patron_name'] = array(
            '#type' => 'user_profile_item',
            '#title' => 'Patron Name',
            '#value' => l($patron->name_first . ' ' . $patron->name_last, 'node/' . $patron->nid),
            '#attributes' => array(
              'class' => 'profile-patron',
            ),
          );
        }
        break;
      case 'register':
        if (variable_get('patron_autocreate', 0) == 1) {
          return patron_register_form();
        }
        break;
      case 'insert':
        if (variable_get('patron_autocreate', 0) == 1 && isset($edit['name_last'])) {
          return patron_create_patron($edit, $user);
        }
        break;
      case 'delete':

        //$patron = patron_load_by_uid($user->uid);

        //if (variable_get('patron_autocreate', 0) == 1 && !empty($patron) && is_numeric($patron->nid)) {

        //node_delete($patron->nid);

        //}
        break;
    }
  }
}
function patron_load_by_uid($uid) {
  if (variable_get('patron_is_user', PATRON_NOT_USER) == PATRON_USER && is_numeric($uid)) {
    $nid = db_result(db_query_range("SELECT nid FROM {library_patrons} WHERE patron_uid = %d", $uid, 0, 1));
    if ($nid) {
      $node = node_load($nid);
      return $node;
    }
  }
  return '';
}
function patron_register_form() {
  $form = array();
  $form['required_for_library'] = array(
    '#type' => 'fieldset',
    '#title' => t('Required Patron Fields'),
    '#collapsed' => FALSE,
    '#weight' => -3,
  );
  $form['required_for_library']['name_first'] = array(
    '#type' => 'textfield',
    '#title' => t('First Name'),
    '#default_value' => '',
    '#size' => 10,
    '#maxlength' => 30,
    '#weight' => -4,
    '#required' => TRUE,
  );
  $form['required_for_library']['name_last'] = array(
    '#type' => 'textfield',
    '#title' => t('Last Name'),
    '#default_value' => '',
    '#size' => 10,
    '#maxlength' => 30,
    '#weight' => -3,
    '#required' => TRUE,
  );
  return $form;
}
function patron_create_patron(&$edit, $user) {
  $node = (object) array(
    'type' => 'patron',
    'title' => check_plain($edit['name_last']) . ', ' . check_plain($edit['name_first']),
    'name' => $user->name,
    'uid' => $user->uid,
    'email' => $user->mail,
    'name_last' => check_plain($edit['name_last']),
    'name_first' => check_plain($edit['name_first']),
    'patron_uid' => $user->uid,
  );
  node_save($node);
}

Functions

Namesort descending Description
patron_access Implemenation of hook_access().
patron_admin_settings Menu callback: Edit Patron Settings.
patron_autocomplete Retrieve a pipe delimited string of autocomplete suggestions for existing patron
patron_create_patron
patron_db_rewrite_sql Implementation of hook_db_rewrite_sql().
patron_delete Implemenation of hook_delete().
patron_email_autocomplete Retrieve a pipe delimited string of autocomplete suggestions for existing patron
patron_email_js
patron_email_link
patron_form Implementation of hook_form().
patron_get_patrons Retrieve a list of patrons
patron_help Implementation of hook_help()
patron_insert Implemenation of hook_insert().
patron_load Implemenation of hook_load().
patron_load_by_uid
patron_mail Implementation of hook_mail()
patron_menu Implementation of hook_menu()
patron_nodeapi Implemenation of hook_nodeapi().
patron_node_info Implementation of hook_node_info().
patron_perm Valid permissions for this module
patron_register_form
patron_update Implemenation of hook_update().
patron_user Implementation of hook_user().
patron_validate Implementation of hook_validate().

Constants

Namesort descending Description
PATRON_BARCODES Library Patrons have barcodes.
PATRON_DISABLED Patron may not currently use the library
PATRON_ENABLED Patron may use the library
PATRON_NOT_USER Library Patrons are not users.
PATRON_NO_BARCODES Library patrons do not have barcodes.
PATRON_USER Library Patrons may be users.