array( 'title' => t('Filter private messages'), 'description' => t('Use the search and filter widget'), ), 'tag private messages' => array( 'title' => t('Tag private messages'), 'description' => t('Tag private messages'), ), 'create private message tags' => array( 'title' => t('Create private message tags'), 'description' => t('Create new private message tags'), ), ); } /** * Implementation of hook_menu(). */ function privatemsg_filter_menu() { $items['admin/config/messaging/privatemsg/tags'] = array( 'title' => 'Tags', 'description' => 'Configure tags.', 'page callback' => 'privatemsg_tags_admin', 'file' => 'privatemsg_filter.admin.inc', 'access arguments' => array('administer privatemsg settings'), 'type' => MENU_LOCAL_TASK, ); $items['admin/config/messaging/privatemsg/tags/list'] = array( 'title' => 'List', 'description' => 'Configure tags.', 'page callback' => 'privatemsg_tags_admin', 'file' => 'privatemsg_filter.admin.inc', 'access arguments' => array('administer privatemsg settings'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -5, ); $items['admin/config/messaging/privatemsg/tags/add'] = array( 'title' => 'Add tag', 'description' => 'Configure tags.', 'page callback' => 'drupal_get_form', 'page arguments' => array('privatemsg_tags_form'), 'file' => 'privatemsg_filter.admin.inc', 'access arguments' => array('administer privatemsg settings'), 'type' => MENU_LOCAL_ACTION, ); $items['admin/config/messaging/privatemsg/tags/rebuild'] = array( 'title' => 'Rebuild inbox', 'page callback' => 'drupal_get_form', 'page arguments' => array('privatemsg_filter_inbox_rebuid_form'), 'file' => 'privatemsg_filter.admin.inc', 'access arguments' => array('administer privatemsg settings'), 'type' => MENU_LOCAL_TASK, ); $items['admin/config/messaging/privatemsg/tags/edit/%'] = array( 'title' => 'Edit tag', 'description' => 'Configure tags.', 'page callback' => 'drupal_get_form', 'page arguments' => array('privatemsg_tags_form', 6), 'file' => 'privatemsg_filter.admin.inc', 'access arguments' => array('administer privatemsg settings'), 'type' => MENU_CALLBACK, ); $items['admin/config/messaging/privatemsg/tags/delete/%'] = array( 'title' => 'Delete tag', 'description' => 'Configure tags.', 'page callback' => 'drupal_get_form', 'page arguments' => array('privatemsg_filter_tags_delete', 6), 'file' => 'privatemsg_filter.admin.inc', 'access arguments' => array('administer privatemsg settings'), 'type' => MENU_CALLBACK, ); $items['messages/inbox'] = array( 'title' => 'Inbox', 'page callback' => 'privatemsg_list_page', 'page arguments' => array('inbox'), 'file' => 'privatemsg.pages.inc', 'file path' => drupal_get_path('module', 'privatemsg'), 'access callback' => 'privatemsg_user_access', 'type' => variable_get('privatemsg_filter_default_list', 0) ? MENU_LOCAL_TASK : MENU_DEFAULT_LOCAL_TASK, 'weight' => -15, 'menu_name' => 'user-menu', ); $items['messages/sent'] = array( 'title' => 'Sent Messages', 'page callback' => 'privatemsg_list_page', 'page arguments' => array('sent'), 'file' => 'privatemsg.pages.inc', 'file path' => drupal_get_path('module', 'privatemsg'), 'access callback' => 'privatemsg_user_access', 'type' => MENU_LOCAL_TASK, 'weight' => -12, 'menu_name' => 'user-menu', ); $items['messages/filter/autocomplete'] = array( 'page callback' => 'privatemsg_autocomplete', 'file' => 'privatemsg.pages.inc', 'file path' => drupal_get_path('module', 'privatemsg'), 'access callback' => 'privatemsg_user_access', 'access arguments' => array('write privatemsg'), 'type' => MENU_CALLBACK, 'weight' => -10, ); $items['messages/filter/tag-autocomplete'] = array( 'page callback' => 'privatemsg_filter_tags_autocomplete', 'file' => 'privatemsg_filter.pages.inc', 'access callback' => 'privatemsg_user_access', 'access arguments' => array('tag private messages'), 'type' => MENU_CALLBACK, 'weight' => -10, ); return $items; } /** * Implement hook_menu_alter(). */ function privatemsg_filter_menu_alter(&$items) { // Rename messages to "All messages". $items['messages/list']['title'] = 'All messages'; if(variable_get('privatemsg_filter_default_list', 0) == 0) { // Change default argument of /messages to inbox. and set the task to MENU_LOCAL_TASK. $items['messages']['page arguments'] = array('inbox'); $items['messages/list']['type'] = MENU_LOCAL_TASK; } } /** * Implementation of hook_form_FORM_ID_alter() to add a filter widget to the message listing pages. */ function privatemsg_filter_form_privatemsg_admin_settings_alter(&$form, $form_state) { $form['privatemsg_listing']['privatemsg_filter_default_list'] = array( '#type' => 'radios', '#default_value' => variable_get('privatemsg_filter_default_list', 0), '#options' => array(t('Inbox'), t('All messages')), '#title' => t('Choose the default list option'), '#description' => t('Choose which of the two lists are shown by default when following the messages link.'), ); $form['privatemsg_listing']['privatemsg_filter_searchbody'] = array( '#type' => 'checkbox', '#title' => t('Search message body'), '#description' => t('WARNING: turning on this feature will slow down search performance by a large factor. Gets worse as your messages database increases.'), '#default_value' => variable_get('privatemsg_filter_searchbody', FALSE), ); // Add tags to the list of possible columns. $form['privatemsg_listing']['privatemsg_display_fields']['#options']['tags'] = t('Tags'); $form['#submit'][] = 'privatemsg_filter_settings_submit'; } /** * Rebuilding the menu if necessary. */ function privatemsg_filter_settings_submit($form, &$form_state) { if ($form['privatemsg_listing']['privatemsg_filter_default_list']['#default_value'] != $form_state['values']['privatemsg_filter_default_list']) { menu_rebuild(); } } /** * Function to create a tag * * @param $tags A single tag or an array of tags. */ function privatemsg_filter_create_tags($tags) { if (!is_array($tags)) { $tags = array($tags); } $tag_ids = array(); foreach ($tags as $tag) { $tag = trim($tag); if (empty($tag)) { // Do not save a blank tag. continue; } // Check if the tag already exists and only create the tag if it does not. $tag_id = db_query("SELECT tag_id FROM {pm_tags} WHERE tag = :tag", array(':tag' => $tag))->fetchField(); if (empty($tag_id) && privatemsg_user_access('create private message tags')) { $tag_id = db_insert('pm_tags') ->fields(array('tag' => $tag)) ->execute(); } elseif (empty($tag_id)) { // The user does not have permission to create new tags - disregard this tag and move onto the next. drupal_set_message(t('Tag %tag was ignored because you do not have permission to create new tags.', array('%tag' => $tag))); continue; } $tag_ids[] = $tag_id; } return $tag_ids; } /** * Tag one or multiple threads with a tag. * * @param $threads A single thread id or an array of thread ids. * @param $tag_id Id of the tag. */ function privatemsg_filter_add_tags($threads, $tag_ids, $account = NULL) { if (!is_array($threads)) { $threads = array($threads); } if (!is_array($tag_ids)) { $tag_ids = array($tag_ids); } if (empty($account)) { global $user; $account = clone $user; } foreach ($tag_ids as $tag_id) { foreach ($threads as $thread) { // Make sure that we don't add a tag to a thread twice, // only insert if there is no such tag yet. db_merge('pm_tags_index') ->key(array( 'tag_id' => $tag_id, 'uid' => $account->uid, 'thread_id' => $thread, )) ->execute(); } } } /** * Remove tag from one or multiple threads. * * @param $threads A single thread id or an array of thread ids. * @param $tag_id Id of the tag - set to NULL to remove all tags. */ function privatemsg_filter_remove_tags($threads, $tag_ids = NULL, $account = NULL) { if (!is_array($threads)) { $threads = array($threads); } if (empty($account)) { global $user; $account = $user; } if (is_null($tag_ids)) { //Delete all tag mapping - all except for the inbox tag if it exists. db_delete('pm_tags_index') ->condition('uid', $account->uid) ->condition('thread_id', $threads) ->condition('tag_id', variable_get('privatemsg_filter_inbox_tag', ''), '<>') ->execute(); } else { if (!is_array($tag_ids)) { $tag_ids = array($tag_ids); } //Delete tag mapping for the specified tag. db_delete('pm_tags_index') ->condition('uid', $account->uid) ->condition('thread_id', $threads) ->condition('tag_id', $tag_ids) ->execute(); } } function privatemsg_filter_get_filter($account) { $filter = array(); // Filtering by tags is either allowed if the user can use tags or he can // filter. if (privatemsg_user_access('filter private messages') || privatemsg_user_access('tag private messages')) { if (isset($_GET['tags'])) { $_GET['tags'] = urldecode($_GET['tags']); $tag_data = privatemsg_filter_get_tags_data($account); foreach (explode(',', $_GET['tags']) as $tag) { if (isset($tag_data[$tag])) { $filter['tags'][$tag] = $tag; } elseif (in_array($tag, $tag_data)) { $filter['tags'][array_search($tag, $tag_data)] = array_search($tag, $tag_data); } } } } // Users can only use the text search or search by author if they have the // necessary permission. if (privatemsg_user_access('filter private messages')) { if (isset($_GET['author'])) { list($filter['author']) = _privatemsg_parse_userstring($_GET['author']); } if (isset($_GET['search'])) { $filter['search'] = $_GET['search']; } } if(!empty($filter)) { return $filter; } if (!empty($_SESSION['privatemsg_filter'])) { return $_SESSION['privatemsg_filter']; } } function privatemsg_filter_get_tags_data($account) { static $tag_data; if (is_array($tag_data)) { return $tag_data; } // Only show the tags that a user have used. return $tag_data = _privatemsg_assemble_query(array('tags', 'privatemsg_filter'), $account)->execute()->fetchAllKeyed(); } function privatemsg_filter_dropdown(&$form_state, $account) { drupal_add_css(drupal_get_path('module', 'privatemsg_filter') . '/privatemsg_filter.css'); $form['filter'] = array( '#type' => 'fieldset', '#title' => t('Filter Messages'), '#collapsible' => TRUE, '#collapsed' => TRUE, '#weight' => -20, // The form is always called when search arguments are passed in, even if // they don't have access to it. This is necessary to process the search // query. But we don't want to show them the form. '#access' => privatemsg_user_access('filter private messages'), ); $form['filter']['search'] = array( '#type' => 'textfield', '#title' => variable_get('privatemsg_filter_searchbody', FALSE) ? t('By message text') : t('By subject'), '#weight' => -20, '#size' => 25, ); $form['filter']['author'] = array( '#type' => 'textfield', '#title' => t('By participant'), '#weight' => -5, '#size' => 25, '#autocomplete_path' => 'messages/filter/autocomplete', ); // Only show form if the user has some messages tagged. if (count($tag_data = privatemsg_filter_get_tags_data($account))) { $form['filter']['tags'] = array( '#type' => 'select', '#title' => t('By tags'), '#options' => $tag_data, '#multiple' => TRUE, '#weight' => 0 ); } $form['filter']['actions'] = array( '#type' => 'actions', '#attributes' => array('class' => array('privatemsg-filter-actions')), ); $form['filter']['actions']['submit'] = array( '#type' => 'submit', '#value' => t('Filter'), '#weight' => 10, '#submit' => array('privatemsg_filter_dropdown_submit'), ); $form['filter']['actions']['save'] = array( '#type' => 'submit', '#value' => t('Save filter'), '#weight' => 11, '#submit' => array('privatemsg_filter_dropdown_submit'), ); if ($filter = privatemsg_filter_get_filter($account)) { // Display a message if the user will not see the filter form. if (!empty($filter['tags']) && !empty($_GET['tags']) && !privatemsg_user_access('filter private messages')) { drupal_set_message(t('Messages tagged with %tags are currently displayed. Click here to remove this filter.', array('%tags' => $_GET['tags'], '@remove_filter_url' => url($_GET['q'])))); } privatemsg_filter_dropdown_set_active($form, $filter); } return $form; } function privatemsg_filter_dropdown_set_active(&$form, $filter) { $form['filter']['#title'] = t('Filter Messages (Active)'); $form['filter']['#collapsed'] = FALSE; if (isset($filter['author'])) { $string = ''; foreach ($filter['author'] as $author) { $string .= privatemsg_recipient_format($author, array('plain' => TRUE)) . ', '; } $form['filter']['author']['#default_value'] = $string; } if (isset($filter['tags'])) { $form['filter']['tags']['#default_value'] = $filter['tags']; } if (isset($filter['search'])) { $form['filter']['search']['#default_value'] = $filter['search']; } $form['filter']['actions']['reset'] = array( '#type' => 'submit', '#value' => t('Reset'), '#weight' => 12, '#submit' => array('privatemsg_filter_dropdown_submit'), ); } function privatemsg_filter_dropdown_submit($form, &$form_state) { if (!empty($form_state['values']['author'])) { list($form_state['values']['author']) = _privatemsg_parse_userstring($form_state['values']['author']); } switch ($form_state['values']['op']) { case t('Save filter'): $filter = array(); if (!empty($form_state['values']['tags'])) { $filter['tags'] = $form_state['values']['tags']; } if (!empty($form_state['values']['author'])) { $filter['author'] = $form_state['values']['author']; } if (!empty($form_state['values']['search'])) { $filter['search'] = $form_state['values']['search']; } $_SESSION['privatemsg_filter'] = $filter; break; case t('Filter'): drupal_goto($_GET['q'], array('query' => privatemsg_filter_create_get_query($form_state['values']))); return; break; case t('Reset'): $_SESSION['privatemsg_filter'] = array(); break; } $form_state['redirect'] = $_GET['q']; } /** * Creates a GET query based on the selected filters. */ function privatemsg_filter_create_get_query($filter) { $query = array(); if (isset($filter['tags']) && !empty($filter['tags'])) { $ids = array(); foreach ($filter['tags'] as $tag) { if ((int)$tag > 0) { $ids[] = $tag; } else { $query['tags'][] = $tag; } } $sql = 'SELECT pmt.tag FROM {pm_tags} pmt WHERE pmt.tag_id IN (:tags)'; $query['tags'] = db_query($sql, array(':tags' => $filter['tags']))->fetchCol(); if (isset($query['tags'])) { $query['tags'] = implode(',', $query['tags']); } } if (isset($filter['author']) && !empty($filter['author'])) { foreach ($filter['author'] as $author) { if (is_object($author) && isset($author->uid) && isset($author->name)) { $query['author'][] = privatemsg_recipient_format($author, array('plain' => TRUE)); } elseif (is_int($author) && $author_obj = array_shift(privatemsg_user_load_multiple(array($author)))) { $query['author'][] = privatemsg_recipient_format($author, array('plain' => TRUE)); } } if (isset($query['author'])) { $query['author'] = implode(',', $query['author']); } } if (isset($filter['search']) && !empty($filter['search'])) { $query['search'] = $filter['search']; } return $query; } /** * Implementation of hook_form_FORM_ID_alter() to add a filter widget to the message listing pages. */ function privatemsg_filter_form_privatemsg_list_alter(&$form, $form_state) { global $user; if (privatemsg_user_access('filter private messages') && !empty($form['updated']['list']['#options']) || privatemsg_filter_get_filter($user)) { $form += privatemsg_filter_dropdown($form_state, $form['account']['#value']); } $fields = array_filter(variable_get('privatemsg_display_fields', array('participants'))); if (privatemsg_user_access('tag private messages') && in_array('tags', $fields) && !empty($form['updated']['list']['#options'])) { // Load thread id's of the current list. $threads = array_keys($form['updated']['list']['#options']); // Fetch all tags of those threads. $query = _privatemsg_assemble_query(array('tags', 'privatemsg_filter'), $user, $threads, 3); // Add them to tableselect options. foreach ($query->execute() as $tag) { $form['updated']['list']['#options'][$tag->thread_id]['tags'][$tag->tag_id] = $tag->tag; } // Avoid notices for threads without tags. foreach ($form['updated']['list']['#options'] as &$thread) { if (empty($thread['tags'])) { $thread['tags'] = array(); } } } if (privatemsg_user_access('tag private messages') && !empty( $form['updated']['list']['#options'])) { $form['updated']['actions']['tag-add'] = array( '#type' => 'textfield', '#size' => 15, '#autocomplete_path' => 'messages/filter/tag-autocomplete', ); $form['updated']['actions']['tag-add-submit'] = array( '#type' => 'submit', '#value' => t('Apply Tag'), '#submit' => array('privatemsg_filter_add_tag_submit'), '#ajax' => array( 'callback' => 'privatemsg_list_js', 'wrapper' => 'privatemsg-list-form', 'effect' => 'fade', ), ); $tags = privatemsg_filter_get_tags_data($user); if (!empty($tags)) { $options[0] = t('Remove Tag...'); foreach ($tags as $tag_id => $tag) { $options[$tag_id] = $tag; } $form['updated']['actions']['tag-remove'] = array( '#type' => 'select', '#options' => $options, '#default_value' => 0, '#ajax' => array( 'callback' => 'privatemsg_list_js', 'wrapper' => 'privatemsg-list-form', 'effect' => 'fade', ), '#submit' => array('privatemsg_filter_remove_tag_submit'), '#executes_submit_callback' => TRUE, ); $form['updated']['actions']['tag-remove-submit'] = array( '#type' => 'submit', '#value' => t('Remove Tag'), '#submit' => array('privatemsg_filter_remove_tag_submit'), '#attributes' => array('class' => array('form-item')), '#states' => array( 'visible' => array( // This is never true, button is always hidden when JS is enabled. ':input[name=operation]' => array('value' => 'fake'), ), ), ); } } } /** * Form callback for removing a tag to threads. */ function privatemsg_filter_privatemsg_thread_operations($type) { if ($type == 'inbox') { $archive = array( 'label' => t('Archive'), 'callback' => 'privatemsg_filter_remove_tags', 'callback arguments' => array('tag_id' => variable_get('privatemsg_filter_inbox_tag', '')), 'success message' => t('The messages have been archived.'), 'undo callback' => 'privatemsg_filter_add_tags', 'undo callback arguments' => array('tag_id' => variable_get('privatemsg_filter_inbox_tag', '')), ); return array('archive' => $archive); } } /** * Define the header for the tags column. * * @see theme_privatemsg_list_header() */ function theme_privatemsg_list_header__tags() { if (privatemsg_user_access('tag private messages')) { return array( 'data' => t('Tags'), 'class' => 'privatemsg-header-tags', '#weight' => -42, ); } } /** * Default theme pattern function to display tags. * * @see theme_privatemsg_list_field() */ function theme_privatemsg_list_field__tags($arguments) { $thread = $arguments['thread']; if (!empty($thread['tags'])) { $tags = array(); foreach ($thread['tags'] as $tag_id => $tag) { $tags[] = l(strlen($tag) > 15 ? substr($tag, 0, 13) . '...' : $tag, 'messages', array( 'attributes' => array('title' => $tag), 'query' => array('tags' => $tag) )); } return array( 'data' => implode(', ', $tags), 'class' => array('privatemsg-list-tags'), ); } // Return an empty row. return array('data' => ''); } /** * Form callback for adding a tag to threads. */ function privatemsg_filter_add_tag_submit($form, &$form_state) { // Check if textfield is not empty. if (empty($form_state['values']['tag-add'])) { return; } $tags = explode(',', $form_state['values']['tag-add']); $tag_ids = privatemsg_filter_create_tags($tags); if (empty($tag_ids)) { return; } $operation = array( 'callback' => 'privatemsg_filter_add_tags', 'callback arguments' => array('tag_id' => $tag_ids), 'success message' => t('The selected conversations have been tagged.'), 'undo callback' => 'privatemsg_filter_remove_tags', 'undo callback arguments' => array('tag_id' => $tag_ids), ); privatemsg_operation_execute($operation, $form_state['values']['list']); $form_state['rebuild'] = TRUE; $form_state['input'] = array(); } /** * Form callback for removing a tag to threads. */ function privatemsg_filter_remove_tag_submit($form, &$form_state) { $operation = array( 'callback' => 'privatemsg_filter_remove_tags', 'callback arguments' => array('tag_id' => $form_state['values']['tag-remove']), 'success message' => t('The tag has been removed from the selected conversations.'), 'undo callback' => 'privatemsg_filter_add_tags', 'undo callback arguments' => array('tag_id' => $form_state['values']['tag-remove']), ); privatemsg_operation_execute($operation, $form_state['values']['list']); $form_state['rebuild'] = TRUE; $form_state['input'] = array(); } /** * Hook into the query builder to add the tagging info to the correct query */ function privatemsg_filter_query_privatemsg_list_alter($query) { $account = $query->getMetaData('arg_1'); $argument = $query->getMetaData('arg_2'); // Add all conditions to the count query too. $count_query = $query->getCountQuery(); // Check if its a filtered view. if ($argument == 'sent') { $query->condition('pm.author', $account->uid); $count_query->condition('pm.author', $account->uid); } $filter = privatemsg_filter_get_filter($account); if ($argument == 'inbox') { $filter['tags'][] = variable_get('privatemsg_filter_inbox_tag', ''); } // Filter the message listing by any set tags. if ($filter) { if (!empty($filter['tags'])) { foreach ($filter['tags'] as $tag) { $alias = $query->join('pm_tags_index', 'pmti',"%alias.thread_id = pmi.thread_id AND %alias.uid = pmi.recipient AND pmi.type IN ('user', 'hidden')"); $query->condition($alias . '.tag_id', $tag); $alias = $count_query->join('pm_tags_index', 'pmti',"%alias.thread_id = pmi.thread_id AND %alias.uid = pmi.recipient AND pmi.type IN ('user', 'hidden')"); $count_query->condition($alias . '.tag_id', $tag); } } if (isset($filter['author']) && !empty($filter['author'])) { foreach ($filter['author'] as $author) { $alias = $query->join('pm_index', 'pmi', '%alias.mid = pm.mid'); $query->condition($alias . '.recipient', $author->uid); $query->condition($alias . '.type', 'user'); $alias = $count_query->join('pm_index', 'pmi', '%alias.mid = pm.mid'); $count_query->condition($alias . '.recipient', $author->uid); $count_query->condition($alias . '.type', 'user'); } } if (!empty($filter['search'])) { if (variable_get('privatemsg_filter_searchbody', FALSE)) { $search = db_or() ->condition('pm.subject', '%' . $filter['search'] . '%', 'LIKE') ->condition('pm.body', '%' . $filter['search'] . '%', 'LIKE'); // Clone the condition so that they are both compiled. $query->condition(clone $search); $count_query->condition($search); } else { $query->condition('pm.subject', '%'. $filter['search'] .'%', 'LIKE'); $count_query->condition('pm.subject', '%'. $filter['search'] .'%', 'LIKE'); } } } } /** * Implements hook_privatemsg_view_alter(). */ function privatemsg_filter_privatemsg_view_alter(&$content) { if (privatemsg_user_access('tag private messages')) { $content['tags'] = privatemsg_filter_show_tags($content['#thread']['thread_id'], !empty($_GET['show_tags_form'])); } } function privatemsg_filter_show_tags($thread_id, $show_form) { global $user; drupal_add_css(drupal_get_path('module', 'privatemsg_filter') . '/privatemsg_filter.css'); $element = array( '#prefix' => '
', '#weight' => -10, ); if (!$show_form) { $query = _privatemsg_assemble_query(array('tags', 'privatemsg_filter'), $user, array($thread_id)); if ($query->countQuery()->execute()->fetchField() == 0) { $element['link'] = array( '#type' => 'link', '#href' => $_GET['q'], '#options' => array( 'query' => array('show_tags_form' => TRUE), 'attributes' => array('class' => array('privatemsg-filter-tags-add')), ), '#title' => t('Tag this conversation'), ); } else { $element['label'] = array( '#prefix' => ' ', '#markup' => t('Tags:'), ); foreach ($query->execute()->fetchCol(1) as $tag) { $element['tags'][] = array( '#type' => 'link', '#title' => $tag, '#href' => 'messages', '#options' => array( 'attributes' => array('title' => $tag), 'query' => array('tags' => $tag), ), ); } $element['link'] = array( '#type' => 'link', '#href' => $_GET['q'], '#options' => array( 'query' => array('show_tags_form' => TRUE), 'attributes' => array('class' => array('privatemsg-filter-tags-modify')), ), '#title' => t('(modify tags)'), ); } return $element; } else { return drupal_get_form('privatemsg_filter_form', $thread_id) + $element; } } /** * Form to show and allow modification of tagging information for a conversation. */ function privatemsg_filter_form($form, &$form_state, $thread_id) { global $user; // Get a list of current tags for this thread $query = _privatemsg_assemble_query(array('tags', 'privatemsg_filter'), $user, array($thread_id)); $count = $query->countQuery()->execute()->fetchField(); $tags = implode(', ', $query->execute()->fetchCol(1)); $form['user_id'] = array( '#type' => 'value', '#value' => $user->uid, ); $form['thread_id'] = array( '#type' => 'value', '#value' => $thread_id, ); $form['tags'] = array( '#type' => 'textfield', '#title' => t('Tags for this conversation'), '#title_display' => 'invisible', '#size' => 30, '#default_value' => $tags, '#autocomplete_path' => 'messages/filter/tag-autocomplete', ); $form['modify_tags'] = array( '#type' => 'submit', '#value' => t('Tag this conversation'), ); $form['cancel'] = array( '#type' => 'link', '#href' => $_GET['q'], '#title' => t('Cancel'), '#attributes' => array('id' => 'privatemsg-filter-tags-cancel'), '#weight' => 50, ); return $form; } /** * Form builder function, display a form to modify tags on a thread. */ function privatemsg_filter_form_submit($form, &$form_state) { $tags = explode(',', $form_state['values']['tags']); // Step 1 - Delete all tag mapping. privatemsg_filter_remove_tags($form_state['values']['thread_id']); // Step 2 - Get the id for each of the tags. $tag_ids = privatemsg_filter_create_tags($tags); // Step 3 - Save all the tagging data. foreach ($tag_ids as $tag_id) { privatemsg_filter_add_tags($form_state['values']['thread_id'], $tag_id); } drupal_set_message(t('Your conversation tags have been saved.')); } /** * Limit the user autocomplete for the filter widget. */ function privatemsg_filter_query_privatemsg_autocomplete_alter($query) { global $user; if (arg(1) == 'filter') { $query->join('pm_index', 'pip', "pip.recipient = u.uid AND pip.type = 'user'"); $query->join('pm_index', 'piu', "piu.recipient = :uid_index AND piu.type = 'user' AND pip.mid = piu.mid", array(':uid_index' => $user->uid)); } } /** * Query definition to get the tags in use by the specified user. * * @param $user * User object for whom we want the tags. * @param $threads * Array of thread ids, defaults to all threads of a user. * @param $limit * Limit the number of tags *per thread*. */ function privatemsg_filter_sql_tags($user = NULL, $threads = NULL, $limit = NULL, $showHidden = FALSE) { $query = db_select('pm_tags', 't') ->fields('t', array('tag_id', 'tag', 'public')) ->orderBy('t.tag', 'ASC'); if (!empty($threads)) { $query->addField('ti', 'thread_id'); $query->join('pm_tags_index', 'ti', 'ti.tag_id = t.tag_id'); $query->condition('ti.thread_id', $threads); } else { $query->addExpression('COUNT(ti.thread_id)', 'count'); $query->leftJoin('pm_tags_index', 'ti', 'ti.tag_id = t.tag_id'); $query ->groupBy('t.tag_id') ->groupBy('t.tag') ->groupBy('t.public'); } if (!empty($user)) { $query->condition('ti.uid', $user->uid); } if (!$showHidden) { $query->condition(db_or()->condition('t.hidden', 0)->isNull('t.hidden')); } // Only select n tags per thread (ordered per tag_id), see // http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/. // // It does select how many tags for that thread/uid combination exist that // have a lower tag_id and does only select those that have less than $limit. // // This should only have a very minor performance impact as most users won't // tag a thread with 1000 different tags. if ($limit) { $query->where('(SELECT count(*) FROM {pm_tags_index} AS pmtic WHERE pmtic.thread_id = ti.thread_id AND pmtic.uid = ti.uid AND pmtic.tag_id < ti.tag_id) < :limit', array(':limit' => $limit)); } elseif (!empty($thread_id) || !empty($user)) { $query->orderBy('t.tag', 'ASC'); } return $query; } /** * Query definition to get autocomplete suggestions for tags * * @param $search * String fragment to use for tag suggestions. * @param $tags * Array of tags not to be used as suggestions. */ function privatemsg_filter_sql_tags_autocomplete($search, $tags) { $query = db_select('pm_tags', 'pmt') ->fields('pmt', array('tag')) ->condition('pmt.tag', $search . '%%', 'LIKE') ->orderBy('pmt.tag', 'ASC') ->range(0, 10); if (!empty($tags)) { $query->condition('pmt.tag', $tags, 'NOT IN'); } return $query; } /** * Implements hook_user_cancel(). */ function privatemsg_filter_user_cancel($edit, $account, $method) { // Always delete since this is only visible for the user anyway. db_delete('pm_tags_index') ->condition('uid', $account->uid) ->execute(); } /** * Implements hook_privatemsg_message_insert(). */ function privatemsg_filter_privatemsg_message_insert($message) { foreach ($message->recipients as $recipient) { if ($recipient->type == 'user' || $recipient->type == 'hidden') { privatemsg_filter_add_tags(array($message->thread_id), variable_get('privatemsg_filter_inbox_tag', ''), $recipient); } } } /** * Implements hook_privatemsg_message_recipient_changed(). */ function privatemsg_filter_privatemsg_message_recipient_changed($mid, $thread_id, $recipient, $type, $added) { if ($added && ($type == 'user' || $type == 'hidden')) { privatemsg_filter_add_tags(array($thread_id), variable_get('privatemsg_filter_inbox_tag', ''), (object)array('uid' => $recipient)); } }