You are here

datereminder.module in Date Reminder 6

Same filename and directory in other branches
  1. 6.2 datereminder.module
  2. 7 datereminder.module

Support for reminders for nodes with dates.

datereminder, or date reminder. A module that lets an authorized user ask for a reminder to be set at one or more durations before a scheduled event. It can be a repeating event; reminders will be sent at the requested times before each occurance.

Significant portions of this were blatently borrowed from or at least inspired by notifications. Notifications was oh so close to what I wanted, but just not quite.

See the README file for a list of outstanding issues.

File

datereminder.module
View source
<?php

/**
 * @file
 * Support for reminders for nodes with dates.
 *
 * datereminder, or date reminder.  A module that lets an authorized user
 * ask for a reminder to be set at one or more durations before a
 * scheduled event.  It can be a repeating event; reminders will
 * be sent at the requested times before each occurance.
 *
 * Significant portions of this were blatently borrowed from or
 * at least inspired by notifications.  Notifications was oh so close
 * to what I wanted, but just not quite.
 *
 * See the README file for a list of outstanding issues.
 */

/**
 * Implements of hook_menu().
 */
function datereminder_menu() {
  module_load_include('inc', 'datereminder', 'includes/defines');
  $astab = variable_get('datereminder_as_tab', FALSE);
  $path = drupal_get_path('module', 'datereminder') . '/includes';
  $items = array();
  $items['admin/settings/datereminder'] = array(
    'title' => 'Date reminders',
    'description' => 'Configure reminders for calendar events',
    'page callback' => 'drupal_get_form',
    'access arguments' => array(
      DATEREMINDER_ADMINISTER_REMINDERS,
    ),
    'page arguments' => array(
      'datereminder_settings_form',
    ),
    'file' => 'admin.settings.inc',
    'file path' => $path,
  );
  $items['admin/settings/datereminder/settings'] = array(
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'title' => 'Configure Settings',
  );
  $items['admin/settings/datereminder/view'] = array(
    'type' => MENU_LOCAL_TASK,
    'title' => 'View all',
    'description' => 'View all reminders',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'datereminder_form_summary',
      NULL,
      'all',
      'm',
    ),
    'access arguments' => array(
      DATEREMINDER_ADMINISTER_REMINDERS,
    ),
    'file' => 'datereminder_form.inc',
    'file path' => $path,
  );
  $items['user/%user/datereminder'] = array(
    'type' => MENU_LOCAL_TASK,
    'title' => 'Reminders',
    'description' => 'Outstanding reminders for this user',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'datereminder_form_summary',
      1,
      'all_user',
      'm',
    ),
    'access callback' => 'datereminder_allowed_access_user',
    'access arguments' => array(
      1,
    ),
    'file' => 'datereminder_form.inc',
    'file path' => $path,
  );

  /* Different menus installed depending on where reminders are displayed */
  if ($astab) {
    $items['node/%node/datereminder'] = array(
      'type' => MENU_LOCAL_TASK,
      'title' => 'Reminders',
      'description' => 'Your reminders for this event',
      'access callback' => 'datereminder_allowed_access_node',
      'access arguments' => array(
        1,
        'own',
        'menu',
      ),
      'page callback' => 'drupal_get_form',
      'page arguments' => array(
        'datereminder_form',
        1,
        'm',
      ),
      'file' => 'datereminder_form.inc',
      'file path' => $path,
    );
    $items['node/%node/datereminder/mine'] = array(
      'type' => MENU_DEFAULT_LOCAL_TASK,
      'title' => 'Your Reminders',
      'weight' => -10,
    );
    $items['node/%node/datereminder/all'] = array(
      'type' => MENU_LOCAL_TASK,
      'title' => 'All For This Event',
      'description' => 'All reminders for this event',
      'access callback' => 'datereminder_allowed_access_node',
      'access arguments' => array(
        1,
        'all',
        'menu',
      ),
      'page callback' => 'drupal_get_form',
      'page arguments' => array(
        'datereminder_form_summary',
        1,
        'all_node',
        'm',
      ),
      'file' => 'datereminder_form.inc',
      'file path' => $path,
    );
  }
  else {
    $items['node/%node/datereminder'] = array(
      'type' => MENU_LOCAL_TASK,
      'title' => 'All Reminders',
      'description' => 'All reminders for this event',
      'access callback' => 'datereminder_allowed_access_node',
      'access arguments' => array(
        1,
        'all',
        'inline',
      ),
      'page callback' => 'drupal_get_form',
      'page arguments' => array(
        'datereminder_form_summary',
        1,
        'all_node',
        'm',
      ),
      'file' => 'datereminder_form.inc',
      'file path' => $path,
    );
  }
  return $items;
}

/**
 * Implements hook_nodeapi().
 *
 * @param node &$node
 *   The node in question
 * @param string $op
 *   What are we doing to the node?
 * @param boolean $teaser
 *   Set if we're working with teaser.
 * @param boolean $page
 *   Set if we're working with page.
 */
function datereminder_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
  module_load_include('inc', 'datereminder', 'includes/defines');
  $ret = array();

  // Are reminders enabled for this node type?
  $enabled = _datereminder_type_enabled($node->type);
  switch ($op) {
    case 'delete':

      // Clean up anything for this node, even if we don't think the node type
      // or node has any reminders.
      _datereminder_clean_node_reminders($node->nid);
      break;
    case 'load':

      // Return array of items to add to node.
      if ($enabled >= DATEREMINDER_TYPE_ALLOWED) {
        $dflt = $enabled == DATEREMINDER_TYPE_ON ? DATEREMINDER_TYPE_ON : DATEREMINDER_TYPE_DISABLED;
        $enabled = _datereminder_get_node_enabled($node->nid, $dflt);
        $ret = array(
          'datereminder_enabled' => $enabled,
        );
        $node->datereminder_enabled = $enabled;

        // We'll defer loading the actual reminders until we need them.
      }
      return $ret;
    case 'view':
      if ($page && $enabled >= DATEREMINDER_TYPE_ALLOWED && !variable_get('datereminder_as_tab', FALSE)) {
        $content = _datereminder_node_output($node, 'node');
        $node->content['reminder'] = array(
          '#value' => $content,
          '#weight' => 50,
        );
      }
      break;
    case 'insert':

      // Node was just inserted into the database.
      if ($enabled >= DATEREMINDER_TYPE_ALLOWED) {
        $enabled = $node->datereminder_enabled;
        _datereminder_set_node_enabled($node, $enabled);
      }
      break;
    case 'update':

      // Node has been edited. Writing back now.
      if ($enabled >= DATEREMINDER_TYPE_ALLOWED) {
        _datereminder_update_node_reminders($node);
      }
      break;
  }
}

/**
 * Update all reminders for a node if the node is updated.
 *
 * @param node $node
 *   Node that's being written back.
 */
function _datereminder_update_node_reminders($node) {
  $rems = _datereminder_load_reminders(array(
    'nid' => $node->nid,
  ), $node);
  _datereminder_update_reminder_nexts($rems);
}

/**
 * Recompute "next" time and write back a group of reminders.
 *
 * This might be reminders associated with a node when the node changes,
 * or a set of reminders whose time has expired and we need to move on
 * to the next occurance.
 *
 * Note that reminders that are past last occurance of this node
 * will be deleted.
 *
 * @param array $rems
 *   list of reminders
 */
function _datereminder_update_reminder_nexts($rems) {
  module_load_include('inc', 'datereminder', 'includes/date');
  foreach ($rems as $r) {
    _datereminder_complete_reminder($r);
    _datereminder_get_next_reminder($r);
  }
  _datereminder_set_reminders($rems);
}

/**
 * Clean up any references to a given node or nodes.
 */
function _datereminder_clean_node_reminders($nids) {
  if (!is_array($nids)) {
    $nids = array(
      $nids,
    );
  }
  $ph = db_placeholders($nids);
  db_query('DELETE FROM {datereminder} WHERE nid IN (' . $ph . ')', $nids);
  db_query('DELETE FROM {datereminder_enable} WHERE nid IN (' . $ph . ')', $nids);
}

/**
 * Clean out reminders for everything associated with this type.
 */
function _datereminder_clean_type_reminders($type) {
  if (_datereminder_type_enabled($type) != DATEREMINDER_TYPE_DISABLED) {

    // There must be a way to do this using a join, but I can't figure it out.
    $q = db_query('SELECT nid from {node} WHERE type = \'%s\'', $type);
    $nids = array();
    while ($anode = db_fetch_object($q)) {
      $nids[] = $anode->nid;
    }
    if (count($nids) > 0) {
      _datereminder_clean_node_reminders($nids);
    }
  }
}

/**
 * Implements hook_user().
 *
 * Remove any reminders for given users(s)
 */
function datereminder_user($op, &$edit, &$account, $category = NULL) {
  switch ($op) {
    case 'delete':
      if (is_array($edit['accounts'])) {

        // A multi-user delete from Admin > User management > Users.
        $uids = $edit['accounts'];
      }
      else {

        // A single-user delete from the edit tab on the user's profile.
        $uids = array(
          $edit['_account']->uid,
        );
      }
      $ph = db_placeholders($uids);
      db_query('DELETE FROM {datereminder} WHERE uid IN (' . $ph . ')', $uids);
      break;
  }
}

/**
 * Implements hook_node_type().
 *
 * Need to delete anything associated with any nodes of this type.
 */
function datereminder_node_type($op, $info) {
  module_load_include('inc', 'datereminder', 'includes/defines');
  switch ($op) {
    case 'delete':

      // Clean up for node type $info->type
      _datereminder_clean_type_reminders($info->type);
      break;
    case 'update':
      $en = _datereminder_type_enabled($info->type);
      if ($en == DATEREMINDER_TYPE_DISABLED) {

        // If reminders are disabled for this node type,
        // clean out old reminders.
        _datereminder_clean_type_reminders($info->type);
      }
  }
}

/**
 * Add option to node form allowing user to request a reminder.
 */
function _datereminder_node_output(&$node, $type = 'node') {
  module_load_include('inc', 'datereminder', 'includes/defines');
  global $user;
  $output = '';
  if ($node->datereminder_enabled < DATEREMINDER_TYPE_ALLOWED) {
    return $output;
  }
  if (datereminder_allowed_access_node($node, 'own', 'inline')) {
    $output = '<a name="reminder"></a>';
    $output .= _datereminder_current_user_reminder($node, $type);
  }
  return $output;
}

/**
 * Get table of the given node's reminders.
 */
function _datereminder_current_user_reminder($node, $type = 'node') {
  global $user;
  $output = '';
  $fieldset = $type == 'node' ? 'f' : 'm';
  module_load_include('inc', 'datereminder', 'includes/datereminder_form');
  $output .= drupal_get_form('datereminder_form', $node, $fieldset);
  return $output;
}

/**
 * Implements hook_form_alter().
 *
 * Add section to node type edit form to enable reminders.
 */
function datereminder_form_alter(&$form, &$form_state, $form_id) {
  switch ($form_id) {
    case 'node_type_form':
      module_load_include('inc', 'datereminder', 'includes/node_form');
      datereminder_alter_node_type_form($form, $form_state, $form['#node_type']->type);
      break;
    default:
      if (!empty($form['type']['#value'])) {
        if ($form_id == $form['type']['#value'] . '_node_form') {
          module_load_include('inc', 'datereminder', 'includes/node_form');
          datereminder_alter_node_form($form, $form_state, $form_id);
        }
      }
      break;
  }
}

/**
 * Make sure that the user doesn't try to set node enabled to silly value.
 *
 * Note: This is only invoked if reminders are allowed for this node type.
 *
 * @param type $form
 * @param type $form_state
 */
function _datereminder_form_validate_node(&$form, &$form_state) {
  module_load_include('inc', 'datereminder', 'includes/defines');

  // what is user setting it to?
  $en = $form_state['values']['datereminder_enabled'];
  if ($en != DATEREMINDER_TYPE_DISABLED && $en != DATEREMINDER_TYPE_ON && $en != DATEREMINDER_TYPE_RETAIN) {
    form_set_error('datereminder_enabled', t("That's not a legal reminder setting"), 'error');
  }
}

/**
 * Handle form submit when admin enables or disables reminder for a node.
 *
 * Note: We don't need to check user access here. We'll only come here
 * if datereminder_alter_node_form() said we should. And it will only do
 * that if it's OK for the user to enable or disable reminders on this node.
 * Note that if reminders are enabled for this node type, anyone who can
 * modify a node of that type can enable or disable reminders.
 *
 * @param array &$form
 *   The submitted form
 * @param array &$form_state
 *   State of submitted form.
 */
function _datereminder_form_submit_node(&$form, &$form_state) {
  _datereminder_set_node_enabled($form['#node'], $form_state['values']['datereminder_enabled']);
}

/**
 * Get enablement for a content type.
 *
 * @param string $type
 *   The content type
 *
 * @return int
 *   Enum telling default value for reminders for this type.
 */
function _datereminder_type_enabled($type) {
  module_load_include('inc', 'datereminder', 'includes/defines');
  $enabled = variable_get("datereminder_enabled_{$type}", DATEREMINDER_TYPE_DISABLED);
  return $enabled;
}

/**
 * Set enabled for all nodes of the given type.
 *
 * @param type $type
 *   Node type.
 */
function _datereminder_enable_all_nodes($type) {
  $s = 'SELECT nid, r.enabled FROM {node} n LEFT JOIN {datereminder_enable} r ';
  $s .= 'USING(nid) WHERE n.type = \'%s\' AND r.enabled != %d';
  $rs = db_rewrite_sql($s);
  $q = db_query($rs, array(
    $type,
    DATEREMINDER_TYPE_ON,
  ));
  while ($rec = db_fetch_object($q)) {
    if (!isset($rec->enabled) || $rec->enabled != DATEREMINDER_TYPE_ON) {
      _datereminder_set_nid_enabled($rec->nid, DATEREMINDER_TYPE_ON);
    }
  }
}

/**
 * Tell if reminders are enabled for this node.
 *
 * @todo Should default (if not in the table) come from node type?
 */
function _datereminder_get_node_enabled($nid, $default) {
  module_load_include('inc', 'datereminder', 'includes/defines');
  $q = db_query('SELECT (enabled) FROM {datereminder_enable} WHERE nid = %d', $nid);
  $e = db_fetch_object($q);
  if (empty($e)) {
    return $default;
  }
  return $e->enabled;
}

/**
 * Enable/disable reminders for a node.
 *
 * @param node $node
 *   The node
 * @param boolean $enabled
 *   Value to set enable flag to for this node.
 */
function _datereminder_set_node_enabled($node, $enabled) {
  module_load_include('inc', 'datereminder', 'includes/defines');
  $nid = $node->nid;
  _datereminder_set_nid_enabled($nid, $enabled);
}
function _datereminder_set_nid_enabled($nid, $enabled) {
  if (empty($enabled)) {
    $enabled = DATEREMINDER_TYPE_DISABLED;
  }
  if ($enabled == DATEREMINDER_TYPE_DISABLED) {
    _datereminder_clean_node_reminders($nid);
  }
  $q = 'INSERT INTO {datereminder_enable} (nid, enabled)';
  $q .= ' VALUE (%d,%d) ON DUPLICATE KEY UPDATE enabled = %d';
  db_query($q, $nid, $enabled, $enabled);
}

/**
 * Get existing reminder info for a node and current user.
 *
 * @todo Pull in collateral info at the same time, like node title
 * and user name.
 */
function _datereminder_get_node_user_reminders(&$node) {
  module_load_include('inc', 'datereminder', 'includes/defines');
  global $user;
  if ($user->uid == 0 || !user_access(DATEREMINDER_REQUEST_REMINDER)) {
    return NONE;
  }
  if (isset($node->reminders)) {
    $rem = $node->reminders;
  }
  else {
    $rem = _datereminder_load_reminders(array(
      'uid' => $user->uid,
      'nid' => $node->nid,
    ), $node, 'leadtime');
    $node->reminders = $rem;
  }
  return $rem;
}

/**
 * Load reminders filtering one one or more keys.
 *
 * @param array $selectors
 *   a key:value array specifying what to load from
 *   the reminders table. Anything in the reminder table is fair game, but
 *   generally the keys are 'nid', 'rid',  or 'uid'.
 * @param node $node
 *   Optional parameter. If set, $r->node is set for any loaded reminder
 *   with the right nid.
 * @param string sortkey
 *   If set, sort loaded reminders by this.
 *
 * @return array
 *   an array of reminder objects as selected from the database, keyed by rid.
 *   Each object also includes the node title and user name.
 *
 * @example: $reminders = _datereminder_load_reminders(array('uid' => $uid));
 */
function _datereminder_load_reminders($selectors, $node = NULL, $sortkey = NULL) {
  global $user;
  $s = 'SELECT r.*, title, name FROM {node} n INNER JOIN {datereminder} r ';
  $s .= 'USING(nid) INNER JOIN {users} u WHERE r.uid = u.uid';
  $vals = array();
  foreach ($selectors as $k => $v) {
    $s .= " AND r.{$k} = %d";
    $vals[] = $v;
  }
  if ($sortkey != NULL) {
    $s .= " ORDER by r.{$sortkey}";
  }
  $rs = db_rewrite_sql($s);
  $q = db_query($rs, $vals);
  $ret = array();
  while ($r = db_fetch_object($q)) {
    if (isset($node) && $node->nid == $r->nid) {
      $r->node = $node;
    }
    if ($r->uid == $user->uid) {
      $r->user = $user;
    }
    $ret[$r->rid] = $r;
  }
  return $ret;
}

/**
 * Write back user reminder information.
 */
function _datereminder_set_reminders(&$reminders) {
  foreach (array_keys($reminders) as $k) {
    $r = $reminders[$k];

    // first, are there any reminders to save?
    if ($r->leadtime == 0 || !isset($r->next)) {

      // No reminders, so delete any existing entry
      if ($r->rid > 0) {
        db_query('DELETE FROM {datereminder} WHERE rid = %d', $r->rid);
      }
      unset($reminders[$k]);
    }
    else {
      if ($r->rid > 0) {
        drupal_write_record('datereminder', $r, 'rid');
      }
      else {

        // This is a new entry
        $ok = drupal_write_record('datereminder', $r);
        if ($ok) {
          unset($reminders[$k]);
          $reminders[$r->rid] = $r;
        }
      }
    }
  }
}

/**
 * Callback on validate from datereminder_form.
 *
 * Did the user put reasonable values in the form?
 */
function _datereminder_form_validate_user($form, &$form_state) {
  module_load_include('inc', 'datereminder', 'includes/defines');
  global $user;
  $ok = TRUE;
  $v = $form_state['values'];
  $nid = $v['nid'];
  $node = node_load($nid);
  if (empty($node) || $user->uid == 0 || !user_access(DATEREMINDER_REQUEST_REMINDER)) {
    form_set_error(NULL, t('Permission error'), 'error');
    return FALSE;
  }

  // Any reason not to do this?
  $form_state['datereminder_node'] = $node;

  // Get existing reminders.
  $r = _datereminder_get_node_user_reminders($node);
  $other_email = user_access(DATEREMINDER_OTHER_EMAIL);
  $rows = $v['rids'];
  $added = 0;
  if (!isset($rows) or $rows == '') {
    form_set_error(NULL, t('Corrupted form'));
    return FALSE;
  }
  $rows = explode(',', $rows);
  if (count($rows) > variable_get('datereminder_max_reminders', DATEREMINDER_MAX_REMINDERS)) {
    form_set_error(NULL, t('Permission error'), 'error');
    return;
  }
  foreach ($rows as $rid) {
    if (substr($rid, 0, 1) != 'n') {
      if (!isset($r[$rid])) {
        form_set_error(NULL, t('Permission error'), 'error');
        return;
      }
    }
    if ($other_email) {
      $formid = "datereminder_email_{$rid}";
      $e = $v[$formid];
      if ($e) {
        $outemails = array();
        foreach (explode(',', $e) as $email) {
          $email = trim($email);
          if ($email) {
            if (valid_email_address($email)) {
              $outemails[] = $email;
            }
            else {
              form_set_error($formid, t("'@email' is a bad address", array(
                '@email' => $email,
              )));
              $ok = FALSE;
              break;
            }
          }
        }
        if ($ok) {
          $form_state['values'][$formid] = implode(',', $outemails);
        }
      }
    }
  }
  return $ok;
}

/**
 * Callback on submit from datereminder_form.
 *
 * @todo The "send-now" operation sends email using the last reminder
 * found in the list, which may not correspond to anything useful. For
 * normal users, this isn't an issue. If the user can send emails, though,
 * the reminder used determines the target email address.  Probably should
 * let priviledged user select which email to send to.
 */
function _datereminder_form_submit_user($form, &$form_state) {
  global $user;
  $v = $form_state['values'];
  $nid = $v['nid'];
  $node = $form_state['datereminder_node'];
  $rems = _datereminder_get_node_user_reminders($node);
  $rows = explode(',', $v['rids']);
  module_load_include('inc', 'datereminder', 'includes/date');
  $df = _datereminder_get_node_datefield($node);
  $other_email = user_access(DATEREMINDER_OTHER_EMAIL);
  $changedrems = array();
  foreach ($rows as $rtag) {
    $changed = FALSE;
    $newtime = FALSE;
    if (substr($rtag, 0, 1) == 'n') {

      // This is a new reminder.
      unset($r);
      $r->leadtime = $v["datereminder_lead_{$rtag}"];
      if ($r->leadtime > 0) {
        $rid = -substr($rtag, 1);
        $r->nid = $node->nid;
        $r->node = $node;
        $r->uid = $user->uid;
        $r->user = $user;
        $r->next = 0;
        $r->rid = $rid;
        if ($other_email) {
          $r->email = $v["datereminder_email_{$rtag}"];
        }
        else {
          $r->email = '';
        }
        $newtime = TRUE;
      }
    }
    else {

      // This is an existing reminder.
      $rid = $rtag;
      $r = $rems[$rid];
      $ltn = $v["datereminder_lead_{$rtag}"];
      if ($ltn != $r->leadtime) {
        $r->leadtime = $ltn;
        $newtime = TRUE;
      }
      if ($other_email) {
        $em = $v["datereminder_email_{$rtag}"];
        if ($em != $r->email) {
          $r->email = $em;
          $changed = TRUE;
        }
      }
    }
    if ($newtime) {
      _datereminder_get_next_reminder($r, $df);
      if (!isset($r->next)) {
        drupal_set_message(t("Sorry, but it's too late to send that reminder"), 'error');
        return;
      }
      $changed = TRUE;
    }
    if ($changed) {
      $changedrems[$rid] = $r;
    }
  }
  if (count($changedrems) > 0) {
    _datereminder_set_reminders($changedrems);
    unset($node->reminders);
  }
  if ($v['send-now']) {
    module_load_include('inc', 'datereminder', 'includes/messaging');
    $r = NULL;
    $r->uid = $user->uid;
    $r->nid = $node->nid;
    $r->node = $node;
    $r->user = $user;
    $r->leadtime = 0;
    $r->next = NULL;
    if (_datereminder_send_reminder($r)) {
      drupal_set_message(t('An email reminder has been sent'));
    }
    else {
      drupal_set_message(t('Sorry, there was a problem sending mail'), 'error');
    }
  }
}

/**
 * Callback to delete a group of reminders from admin menu form.
 */
function _datereminder_admin_delete_set($form, &$form_state) {
  $v = $form_state['values'];
  $reminders = $v['reminders'];
  $dset = array();
  foreach ($reminders as $rem) {
    if ($rem > 0) {
      $dset[] = $rem;
    }
  }
  if (count($dset) > 0) {
    db_query('DELETE FROM {datereminder} WHERE rid IN (' . db_placeholders($dset) . ')', $dset);
  }
}

/**
 * Implements hook_perm().
 */
function datereminder_perm() {
  module_load_include('inc', 'datereminder', 'includes/defines');
  return array(
    DATEREMINDER_ADMINISTER_REMINDERS,
    DATEREMINDER_VIEW_OTHER_USER_REMINDERS,
    DATEREMINDER_OTHER_EMAIL,
    DATEREMINDER_REQUEST_REMINDER,
  );
}

/**
 * Implements hook_messaging().
 */
function datereminder_messaging($op, $type = NULL, $arg2 = NULL) {
  module_load_include('inc', 'datereminder', 'includes/messaging');
  return _datereminder_messaging($op, $type, $arg2);
}

/**
 * Utility function to load node and user objects for a reminder when needed.
 *
 * @param reminder  $r
 *   Reminder to be completed
 */
function _datereminder_complete_reminder(&$r) {
  if (!isset($r->node)) {
    $r->node = node_load($r->nid);
  }
  if (!isset($r->user)) {
    $r->user = user_load(array(
      'uid' => $r->uid,
    ));
  }
}

/**
 * Implements hook_token().
 *
 * @param string $type
 *   Type of tokens being requested
 * @param string $object
 *   Associated object
 * @param array $options
 *   Not used here
 */
function datereminder_token_values($type, $object = NULL, $options = array()) {
  $values = array();
  if ($type == 'datereminder') {
    $r = $object;
    if ($r) {
      module_load_include('inc', 'datereminder', 'includes/date');
      $datefield = _datereminder_get_datefield($r);
      $tz = $r->user->timezone_name;
      if (!isset($tz)) {
        $tz = date_default_timezone_name(FALSE);
      }
      $next = $r->next;

      // We want then next-date tokens to show next occurrance after
      // the time this reminder will be sent. But if the reminder isn't
      // currently scheduled, use 'now'.
      if (isset($next)) {
        $next = _datereminder_internal_date_to_datetime($next);
      }
      else {
        $next = _datereminder_now();
      }
      $nd = _datereminder_get_occurance_after_date($datefield, $next);
      if (isset($nd)) {
        $nextdate = _datereminder_date_format_internal($nd);
        $dobj = date_create($nextdate, timezone_open('UTC'));
        date_timezone_set($dobj, timezone_open($tz));
        $values['next-date-short'] = date_format_date($dobj, 'short');
        $values['next-date-medium'] = date_format_date($dobj, 'medium');
        $values['next-date-long'] = date_format_date($dobj, 'long');
      }
      else {
        $values['next-date-short'] = t('Past');
        $values['next-date-medium'] = t('Past');
        $values['next-date-long'] = t('Past');
      }
    }
  }
  return $values;
}

/**
 * Implements hook_token_list().
 */
function datereminder_token_list($type = 'all') {
  $tokens = array();
  if ($type == 'datereminder' || $type == 'all') {
    $tokens['datereminder']['next-date-short'] = t('The date of the next occurrance of this event, short form');
    $tokens['datereminder']['next-date-medium'] = t('The date and time of the next occurance. medium form');
    $tokens['datereminder']['next-date-long'] = t('The date and time of the next occurance. long form');
  }
  return $tokens;
}

/**
 * Implements hook_cron().
 *
 * Check to see if we need to send any reminders.
 */
function datereminder_cron() {
  module_load_include('inc', 'datereminder', 'includes/cron');
  _datereminder_cron();
}

/**
 * Check if this user can access reminders at all.
 *
 * @global type $user
 *
 * @param user $acct
 *   A user struct, maybe not the current one
 *
 * @return boolean
 *   TRUE if requested access is allowed
 */
function datereminder_access_user($acct) {
  module_load_include('inc', 'datereminder', 'includes/defines');
  global $user;
  if ($acct && $acct->uid && $user->uid == $acct->uid) {
    return user_access(DATEREMINDER_REQUEST_REMINDER);
  }
  return FALSE;
}

/**
 * Check if this user can access reminders for this node.
 *
 * @param node $node
 *   The node
 * @param string $acc
 *   What kind of access is requested?
 *   'own' means set/view own reminder
 *   'all' means view others' reminders
 */
function datereminder_allowed_access_node($node = NULL, $acc = 'own', $loc = 'inline') {
  global $user;
  if ($user->uid == 0) {

    // Anonymous users never have access to reminders. Sorry.
    return FALSE;
  }
  module_load_include('inc', 'datereminder', 'includes/defines');

  // First, be sure reminders are on for this.
  if (!isset($node) || $node->datereminder_enabled != DATEREMINDER_TYPE_ON) {
    return FALSE;
  }
  $astab = variable_get('datereminder_as_tab', FALSE);
  if ($loc == 'inline') {
    if ($astab) {
      return FALSE;
    }
  }
  else {
    if (!$astab) {
      return FALSE;
    }
  }
  if (user_access(DATEREMINDER_VIEW_OTHER_USER_REMINDERS) || user_access(DATEREMINDER_ADMINISTER_REMINDERS)) {
    return TRUE;
  }
  if ($acc == 'own' && user_access(DATEREMINDER_REQUEST_REMINDER)) {
    module_load_include('inc', 'datereminder', 'includes/datereminder_form');
    return _datereminder_has_future_dates($node);
  }
  else {
    return FALSE;
  }
}

/**
 * Check if this user see another specific user's reminders.
 *
 * @param user $u
 *   The user struct. NULL means all users.
 */
function datereminder_allowed_access_user($u = NULL) {
  module_load_include('inc', 'datereminder', 'includes/defines');
  global $user;
  if ($user->uid == 0) {

    // Reminders explicitly not supported for anonymous users.
    return FALSE;
  }
  if (user_access(DATEREMINDER_ADMINISTER_REMINDERS) || user_access(DATEREMINDER_VIEW_OTHER_USER_REMINDERS)) {
    return TRUE;
  }
  if (!user_access(DATEREMINDER_REQUEST_REMINDER)) {
    return FALSE;
  }
  return isset($u) && $u->uid == $user->uid;
}

/**
 * Implements hook_theme().
 */
function datereminder_theme() {
  return array(
    'datereminder_manage_reminders' => array(
      'arguments' => array(
        'form' => NULL,
      ),
      'file' => 'datereminder.form.inc',
      'file path' => drupal_get_path('module', 'datereminder') . '/includes',
    ),
    'datereminder_table' => array(
      'arguments' => array(
        'form' => NULL,
      ),
      'file' => 'datereminder.form.inc',
      'file path' => drupal_get_path('module', 'datereminder') . '/includes',
    ),
  );
}

/**
 * Validate node type form submission.
 * (1) Don't allow "all_on" to be set if reminders are disabled.
 * (2) Move the "all_on" value out of $form_state['values'] so that
 *     core's node form handler doesn't create a variable. We'll handle
 *     it in our own submit function.
 * @param type $form
 * @param type $form_state 
 */
function _datereminder_form_validate_node_type(&$form, &$form_state) {
  $allon = $form_state['values']['datereminder_all_on'];
  if (isset($allon)) {
    $enabled = $form_state['values']['datereminder_enabled'];
    if ($allon && $enabled <= DATEREMINDER_TYPE_RETAIN) {
      form_set_error('datereminder_all_on', t('Don\'t ask to enable for all if reminders aren\'t enabled'));
      return;
    }
    $form_state['customvalues']['datereminder_all_on'] = $allon;
    unset($form_state['values']['datereminder_all_on']);
  }
}

/**
 * Processing on a node type submit. This does the enable of reminders
 * in existing nodes, if requested.
 * 
 * @param type $form
 * @param type $form_state 
 */
function _datereminder_form_submit_node_type(&$form, &$form_state) {
  $allon = $form_state['customvalues']['datereminder_all_on'];
  if ($allon) {
    $type = $form_state['values']['type'];
    _datereminder_enable_all_nodes($type);
  }
}

Functions

Namesort descending Description
datereminder_access_user Check if this user can access reminders at all.
datereminder_allowed_access_node Check if this user can access reminders for this node.
datereminder_allowed_access_user Check if this user see another specific user's reminders.
datereminder_cron Implements hook_cron().
datereminder_form_alter Implements hook_form_alter().
datereminder_menu Implements of hook_menu().
datereminder_messaging Implements hook_messaging().
datereminder_nodeapi Implements hook_nodeapi().
datereminder_node_type Implements hook_node_type().
datereminder_perm Implements hook_perm().
datereminder_theme Implements hook_theme().
datereminder_token_list Implements hook_token_list().
datereminder_token_values Implements hook_token().
datereminder_user Implements hook_user().
_datereminder_admin_delete_set Callback to delete a group of reminders from admin menu form.
_datereminder_clean_node_reminders Clean up any references to a given node or nodes.
_datereminder_clean_type_reminders Clean out reminders for everything associated with this type.
_datereminder_complete_reminder Utility function to load node and user objects for a reminder when needed.
_datereminder_current_user_reminder Get table of the given node's reminders.
_datereminder_enable_all_nodes Set enabled for all nodes of the given type.
_datereminder_form_submit_node Handle form submit when admin enables or disables reminder for a node.
_datereminder_form_submit_node_type Processing on a node type submit. This does the enable of reminders in existing nodes, if requested.
_datereminder_form_submit_user Callback on submit from datereminder_form.
_datereminder_form_validate_node Make sure that the user doesn't try to set node enabled to silly value.
_datereminder_form_validate_node_type Validate node type form submission. (1) Don't allow "all_on" to be set if reminders are disabled. (2) Move the "all_on" value out of $form_state['values'] so that core's node form handler doesn't create a…
_datereminder_form_validate_user Callback on validate from datereminder_form.
_datereminder_get_node_enabled Tell if reminders are enabled for this node.
_datereminder_get_node_user_reminders Get existing reminder info for a node and current user.
_datereminder_load_reminders Load reminders filtering one one or more keys.
_datereminder_node_output Add option to node form allowing user to request a reminder.
_datereminder_set_nid_enabled
_datereminder_set_node_enabled Enable/disable reminders for a node.
_datereminder_set_reminders Write back user reminder information.
_datereminder_type_enabled Get enablement for a content type.
_datereminder_update_node_reminders Update all reminders for a node if the node is updated.
_datereminder_update_reminder_nexts Recompute "next" time and write back a group of reminders.