'Notifications_team autocomplete', 'page callback' => 'notifications_team_autocomplete', 'page arguments' => array(2), 'access arguments' => array('subscribe other users'), 'type' => MENU_CALLBACK ); $items['admin/messaging/notifications/team_ui'] = array( 'title' => 'Team UI', 'description' => 'Team UI settings.', 'page callback' => 'drupal_get_form', 'page arguments' => array('notifications_team_ui_settings_form'), 'access arguments' => array('administer site configuration'), 'type' => MENU_LOCAL_TASK, ); return $items; } /** * Implementation of hook_perms() */ function notifications_team_perm() { return array('subscribe other users'); } /** * Implementation of hook_theme() */ function notifications_team_theme() { return array( 'notifications_team_form' => array(), 'notifications_team_user_display' => array( 'arguments' => array('data' => NULL, 'separator' => NULL, 'user' => NULL), ), 'notifications_team_user_plaintext' => array( 'arguments' => array('data' => NULL, 'separator' => NULL, 'user' => NULL), ), ); } /** * We implement a more efficient static cache than user_access() * to check whether a user can subscribe to content. */ function notifications_team_can_subscribe($account = NULL, $reset = FALSE) { // Cache the role ids that have access to 'subscribe to content' static $roles; if ($account->uid == 1) { return TRUE; } if (!isset($roles) || $reset) { $result = db_query("SELECT rid, perm FROM {permission}"); while ($row = db_fetch_object($result)) { $perms = explode(', ', $row->perm); if (array_search('subscribe to content', $perms) !== FALSE) { $roles[$row->rid] = TRUE; } else { $roles[$row->rid] = FALSE; } } } // Check each role to see if this user has access to 'subscribe to content' if (!empty($account->roles)) { foreach ($account->roles as $rid) { if (!empty($roles[$rid])) { return TRUE; } } } return FALSE; } /** * Get roles that have the permission */ function _notifications_team_get_roles($permission = 'subscribe to content') { static $rids; if (!isset($rids[$permission])) { $rids[$permission] = array(); // Search for permission name not followed by a space (which can be other permission) $result = db_query("SELECT DISTINCT rid FROM {permission} WHERE perm LIKE '%%%s,%%' OR perm LIKE '%%%s'", $permission, $permission); while ($role = db_fetch_object($result)) { $rids[$permission][$role->rid] = $role->rid; } } return $rids[$permission]; } /** * Returns an array of minimal user account objects that have been * checked for the 'subscribe to content' permission. * * @param $like * String to match for autocomplete fields * @param $limit * Maximum number of rows to return * @param $gid * Group id if using organic groups * @param $op * Operation to perform * - 'query' for regular query * - 'count' for count query * - 'reset' to reset the static cache, mostly for unit testing; */ function notifications_team_get_users($like = NULL, $limit = 0, $gid = 0, $uids = NULL, $op = 'query') { static $users; if ($op == 'reset') { $users = array(); return; } // This is our static cache id $params = array($like ? $like : '', $gid, $uids ? implode(',', $uids) : '', $op); $cid = implode(':', $params); if (!isset($users[$cid])) { if (($view = variable_get('notifications_team_user_view', '')) && module_exists('views')) { $users[$cid] = notifications_team_get_users_view($view, $like, $limit, $gid, $uids, $op); } else { $users[$cid] = notifications_team_get_users_default($like, $limit, $gid, $uids, $op); } } return $users[$cid]; } /** * Count number of users that meet some conditions * * @param $gid * Group id */ function notifications_team_count_users($gid) { if (($view = variable_get('notifications_team_user_view', '')) && module_exists('views')) { $users = notifications_team_get_users_view($view, $like, $limit, $gid); } else { $users = notifications_team_get_users_default($like, $limit, $gid); } } /** * Get list of users from predefined view */ function notifications_team_get_users_view($view_name, $string = NULL, $limit = 0, $gid = 0, $uids = NULL, $op = 'query') { $result = $op == 'count' ? 0 : array(); if ($view = views_get_view($view_name)) { // Use the default display $view->set_display(); $view->preview = TRUE; // If we have a $string filter, we find string fields in our view, and add conditions to narrow the results // What we do is adding the information into the display handler so it can be retrieved later on hook_views_query_alter() // The $search array contains an array of searchable fields in the view for each table (varchar, text) if (isset($string) && ($search = _notifications_team_view_string_fields($view))) { $options = array( 'search_fields' => $search, 'string' => $string, 'match' => 'contains', ); } elseif ($uids) { // If we just want some users, pass more parameters to the query alter // This and the string search are exclusive options $options = array( 'table' => 'users', 'field_id' => 'uid', 'ids' => $uids, ); } if (!empty($options)) { $view->display_handler->set_option('notifications_team_options', $options); } // If we have a group id we set it as an argument if ($gid) { $view->pre_execute(array($gid)); } else { $view->pre_execute(); } if ($op == 'count') { $view->set_items_per_page(1); // Count operation: trick the view with some parameters. // @todo: There should be a better way to do this (?) $view->get_total_rows = TRUE; $view->display_handler->preview(); $view->post_execute(); return $view->total_rows; } else { $view->set_items_per_page($limit); // Get the results. Render the fields separately to get the name $view->display_handler->preview(); $view->post_execute(); $fields = $view->field; $options = $view->style_plugin->row_plugin->options; foreach ($view->result as $index => $row) { $rendered = (array)$view->style_plugin->rendered_fields[$index]; $result[$row->uid] = _notifications_team_users_view_format($row, $rendered, $fields, $options); } } } return $result; } /** * Format user names from view * * @param $user * User object resulting from the query * @param $rendered * Rendered fields, usually as HTML * @param $fields * Field definition objects from the view * @param $options * Options form $view->style_plugin->row_plugin->options */ function _notifications_team_users_view_format($user, $rendered, $fields, $options) { $inline = !empty($options['inline']) ? $options['inline'] : array('name'); $separator = !empty($options['separator']) ? $options['separator'] : ', '; // Build user name, just reassign field $user->name = $user->users_name; // Build html display part, get out excluded fields from rendered foreach ($fields as $key => $field) { if (!empty($field->options['exclude'])) { unset($rendered[$key]); } } $user->display = theme('notifications_team_user_display', $rendered, $separator, $user); // Build plaintext display part $text= array(); foreach ($inline as $key) { // @TODO: There should be a better way of rendering the field as plaintext (?) $text[$key] = check_plain($user->{$fields[$key]->field_alias}); //$fields[$key]->render($user); } $user->plaintext = theme('notifications_team_user_plaintext', $text, $separator, $user); return $user; } /** * Get string fields from view to perform searches * * @return array of table => array('field1', 'field2'...) */ function _notifications_team_view_string_fields($view) { $search = array(); foreach ($view->display_handler->options['fields'] as $name => $field) { $table = $field['table']; if ($schema = drupal_get_schema($table)) { $type = $schema['fields'][$name]['type']; if ($type == 'varchar' || $type == 'text') { $search[$table][] = $name; } } } return $search; } /** * Get list of users that can be subscribed, default query, using og context when available */ function notifications_team_get_users_default($like = NULL, $limit = 0, $gid = NULL, $uids = NULL, $op = 'query') { $users = array(); $where = $join = $args = array(); $order = ''; // Get roles that can subscribe. If none, returm empty (array or 0 for count) $rids = _notifications_team_get_roles('subscribe to content'); if (!$rids) { return ($op == 'count') ? 0 : array(); } // Remove authenticated user if there if (isset($rids[DRUPAL_AUTHENTICATED_RID])) { unset($rids); } // Populate $gid automatically from group context. // Avoid this behavior if $gid is specified explicitly. if (empty($gid) && module_exists('og') && $oggroup = og_get_group_context()) { $gid = $oggroup->nid; } // Build query $sql_select = "SELECT DISTINCT u.uid, u.name, u.mail"; $sql_from = "FROM {users} u"; $where[] = "u.status > 0"; $order = "ORDER BY u.name ASC"; // Limit to certain users if passed $uids if ($uids) { $where[] = 'u.uid IN (' . db_placeholders($uids) . ')'; $args = $uids; } // Add group condition if gid if ($gid) { $join[] = "INNER JOIN {og_uid} ou ON ou.uid = u.uid"; $where[] = "ou.nid = %d"; $args[] = $gid; $where[] = "ou.is_active >= 1"; $where[] = "ou.is_admin >= 0"; } // Add permission/role condition. If no roles (only authenticated user, add an uid condition) if ($rids) { $join[] = "LEFT JOIN {users_roles} r ON u.uid = r.uid"; $where[] = "(r.rid IN (" . db_placeholders($rids) . ') OR u.uid = 1)'; $args = array_merge($args, $rids); } else { $where[] = "u.uid > 0"; } // Add string matching condition if (!empty($like)) { $where[] = "LOWER(u.name) LIKE LOWER('%s%%')"; $args[] = $like; } $sql_from .= ' ' . implode(' ', $join); $sql_where = ' WHERE ' . implode(' AND ', $where); // If it is a counting query, without order by, just count and return if ($op == 'count') { $sql = implode(' ', array('SELECT COUNT(DISTINCT u.uid)', $sql_from, $sql_where)); return db_result(db_query($sql, $args)); } else { $sql = implode(' ', array($sql_select, $sql_from, $sql_where, $order)); $result = $limit ? db_query_range($sql, $args, 0, $limit) : db_query($sql, $args); } while ($row = db_fetch_object($result)){ $users[$row->uid] = $row; } return $users; } /** * Define a "delicious" like form subscribing users to nodes. * TODO - prepopulate with current user|case owner|case assignee */ function notifications_team_form($nid) { $form = array(); $gid = module_exists('og') && ($group = og_get_group_context()) ? $group->nid : 0; $count = notifications_team_get_users(NULL, 0, $gid, NULL, 'count'); if ($count) { // Check whether we need to list all or just an autocomplete form $acomplete = $count > variable_get('notifications_team_max_options', 20); // Get existing subscriptions. if (is_numeric($nid)) { $subscriptions = notifications_team_get_subscriptions($nid); $subscribers = array_keys($subscriptions); } else { $subscriptions = $subscribers = array(); } // Select all users if not autocomplete or users with subscriptions otherwise if ($acomplete) { $users = notifications_team_get_users(NULL, 0, $gid, $subscribers); } else { $users = notifications_team_get_users(NULL, 0, $gid); } // Build user names to display $user_names = array(); if ($acomplete) { // have an autocomplete box and only have users on the checkboxes that are already subscribed foreach($subscribers as $uid) { $user = $users[$uid]; $user_names[$uid] = isset($user->display) ? $user->display : $user->name; } asort($user_names); } elseif (count($users)) { foreach ($users as $user) { $user_names[$user->uid] = isset($user->display) ? $user->display : $user->name; } } else { // If we don't have any user available, display no form return array(); } // Build the form. $form['notifications_team'] = array( '#tree' => TRUE, '#theme' => 'notifications_team_form', ); $form['notifications_team']['selected'] = array( '#type' => 'hidden', '#default_value' => implode(',', $subscribers), ); if ($acomplete) { $form['notifications_team']['listed'] = array( '#type' => 'textfield', '#autocomplete_path' => 'notifications_team/autocomplete/'. $gid, '#default_value' => '', '#description' => t('Enter list of usernames separated by commas'), '#required' => FALSE, ); } else { $form['team_checkall'] = array( '#type' => 'checkbox', '#title' => t('Notify all users'), '#weight' => 0, ); } if ($user_names) { $form['notifications_team']['options'] = array( '#type' => 'markup', '#value' => $user_names, ); } } return $form; } /** * Get existing subscriptions for a node, indexed by uid */ function notifications_team_get_subscriptions($nid, $reset = FALSE) { static $subscriptions; if (!isset($subscriptions[$nid]) || $reset) { $params = array('type' => 'thread', 'event_type' => 'node'); $conditions = array('nid' => $nid); $subscriptions[$nid] = notifications_get_subscriptions($params, $conditions, TRUE, 'uid'); } return $subscriptions[$nid]; } /** * Theme function for rendering the js-enabled team notifications widget. */ function theme_notifications_team_form($form) { // Add javascript drupal_add_js(drupal_get_path('module', 'notifications_team') .'/notifications_team.js', 'module'); drupal_add_css(drupal_get_path('module', 'notifications_team') .'/notifications_team.css'); $output = ''; // Render each of the user selector options if ($form['options']['#value']) { $options = ''; foreach ($form['options']['#value'] as $uid => $name) { $options .= "