privatemsg_filter.module in Privatemsg 7
Same filename and directory in other branches
Allows users to tag private messages and to filter based upon those tags.
File
privatemsg_filter/privatemsg_filter.moduleView source
<?php
/**
* @file
* Allows users to tag private messages and to filter based upon those tags.
*/
/**
* Implements hook_permission().
*/
function privatemsg_filter_permission() {
return array(
'filter private messages' => 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'),
),
);
}
/**
* Implements 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;
}
}
/**
* Implements 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. <a href="@remove_filter_url">Click here to remove this filter</a>.', 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_obj, 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;
}
/**
* Implements 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) {
$tags[] = l(drupal_strlen($tag) > 15 ? drupal_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' => '<div id="privatemsg-filter-tags">',
'#suffix' => '</div>',
'#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' => '<span class="privatemsg-filter-tags-label">',
'#suffix' => '</span>',
'#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,
));
$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);
}
$form_state['redirect'] = current_path();
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,
));
}
}