' . t('Node Invite provides a means to invite people to nodes. Customized email message is token enabled.') . '
';
$output .= '' . t('Here are tokens you can use:') . '
';
$output .= theme('token_help', 'node');
break;
case 'admin/settings/node_invite':
$output .= '' . t('Node invite allows you to invite people to nodes. The email they receive is token-enabled.') . '
';
break;
}
return $output;
}
/**
* Implementation of hook_perm().
*/
function node_invite_perm() {
return array(
'invite users to invite-enabled nodes',
'admin node invite settings',
'respond to invites',
'manage all invites',
'manage own invites',
'view invitee lists',
);
}
/**
* Implementation of hook_theme().
*/
function node_invite_theme() {
return array(
'node_invite_view_field_invitees' => array(
'arguments' => array('nid' => NULL, 'invites' => array()),
),
'node_invite_list_invites' => array(
'arguments' => array('sql' => NULL, 'values' => NULL, 'fields' => NULL, 'limit' => NULL),
),
'node_invite_list_invites_empty' => array(
'arguments' => array(),
),
'node_invite_view' => array(
'arguments' => array('node_invite' => NULL),
),
);
}
/**
* Implementation hook_views_api
*/
function node_invite_views_api() {
return array(
'api' => 2,
);
}
/**
* Implementation of hook_menu().
*/
function node_invite_menu() {
$items = array();
$items['admin/settings/node_invite'] = array(
'title' => 'Node invite',
'description' => 'Node Invite module is similar to RSVP. Invite people to nodes, manage your invites, etc.',
'page callback' => 'drupal_get_form',
'page arguments' => array('node_invite_admin_settings_form'),
'access arguments' => array('admin node invite settings'),
'file' => 'node_invite.admin.inc',
);
$items['admin/settings/node_invite/settings'] = array(
'title' => 'Settings',
'weight' => 0,
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['admin/settings/node_invite/notifications'] = array(
'title' => 'Notifications',
'page callback' => 'drupal_get_form',
'page arguments' => array('node_invite_notifications_form'),
'access arguments' => array('admin node invite settings'),
'file' => 'node_invite.admin.inc',
'weight' => 1,
'type' => MENU_LOCAL_TASK,
);
$items['admin/settings/node_invite/manage'] = array(
'title' => 'Manage invites',
'page callback' => 'node_invite_manage_page',
'access arguments' => array('manage all invites'),
'type' => MENU_LOCAL_TASK,
'file' => 'node_invite.admin.inc',
'weight' => 2,
);
if (variable_get('node_invite_display', 'link') == 'tab') {
$items['node/%node/invite'] = array(
'title' => 'Invite people',
'page callback' => 'drupal_get_form',
'page arguments' => array('node_invite_send', 1),
'access callback' => 'node_invite_invites_access',
'access arguments' => array(1, 'tab'),
'file' => 'node_invite.send.inc',
'weight' => 2,
'type' => MENU_LOCAL_TASK,
);
}
else {
$items['node_invite/invite/%node'] = array(
'title' => 'Invite',
'page callback' => 'drupal_get_form',
'page arguments' => array('node_invite_send', 2),
'access callback' => 'node_invite_invites_access',
'access arguments' => array(2, 'link'),
'file' => 'node_invite.send.inc',
'type' => MENU_CALLBACK,
);
}
$items['node_invite/find_invite/%node'] = array(
'title' => 'Find invite',
'page callback' => 'node_invite_find_invite',
'page arguments' => array(2),
'access callback' => 'node_invite_rsvp_access',
'access arguments' => array(2),
'file' => 'node_invite.rsvp.inc',
'type' => MENU_CALLBACK,
);
$items['node_invite/clear_rsvp_session/%node'] = array(
'title' => 'Clear RSVP session',
'page callback' => 'node_invite_clear_rsvp_session',
'page arguments' => array(2),
'access callback' => TRUE,
'file' => 'node_invite.rsvp.inc',
'type' => MENU_CALLBACK,
);
$items['node_invite/rsvp/%node/%node_invite'] = array(
'title arguments' => array(2, 3),
'title callback' => 'node_invite_rsvp_title',
'page callback' => 'drupal_get_form',
'page arguments' => array('node_invite_rsvp', 2, 3),
'access arguments' => array('respond to invites'),
'file' => 'node_invite.rsvp.inc',
'type' => MENU_CALLBACK,
);
$items['node_invite/rsvp_new/%node'] = array(
'title' => 'Your RSVP',
'page callback' => 'drupal_get_form',
'page arguments' => array('node_invite_rsvp_new', 2),
'access callback' => 'node_invite_rsvp_access',
'access arguments' => array(2),
'file' => 'node_invite.rsvp.inc',
'type' => MENU_CALLBACK,
);
$items['node_invite/revoke/%node_invite'] = array(
'title' => 'Revoke invite',
'page callback' => 'drupal_get_form',
'page arguments' => array('node_invite_revoke', 2),
'access callback' => 'node_invite_can_manage_invite',
'access arguments' => array(2),
'file' => 'node_invite.admin.inc',
'type' => MENU_CALLBACK,
);
$items['node_invite/resend/%node_invite'] = array(
'title' => 'Resend invite',
'page callback' => 'drupal_get_form',
'page arguments' => array('node_invite_resend', 2),
'access callback' => 'node_invite_can_manage_invite',
'access arguments' => array(2),
'file' => 'node_invite.admin.inc',
'type' => MENU_CALLBACK,
);
$items['node_invite/reinstate/%node_invite'] = array(
'title' => 'Reinstate invitation',
'page callback' => 'node_invite_reinstate',
'page arguments' => array(2),
'file' => 'node_invite.admin.inc',
'access callback' => 'node_invite_can_manage_invite',
'access arguments' => array(2),
'type' => MENU_CALLBACK,
);
$items['node_invite/view/%node_invite'] = array(
'title' => 'View invitation',
'page callback' => 'theme',
'page arguments' => array('node_invite_view', 2),
'file' => 'node_invite.admin.inc',
'access callback' => 'node_invite_can_manage_invite',
'access arguments' => array(2),
'type' => MENU_CALLBACK,
);
$items['user/%user/invites'] = array(
'title' => 'My invites',
'page callback' => 'node_invite_list_invites_callback',
'page arguments' => array(1),
'access arguments' => array('manage own invites'),
'weight' => 2,
'type' => MENU_LOCAL_TASK,
);
$items['node/%node/manage_invites'] = array(
'title' => 'Manage invites',
'page callback' => 'node_invite_list_invites_callback',
'page arguments' => array(NULL, 1),
'access callback' => 'node_invite_manage_invites_access',
'access arguments' => array(1),
'weight' => 3,
'type' => MENU_LOCAL_TASK,
);
$items['node_invite/user_autocomplete'] = array(
'title' => 'User autocomplete',
'page callback' => '_node_invite_user_autocomplete',
'access arguments' => array('access user profiles'),
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* The title callback for the rsvp page
*/
function node_invite_rsvp_title($node, $invite) {
node_invite_specific_info($invite, $node);
$page_title = variable_get('node_invite_rsvp_page_title', NODE_INVITE_RSVP_PAGE_TITLE);
// There appears to be an issue when the [title] token is used that it can't
// be properly replaced with token_replace in the title menu callback.
$page_title = str_replace('[title]', $node->title, $page_title);
$page_title = token_replace($page_title, 'node', $node);
return t($page_title);
}
/**
* Menu access callback for determining if the current user can manage
* the given invite.
*/
function node_invite_can_manage_invite($invite) {
global $user;
if (user_access('manage all invites') ||
($invite->uid_inviter == $user->uid && user_access('manage own invites'))) {
return TRUE;
}
return FALSE;
}
/**
* Menu access callback for the manage invites tab.
*/
function node_invite_manage_invites_access($node) {
if (user_access('manage own invites') && _ni_node_is_enabled($node)) {
return TRUE;
}
return FALSE;
}
/**
* Menu access callback for the manage invites tab.
*/
function node_invite_invites_access($node, $type = NULL) {
if (user_access('invite users to invite-enabled nodes') && _node_invite_type_is_allowed($node->type) && _ni_node_is_enabled($node)) {
if (!isset($type) || ($type == variable_get('node_invite_display', 'link'))) {
return TRUE;
}
}
return FALSE;
}
/**
* Menu access callback for the rsvp link on invite node.
*/
function node_invite_rsvp_access($node) {
global $user;
if (user_access('respond to invites') && _node_invite_type_is_allowed($node->type) && _ni_node_is_enabled($node)) {
if ($node->node_invite_settings['open']) {
return TRUE;
}
else {
// Try and find an invite for this user. Note that people who were
// invited by email only will not be able to see this link.
$invites = node_invite_user_invites($user->uid);
foreach ($invites as $invite) {
if ($invite->nid == $node->nid) {
return TRUE;
}
}
}
}
return FALSE;
}
/**
* Load an invite.
*/
function node_invite_load($invite_id, $reset = NULL) {
static $invite_cache = array();
if ($reset) {
$invite_cache = array();
}
if (!isset($invite_cache[$invite_id])) {
// The id can be either a hash or an iid... figure it out
if (is_numeric($invite_id)) {
$where = "ni.iid = %d";
}
else {
$where = "ni.hash = '%s'";
}
$invite = db_fetch_object(db_query("SELECT ni.*, u.mail, u.name FROM {node_invites} AS ni JOIN {users} AS u ON ni.uid_inviter = u.uid WHERE $where", $invite_id));
// Load the settings for this invite
$invite->settings = db_fetch_array(db_query("SELECT * FROM {node_invite_settings} WHERE nid = %d", $invite->nid));
$invite_cache[$invite_id] = $invite;
}
return $invite_cache[$invite_id];
}
/**
* Implementation of hook_link().
*/
function node_invite_link($type, $node = NULL, $teaser = FALSE) {
global $user;
$links = array();
if ($type == 'node' && _node_invite_type_is_allowed($node->type) && _ni_node_is_enabled($node)) {
if (user_access('invite users to invite-enabled nodes') && variable_get('node_invite_display', 'link') == 'link') {
$links['node_invite'] = array(
'title' => t('Invite people to this @type', array('@type' => $node->type)),
'href' => "node_invite/invite/$node->nid",
);
}
if ($node->node_invite_settings['open'] && variable_get('node_invite_rsvp_display', 'link') == 'link') {
$links['node_invite_rsvp'] = array(
'title' => t('RSVP to this @type', array('@type' => $node->type)),
'href' => "node_invite/find_invite/$node->nid",
);
}
}
return $links;
}
/**
* Implementation of hook_user().
*
* Update invite email addresses if the user changes their own email address.
*/
function node_invite_user($op, &$edit, &$account, $category = NULL) {
if ($op == 'update') {
if (variable_get('node_invite_sync_users', 0) && $edit['mail'] != $account->mail) {
db_query("UPDATE {node_invites} SET email_invitee = '%s' WHERE uid_invitee = %d", $edit['mail'], $account->uid);
}
}
}
/**
* Implementation of hook_mail().
*/
function node_invite_mail($key, &$message, $params) {
$message['headers']['Content-Type'] = 'text/html; charset=UTF-8; format=flowed';
$message['subject'] = $params['subject'];
$message['body'] = $params['body'];
// Replace from address if a replacement is set.
if ($params['from'] != $message['from']) {
$message['headers']['Reply-To'] = $message['from'];
$message['headers']['From'] = $params['from'];
$message['from'] = $params['from'];
}
}
/**
* Implementation of hook_token_list().
*/
function node_invite_token_list($type = 'all') {
$tokens = array();
if (in_array($type, array('all', 'node_invite', 'node'))) {
$tokens['node invite']['inviter-name'] = t('The username of the person currently logged in (and thus sending the invite). This will not work as a page-title token since the person rendering the page title will be logged in as someone different (or anonymous).');
$tokens['node invite']['inviter-mail'] = t('The email address of the person currently logged in (and thus sending the invite). This will not work as a page-title token since the person rendering the page title will be logged in as someone different (or anonymous).');
$tokens['node invite']['inviter-rsvp-url'] = t('This is the URL of the RSVP form. Send users here to confirm or deny attendance.');
$tokens['node invite']['inviter-node-url'] = t('This is the URL of the node to which they are being invited. Send them here "for more details."');
$tokens['node invite']['node-invite-recip-mail'] = t('The email of the person receiving the invite');
$tokens['node invite']['node-invite-recip-name'] = t('The name of the person receiving the invite');
$tokens['node invite']['node-invite-iid'] = t('The invite_id (unique identifier) of the invite being sent');
$tokens['node invite']['node-invite-personal-message'] = t('The personal message added to the invite being sent');
}
return $tokens;
}
/**
* Implementation of hook_token_values().
*/
function node_invite_token_values($type, $object = NULL) {
$values = array();
if (in_array($type, array('all', 'node invite', 'node'))) {
global $user;
$values['inviter-name'] = $user->name;
$values['inviter-mail'] = $user->mail;
$values['inviter-rsvp-url'] = url('node_invite/invite/' . $object->nid, array('absolute' => TRUE));
$values['inviter-node-url'] = url('node/' . $object->nid, array('absolute' => TRUE));
// this is hacked in for each invite sent. Won't exist other times
if (isset($object->invite_specific_info)) {
$values['node-invite-iid'] = $object->invite_specific_info['node-invite-iid'];
$values['node-invite-recip-name'] = $object->invite_specific_info['node-invite-recip-name'];
$values['node-invite-recip-mail'] = $object->invite_specific_info['node-invite-recip-mail'];
$values['node-invite-personal-message'] = str_replace("\n", "
\n", $object->invite_specific_info['node-invite-personal-message']);
// the above are defaults... this comes in if alternatives are available
$values['inviter-name'] = $object->invite_specific_info['inviter-name'];
$values['inviter-mail'] = $object->invite_specific_info['inviter-mail'];
}
}
return $values;
}
/**
* Implementation of hook_content_extra_fields().
*/
function node_invite_content_extra_fields($type_name) {
$extra = array();
if (_node_invite_type_is_allowed($type_name)) {
$extra['node_invite_group'] = array(
'label' => t('Node invite settings'),
'description' => t('Node invite module form.'),
'weight' => 10,
);
}
return $extra;
}
/**
* Implementation of hook_block().
*/
function node_invite_block($op = 'list', $delta = 0, $edit = array()) {
// The blocks here can only be used on node invite enabled nodes and
// node_invite pages.
if ($op == 'list') {
$blocks = array();
$blocks[0] = array(
'info' => t('Node invite - invite list'),
);
$blocks[1] = array(
'info' => t('Node invite - attending'),
);
$blocks[2] = array(
'info' => t('Node invite - maybe attending'),
);
$blocks[3] = array(
'info' => t('Node invite - not attending'),
);
$blocks[4] = array(
'info' => t('Node invite - no response'),
);
return $blocks;
}
elseif ($op == 'view') {
// Figure out which node we're viewing.
$path = $_GET['q'];
$matches = array();
if (preg_match('/node\/([0-9]+)/', $path, $matches)) {
$nid = $matches[1];
}
elseif (preg_match('/node_invite\/[a-zA-Z]+\/([0-9]+)/', $path, $matches)) {
$nid = $matches[1];
}
else {
return;
}
// Ensure that the permissions are adequate to display a block on
// the specified node.
$node = node_load($nid);
if (!(_ni_node_is_enabled($node)
&& _node_invite_type_is_allowed($node->type)
&& user_access('view invitee lists'))) {
return;
}
switch ($delta) {
case 0:
$invites = node_invite_load_invites_by_nid($nid);
$subject = t('Invite List');
break;
case 1:
$invites = node_invite_load_invites_by_nid($nid, NODE_INVITE_RESPONSE_YES);
$subject = t('Attending');
break;
case 2:
$invites = node_invite_load_invites_by_nid($nid, NODE_INVITE_RESPONSE_MAYBE);
$subject = t('Maybe Attending');
break;
case 3:
$invites = node_invite_load_invites_by_nid($nid, NODE_INVITE_RESPONSE_NO);
$subject = t('Not Attending');
break;
case 4:
$invites = node_invite_load_invites_by_nid($nid, NODE_INVITE_NEW);
$subject = t('No Response');
break;
}
$block = array(
'subject' => $subject,
'content' => theme('node_invite_view_field_invitees', $nid, $invites),
);
return $block;
}
}
/**
* Menu callback for the user and node invite lists.
*/
function node_invite_list_invites_callback($account = NULL, $node = NULL) {
$filters = array();
$fields = NULL;
if (isset($account)) {
$filters['node_invites.uid_inviter'] = $account->uid;
}
if (isset($node)) {
$filters['node.nid'] = $node->nid;
$fields = array(
'email_invitee' => t('Sent to'),
'users.name' => t('Sent by'),
'node_invites.sent' => t('Invite Sent'),
'node_invites.status' => t('Status'),
'acted_upon' => t('Acted Upon'),
);
}
return node_invite_list_invites($filters, $fields);
}
/**
* Return a list of invites in a themed table
*
* @param $filters - An array of filters to apply to the query. For example:
* array('node_invites.uid_inviter' => 1, 'node.nid' => 13);
* The filters can be any of the fields in the node_invites table, the node
* table or the user table.
* @param $fields - An array of fields and column titles to display
* @return the themed table of invites
*/
function node_invite_list_invites($filters = NULL, $fields = NULL, $limit = 50) {
// TODO:
// 4. Provide ajax(?) text links to alter status of invites
// 5. Provide csv export(?)
if (!isset($fields) || empty($fields)) {
$fields = array(
'node.title' => t('What'),
'email_invitee' => t('Sent to'),
'users.name' => t('Sent by'),
'node_invites.sent' => t('Invite Sent'),
'node_invites.status' => t('Status'),
'acted_upon' => t('Acted Upon'),
);
}
// TODO: Do we need fields besides iid here?
$default_fields = array('iid', 'node_invites.nid', 'uid_inviter', 'notes_invitee', 'notes_inviter');
// Build the WHERE
$where = array();
$values = array();
if (isset($filters) && is_array($filters)) {
foreach ($filters as $field => $value) {
if (is_int($value)) {
$where[] = "$field = %d";
}
else {
$where[] = "$field = '%s'";
}
// Don't display fields that are being filtered on
unset($fields[$field]);
$values[] = $value;
}
$where = implode(" AND ", $where);
}
// Build the SELECT part of the SQL Query
$select = "SELECT " . implode(', ', $default_fields);
$select .= ', ' . implode(', ', array_keys($fields));
// Build the FROM/JOIN component
$from = "FROM {node_invites} AS node_invites JOIN {node} AS node ON node_invites.nid = node.nid JOIN {users} AS users ON users.uid = node_invites.uid_inviter";
$sql = $select . ' ' . $from;
if ($where) {
$sql .= ' AND ' . $where;
}
return theme('node_invite_list_invites', $sql, $values, $fields, $limit);
}
/**
* Implementation of hook_nodeapi().
*/
function node_invite_nodeapi(&$node, $op, $teaser = NULL, $a4 = NULL) {
// decides whether or not to enable disable invites for this node.
if ($op == 'load') {
// We need node_invites_enabled here as well as settings because sometimes
// the node will be set has enabled, but that node type won't be available
// for using with node_invite.
$node->node_invites_enabled = _ni_node_is_enabled($node);
$settings = db_fetch_array(db_query("SELECT * FROM {node_invite_settings} WHERE nid = %d", $node->nid));
$node->node_invite_settings = $settings;
}
elseif ($op == 'update' || $op == 'insert') {
if (!isset($node->node_invites_enabled)) {
$node->node_invites_enabled = _ni_node_is_enabled($node);
}
// Replace any existing data with the content of the submitted node
$sth = db_query("DELETE FROM {node_invite_settings} WHERE nid = %d", $node->nid);
$sth = db_query("INSERT INTO {node_invite_settings} (nid, invites_enabled, open, subject, message) VALUES (%d, %d, '%s', '%s', '%s')", $node->nid, $node->node_invites_enabled, $node->node_invites_open, $node->node_invite_subject_override, $node->node_invite_message_override);
}
elseif ($op == 'delete') {
db_query("DELETE FROM {node_invite_settings} WHERE nid = %d", $node->nid);
}
elseif ($op == 'view' && (!$teaser || variable_get('node_invite_rsvp_form_on_teasers', FALSE))) {
// @TODO: The variable node_invite_form_on_teasers is not yet available
// on the admin interface and needs to be set manually because there's no
// particular reason to not allow the form on the teaser view. Note that
// this variable is only for the RSVP form, not the invite form.
// What would be ideal is if node_invite acted as almost a cck field
// that could be attached to any node type. D7 potential?
if (node_invite_invites_access($node) && variable_get('node_invite_display', 'link') == 'form' && !$teaser) {
module_load_include('inc', 'node_invite', 'node_invite.send');
$invite_form = drupal_get_form('node_invite_send', $node, TRUE);
}
if (variable_get('node_invite_rsvp_display', 'link') == 'form') {
module_load_include('inc', 'node_invite', 'node_invite.rsvp');
$invite = node_invite_find_invite($node, FALSE);
if ($invite) {
$rsvp_form = drupal_get_form('node_invite_rsvp', $node, $invite, TRUE);
}
elseif ($node->node_invite_settings['open']) {
$rsvp_form = drupal_get_form('node_invite_rsvp_new', $node, TRUE);
}
}
if ($invite_form || $rsvp_form) {
$node->content['node_invite'] = array('#weight' => 10);
$node->content['node_invite']['invite'] = array('#value' => $invite_form);
$node->content['node_invite']['rsvp'] = array('#value' => $rsvp_form);
}
}
}
/**
* Implementation of hook_form_alter().
*
* Inserts the node_invite form element into node add/edit forms
*/
function node_invite_form_alter(&$form, &$form_state, $form_id) {
$matches = array();
if (preg_match("/(.+)_node_form$/", $form_id, $matches) && _node_invite_type_is_allowed($matches[1])) {
$node = $form['#node'];
$enabled = _ni_node_is_enabled($node);
// grab the default message/subject (if they exist)
// only if node isn't new (DUH)
$node_invite_subject = $node_invite_message = '';
if (isset($node->nid)) {
$query = db_query("SELECT * FROM {node_invite_settings} WHERE nid = %d", $node->nid);
if ($row = db_fetch_object($query)) {
$node_invite_subject = $row->subject;
$node_invite_message = $row->message;
$node_invite_open = $row->open;
}
}
// add a form element to override
$form['node_invite_group'] = array(
'#type' => 'fieldset',
'#title' => t('Node Invite'),
'#collapsed' => TRUE,
'#collapsible' => TRUE,
'#description' => t('Set the invite settings for this node.'),
);
$form['node_invite_group']['node_invites_enabled'] = array(
'#type' => 'radios',
'#title' => t('Enable invites on this node'),
'#options' => array(
'1' => t('Yes'),
'0' => t('No'),
),
'#default_value' => $enabled,
);
$form['node_invite_group']['node_invites_open'] = array(
'#type' => 'checkbox',
'#title' => t('Allow anyone with permission to RSVP'),
'#description' => t('Leaving this unchecked will mean that only users who have been explicitly invited will be able to rsvp.'),
'#default_value' => $node_invite_open,
);
$form['node_invite_group']['node_invite_subject_override'] = array(
'#type' => 'textfield',
'#title' => t('Override default subject?'),
'#description' => t('Leave this textarea BLANK to use the site-default invite subject.'),
'#default_value' => $node_invite_subject,
);
$form['node_invite_group']['node_invite_message_override'] = array(
'#type' => 'textarea',
'#title' => t('Override default message?'),
'#description' => t('Leave this textarea BLANK to use the site-default invite message.'),
'#default_value' => $node_invite_message,
);
$form['node_invite_group']['node_invite_token_wrapper'] = array(
'#type' => 'fieldset',
'#description' => theme('token_help', 'node'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#title' => t('Available Tokens'),
);
}
}
/**
* Save or update the given invite.
*
* @TODO: We need a hook here for 3rd party module integration
*/
function node_invite_save($invite, $params = array()) {
$ni_fields = array('iid', 'nid', 'uid_inviter', 'inviter_custom_name', 'inviter_custom_email', 'email_invitee', 'name_invitee', 'uid_invitee', 'status', 'sent', 'acted_upon', 'notes_invitee', 'notes_inviter', 'hash', 'personal_message');
if (is_object($invite) && $invite->iid) {
// Updating an invite
$query = array();
$values = array();
foreach ($params as $key => $value) {
if (in_array($key, $ni_fields)) {
$query[] = "$key = '%s'";
$values[] = $value;
}
}
// The status was changed, so acted_upon needs to be set to now()
$keys = array_keys($params);
if (!in_array('acted_upon', $keys) && in_array('status', $keys)) {
$query[] = "acted_upon = %d";
$values[] = time();
}
$success = db_query('UPDATE {node_invites} SET ' . implode(', ', $query) . ' WHERE iid = %d', array_merge($values, array($invite->iid)));
if (!$success) {
return FALSE;
}
// Refresh the invite object
$invite = node_invite_load($invite->iid, TRUE);
}
else {
// Creating a new invite
$fields = array();
$values = array();
$s = array();
foreach ($params as $key => $value) {
if (in_array($key, $ni_fields)) {
$fields[] = $key;
$values[] = $value;
$s[] = is_numeric($value) ? "%d" : "'%s'";
}
}
$sent = time();
$fields[] = 'sent';
$values[] = time();
$s[] = "%d";
$hash = md5($params['email_invitee'] . $sent);
$fields[] = 'hash';
$values[] = $hash;
$s[] = "'%s'";
$success = db_query('INSERT INTO {node_invites} (' . implode(', ', $fields) . ') VALUES ('. implode(', ', $s) . ')', $values);
if (!$success) {
return FALSE;
}
$iid = db_last_insert_id('node_invite', 'iid');
$invite = node_invite_load($iid);
}
return $invite;
}
/**
* Return a list of all invites associated with the given node.
*/
function node_invite_load_invites_by_nid($nid, $status = NULL) {
$status = $status == NODE_INVITE_ANY ? NULL : $status;
$query_args = array($nid);
$status_qry = '';
if ($status && is_array($status)) {
$status_qry = "AND ni.status IN ('" . implode("', '", array_fill(0, count($status), '%s')) . "')";
$query_args = array_merge($query_args, $status);
}
elseif ($status) {
$status_qry = "AND ni.status = '%s'";
$query_args[] = $status;
}
$sql = db_query("SELECT ni.*, u.mail FROM {node_invites} AS ni JOIN {users} AS u ON ni.uid_inviter = u.uid WHERE ni.nid = %d $status_qry", $query_args);
$invites = array();
while ($invite = db_fetch_object($sql)) {
$invites[$invite->iid] = $invite;
}
return $invites;
}
/**
* Attaches invite specific info onto a node.
*/
function node_invite_specific_info($invite, &$node) {
$account = user_load($invite->uid_inviter);
$name = $invite->name_invitee ? $invite->name_invitee : $invitee->email_invitee;
$node->invite_specific_info = array(
'node-invite-iid' => $invite->iid,
'node-invite-hash' => $invite->hash,
'node-invite-recip-name' => $name,
'node-invite-recip-mail' => $invite->email_invitee,
'node-invite-recip-uid' => $invite->uid_invitee,
'inviter-name' => $account->name,
'inviter-mail' => $account->mail,
'node-invite-personal-message' => $invite->personal_message,
);
}
/**
* Mail out the invite.
*
* @param $invite - The invite to send out.
* @param $node - The node object with node_invite_specific_info() already
* having been executed on it.
* @param $token_flush - This is needed if sending multiple invites in a
* single page load (i.e. on the invite send page) as the token's can't
* be cached in that case or everyone's emails will say the same thing
* even if a name or email token is used.
*
* @return the value of drupal_mail().
*/
function node_invite_send_mail($invite, $node, $token_flush = FALSE) {
$message = variable_get('node_invite_message_default', NODE_INVITE_MESSAGE_DEFAULT);
if (isset($invite->settings['message']) && !empty($invite->settings['message'])) {
$message = $invite->settings['message'];
}
$rsvp_url = url(node_invite_rsvp_path($invite), array('absolute' => TRUE));
$message = str_replace("[inviter-rsvp-url]", $rsvp_url, $message);
if ($token_flush) {
$message = token_replace($message, 'node', $node, '[', ']', array(), TRUE);
}
else {
$message = token_replace($message, 'node', $node);
}
// Since the parsed message can contain the "personal message" which can also
// contain tokens, so we need to run a token_replace twice.
$message = token_replace($message, 'node', $node);
$subject = variable_get('node_invite_subject_default', NODE_INVITE_SUBJECT_DEFAULT);
if (isset($invite->settings['subject']) && !empty($invite->settings['subject'])) {
$subject = $invite->settings['subject'];
}
$subject = token_replace($subject, 'node', $node);
$from_string = _ni_format_from_address($invite);
$params = array(
'subject' => $subject,
'body' => $message,
'from' => _ni_format_from_address($invite, TRUE),
);
$msg = drupal_mail(
'node_invite', // module
'invite', // key
$invite->email_invitee, // to
language_default(), // language
$params, // params
$from_string, // from
TRUE // send
);
if ($msg) {
watchdog('node_invite', 'Invite sent to: !email', array('!email' => check_plain($invite->email_invitee)));
}
else {
watchdog('node_invite', 'Unable to send invite to: !email', array('!email' => check_plain($invite->email_invitee)), WATCHDOG_ERROR);
}
return $msg;
}
/**
* Returns a formatted email address to send the message from.
*/
function _ni_format_from_address($invite, $default = FALSE) {
// Format the from address
$from_name = $invite->name;
if ($invite->inviter_custom_name) {
$from_name = $invite->inviter_custom_name;
}
// Use the default from address?
if ($default && $from = variable_get('node_invite_default_from', FALSE)) {
$from_email = $from;
}
else {
$from_email = $invite->mail;
if ($invite->inviter_custom_email) {
$from_email = $invite->inviter_custom_email;
}
}
$from_string = $from_email;
if (!empty($from_name)) {
$from_string = '"' . check_plain($from_name) . '" <' . $from_email . '>';
}
return $from_string;
}
function _ni_format_to_address($invite) {
if ($invite->uid_invitee) {
$user = user_load($invite->uid_invitee);
$to_email = $user->mail;
$to_name = $user->name;
}
else {
$to_email = $invite->email_invitee;
$to_name = $invite->name_invitee;
}
$to_string = $to_email;
if (!empty($to_name) && $to_name != $to_email) {
$to_string = check_plain($to_name) . ' <' . $to_email . '>';
}
return $to_string;
}
/*** Theme functions ***/
function theme_node_invite_view_field_invitees($nid, $invites) {
$items = array();
foreach ($invites as $iid => $invite) {
if ($invite->uid_invitee) {
$account = user_load($invite->uid_invitee);
$items[] = $account->mail;
}
else {
$items[] = $invite->email_invitee;
}
}
if (empty($invites)) {
return t('No one has been invited to this event');
}
else {
return theme('item_list', $items);
}
}
function theme_node_invite_list_invites($sql, $values, $fields, $limit = 50) {
global $user;
// Setup the table headers
$header = array();
foreach ($fields as $field => $title) {
$header[] = array('data' => $title, 'field' => $field);
}
$header[] = array('data' => t('Actions'));
if (isset($account)) {
// Remove the 'Sent by' field, since it's redundant in this case
unset($header[2]);
$header = array_filter($header);
}
if (isset($node)) {
// Remove the 'What' field, since it's redundant in this case
unset($header[0]);
$header = array_filter($header);
}
// Execute the query and build the table row data
$sql .= tablesort_sql($header);
$result = pager_query($sql, $limit, 0, NULL, $values);
// Create a list of display fields without the table part
$display_fields = array();
foreach ($fields as $field => $value) {
if (($index = strrpos($field, '.')) !== FALSE) {
$display_fields[] = substr($field, strrpos($field, '.') + 1);
}
else {
$display_fields[] = $field;
}
}
$destination = drupal_get_destination();
$rows = array();
while ($row = db_fetch_object($result)) {
$actions = array();
if (user_access('manage all invites') || (user_access('manage own invites') && $row->uid_inviter == $user->uid)) {
if (!in_array($row->status, array(NODE_INVITE_RESPONSE_YES, NODE_INVITE_REVOKED))) {
$actions[] = l(t('Revoke'), 'node_invite/revoke/' . $row->iid, array('query' => $destination));
$actions[] = l(t('Resend'), 'node_invite/resend/' . $row->iid, array('query' => $destination));
}
if ($row->status == NODE_INVITE_REVOKED) {
$actions[] = l(t('Reinstate'), 'node_invite/reinstate/' . $row->iid, array('query' => $destination));
}
if (!in_array($row->status, array(NODE_INVITE_NEW, NODE_INVITE_REVOKED))) {
$title = $row->notes_invitee ? t('View (comment)') : t('View');
$actions[] = l($title, 'node_invite/view/' . $row->iid, array('query' => $destination));
}
$url = node_invite_rsvp_path($row->iid);
$actions[] = l(t('Edit'), $url, array('query' => $destination));
}
$actions = implode(' ', $actions);
$actions = empty($actions) ? t('N/A') : $actions;
$current_row = array();
foreach ((array)$row as $field => $value) {
// Don't display non-display fields
if (!in_array($field, $display_fields)) continue;
// Format the date fields
if (in_array($field, array('sent', 'acted_upon'))) {
if (!$value) {
$value = t('Never');
}
else {
$value = format_date($value, 'small');
}
}
$current_row[] = $value;
}
$current_row[] = $actions;
$rows[] = $current_row;
}
if (!$rows) {
return theme('node_invite_list_invites_empty');
}
return theme('table', $header, $rows, array('class' => 'manage-invites')) . theme('pager');
}
function theme_node_invite_list_invites_empty() {
return '' . t('No invites have been sent yet') . '
';
}
function theme_node_invite_view($invite) {
if ($invite->uid_invitee) {
$user = user_load($invite->uid_invitee);
$name = theme('username', $user);
}
elseif (!empty($invite->name_invitee)) {
$name = $invite->name_invitee;
}
else {
$name = $invite->email_invitee;
}
drupal_set_title(t('Viewing invitation for @name', array('@name' => $name)));
$output = array();
$output[] = t('Response: !response', array('!response' => $invite->status));
$output[] = t('Sent: !date', array('!date' => format_date($invite->sent)));
$output[] = t('Updated: !date', array('!date' => format_date($invite->acted_upon)));
$output[] = t('Comment: !notes', array('!notes' => $invite->notes_invitee));
$output = theme_item_list($output);
$link = !empty($_GET['destination']) ? $_GET['destination'] : 'node/' . $invite->nid . '/manage_invites';
$output .= l(t('Back'), $link);
return $output;
}
/*** Node Invite Helper Functions ***/
/**
* Return TRUE if node_invites is enabled on the given nid.
* @param $node - The node to check whether invites are enabled
*/
function _ni_node_is_enabled($node) {
// First confirm that invites are allowed on this node type
if (!_node_invite_type_is_allowed($node->type)) {
return FALSE;
}
$enabled = variable_get('node_invite_default', NODE_INVITE_DEFAULT_FOR_ENABLED_NODES);
// Test to see if the invite status has been explicitly set on this node.
$sth = db_query("SELECT invites_enabled FROM {node_invite_settings} WHERE nid = %d", $node->nid);
if ($row = db_fetch_array($sth)) {
$enabled = $row['invites_enabled'];
}
return $enabled;
}
/**
* Whether node_invite can be used with the specified node type.
*
* @param $type - The node type in question
* @return TRUE if node_invite can be used with the given type.
*/
function _node_invite_type_is_allowed($type) {
return in_array($type, variable_get('node_invite_node_types', array()), TRUE);
}
/**
* Return the path for the RSVP page for the specified invite.
*/
function node_invite_rsvp_path($invite) {
if (!is_object($invite)) {
$invite = node_invite_load($invite);
}
$url = 'node_invite/rsvp/' . $invite->nid . '/';
$url .= variable_get('node_invite_hash_urls', FALSE) ? $invite->hash : $invite->iid;
return $url;
}
/**
* Function to retrieve a list of users based on the given string.
* This is a slight modification of the user_autocomplete() function as we
* want to allow the user to enter a comma separated list of users instead of
* just a single user.
*
* @param $string - A list of usernames separated by comma's
* @return an array containing a list of matching users.
*/
function _node_invite_user_autocomplete($string = '') {
$usernames = preg_split('/ *, */', $string);
// Only try and match on the last username in the list
$username = array_pop($usernames);
$string = implode(', ', $usernames);
$limit = variable_get('node_invite_user_limit', 10);
$matches = array();
if ($username && variable_get('node_invite_userreference', FALSE) && module_exists('userreference')) {
$settings = array(
'referenceable_roles' => variable_get('node_invite_referenceable_roles', array()),
'referenceable_status' => variable_get('node_invite_referenceable_status', ''),
'advanced_view' => variable_get('node_invite_advanced_view', NULL),
'advanced_view_args' => variable_get('node_invite_advanced_view_args', ''),
);
$results = FALSE;
if (!empty($settings['advanced_view'])) {
$results = _userreference_potential_references_views($settings, $username, 'contains', array(), $limit);
}
if (!$results) {
$results = _userreference_potential_references_standard($settings, $username, 'contains', array(), $limit);
}
foreach ($results as $result) {
$key = $string ? $string . ', ' . $result['title'] : $result['title'];
$matches[$key] = '' . $result['rendered'] . '
';
}
}
elseif ($username) {
// Userreference selection is not enabled, so fall back to the default
if (count($usernames)) {
// Filter out all users who have already been selected
$not_in = "AND LOWER(name) NOT IN (" . implode(', ', array_fill(0, count($usernames), "LOWER('%s')")) . ")";
}
$values = array_merge(array($username), $usernames);
$result = db_query_range("SELECT name FROM {users} WHERE LOWER(name) LIKE LOWER('%s%%') $not_in", $values, 0, $limit);
while ($user = db_fetch_object($result)) {
$key = $string ? $string . ', ' . $user->name : $user->name;
$matches[$key] = check_plain($user->name);
}
}
drupal_json($matches);
}
/**
* Return a list of invites for the specified uid or email address. If the uid
* is set then the email address parameter will be ignored.
*/
function node_invite_user_invites($uid = NULL, $email = NULL) {
$invites = array();
if ($uid) {
$query = "SELECT * FROM node_invites WHERE uid_invitee = %d";
$param = $uid;
}
elseif ($email) {
$query = "SELECT * FROM node_invites WHERE email_invitee = '%s'";
$param = $email;
}
if ($query) {
$result = db_query($query, $param);
while ($invite = db_fetch_object($result)) {
$invites[$invite->iid] = $invite;
}
}
return $invites;
}