Index: privatemsg_filter.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/privatemsg/privatemsg_filter/privatemsg_filter.install,v retrieving revision 1.1.2.2 diff -u -r1.1.2.2 privatemsg_filter.install --- privatemsg_filter.install 16 Apr 2009 20:10:35 -0000 1.1.2.2 +++ privatemsg_filter.install 24 Apr 2009 21:09:21 -0000 @@ -66,5 +66,13 @@ function privatemsg_filter_uninstall() { variable_del('privatemsg_filter_searchbody'); + variable_del('privatemsg_filter_tagfield_weight'); drupal_uninstall_schema('privatemsg_filter'); } + +function privatemsg_filter_update_6001() { + $ret = array(); +  $ret[] = update_sql("UPDATE {permission} SET perm = REPLACE(perm, 'use privatemsg_filter', 'filter private messages') WHERE perm LIKE '%use privatemsg_filter%'"); +  $ret[] = update_sql("UPDATE {permission} SET perm = REPLACE(perm, 'create privatemsg_filter', 'create private message tags') WHERE perm LIKE '%create privatemsg_filter%'"); + return $ret; +} \ No newline at end of file Index: privatemsg_filter.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/privatemsg/privatemsg_filter/privatemsg_filter.module,v retrieving revision 1.1.2.15 diff -u -r1.1.2.15 privatemsg_filter.module --- privatemsg_filter.module 22 Apr 2009 02:23:45 -0000 1.1.2.15 +++ privatemsg_filter.module 24 Apr 2009 21:14:32 -0000 @@ -11,9 +11,9 @@ */ function privatemsg_filter_perm() { return array( - 'use privatemsg_filter', - 'create privatemsg_filter', - 'delete privatemsg_filter', + 'filter private messages', + 'tag private messages', + 'create private message tags', ); } @@ -21,13 +21,6 @@ * Implementation of hook_menu(). */ function privatemsg_filter_menu() { - $items['messages/tags'] = array( - 'title' => 'Tags', - 'page callback' => 'privatemsg_filter_page', - 'access callback' => 'privatemsg_user_access', - 'access arguments' => array('use privatemsg_filter'), - 'type' => MENU_LOCAL_TASK, - ); $items['admin/settings/messages/filter'] = array( 'title' => 'Filter', 'description' => 'Configure filter settings.', @@ -60,6 +53,13 @@ 'type' => MENU_LOCAL_TASK, 'weight' => -10, ); + $items['messages/filter/tag-autocomplete'] = array( + 'page callback' => 'privatemsg_filter_tags_autocomplete', + 'access callback' => 'privatemsg_user_access', + 'access arguments' => array('filter private messages'), + 'type' => MENU_CALLBACK, + 'weight' => -10, + ); return $items; } @@ -72,138 +72,24 @@ '#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), ); - - return system_settings_form($form); -} - -function privatemsg_filter_page() { - $content = ''; - drupal_set_title(t('Tags')); - - $sql = 'SELECT * FROM {pm_tags}'; - $query = db_query($sql); - $tag_array = array(); - - while ($result = db_fetch_object($query)) { - $tag_array[] = l($result->tag, 'messages', array('query' => 'tags='. $result->tag)); - } - if (count($tag_array)) { - $content .= '

'. t('Current tags:') .'

'; - $content .= implode(', ', $tag_array) .'.'; - } - - if (privatemsg_user_access('create privatemsg_filter')) { - $content .= drupal_get_form('privatemsg_filter_add_tags'); - } - if (privatemsg_user_access('delete privatemsg_filter')) { - $content .= drupal_get_form('privatemsg_filter_delete_tags'); - } - - return $content; -} - -/** - * Add new tags - */ -function privatemsg_filter_add_tags($form_state) { - $form['addtags'] = array( - '#type' => 'fieldset', - '#title' => t('Add tags'), - '#collapsible' => TRUE, - '#collapsed' => FALSE, - ); - - $form['addtags']['newtags'] = array( - '#type' => 'textfield', - '#title' => t('What tags would you like to add?'), - '#description' => t('Please insert a comma separated list of new tags in the form of "tag1, tag2, tag3...". All spaces will be replaced by hyphens.'), - '#default_value' => '', - '#required' => 1, - ); - - $form['addtags']['submit'] = array( - '#type' => 'submit', - '#value' => t('Add tags'), - ); - - - return $form; -} - -function privatemsg_filter_add_tags_submit($form, &$form_state) { - - if (isset($form_state['values']['submit'])) { - $tags = explode(',', $form_state['values']['newtags']); - - foreach ($tags as $tag) { - $tag = trim($tag); - $tag = str_replace(' ', '-', $tag); - $count = db_result(db_query("SELECT COUNT(*) FROM {pm_tags} WHERE tag = '%s'", $tag)); - if ($count == 0) { - db_query("INSERT INTO {pm_tags} (tag) VALUES ('%s')", $tag); - $inserted[] = $tag; - } - } - } - if (count($inserted)) { - drupal_set_message(t('!count tags have been saved: !tags.', array('!count' => count($inserted), '!tags' => implode(', ', $inserted)))); - } -} - -/** - * Delete existing tags - */ -function privatemsg_filter_delete_tags($form_state) { - - $form['deletetags'] = array( - '#type' => 'fieldset', - '#title' => t('Delete tags'), - '#collapsible' => TRUE, - '#collapsed' => TRUE, - ); - - $sql = 'SELECT * FROM {pm_tags}'; - $query = db_query($sql); - $tag_array = array(); - - while ($result = db_fetch_object($query)) { - $checked = 0; - $form_data = array('#type' => 'checkbox', '#title' => $result->tag, '#default_value' => $checked, '#return_value' => 1); - $form['deletetags']['tag_'. $result->tag_id] = $form_data; - } - - $form['deletetags']['submit'] = array( - '#type' => 'submit', - '#value' => t('Delete selected tags'), + + $form['privatemsg_filter_tagfield_weight'] = array( + '#type' => 'textfield', + '#title' => t('Position of the tagging textfield'), + '#description' => t('Use higher values to push the form lower down the page, lower or negative values to raise it higher.'), + '#size' => 4, + '#default_value' => variable_get('privatemsg_filter_tagfield_weight', 10), ); - return $form; - -} - -function privatemsg_filter_delete_tags_submit($form, &$form_state) { - if (isset($form_state['values']['submit'])) { - $sql = 'SELECT * FROM {pm_tags}'; - $query = db_query($sql); - - while ($result = db_fetch_object($query)) { - if ($form_state['values']['tag_'. $result->tag_id] == 1) { - db_query('DELETE FROM {pm_tags_index} WHERE tag_id = %d', $result->tag_id); - db_query('DELETE FROM {pm_tags} WHERE tag_id = %d', $result->tag_id); - $deleted[] = $result->tag; - } - } - } - if (count($deleted)) { - drupal_set_message(t('!count tags have been deleted: !tags.', array('!count' => count($deleted), '!tags' => implode(', ', $deleted)))); - } + return system_settings_form($form); } function privatemsg_filter_get_filter($account) { $filter = array(); if (isset($_GET['tags'])) { + $_GET['tags'] = urldecode($_GET['tags']); $tag_data = privatemsg_filter_get_tags_data($account); - foreach (explode(' ', $_GET['tags']) as $tag) { + foreach (explode(',', $_GET['tags']) as $tag) { if (isset($tag_data[$tag])) { $filter['tags'][$tag] = $tag; } @@ -263,11 +149,11 @@ } // Only show the tags that a user has used. - $sql = 'SELECT pmt.tag, pmt.tag_id FROM {pm_tags_index} pmti LEFT JOIN {pm_tags} pmt ON pmti.tag_id = pmt.tag_id WHERE pmti.uid = %d GROUP BY pmt.tag_id, pmt.tag'; - $query = db_query($sql, $account->uid); + $query = _privatemsg_assemble_query(array('used_tags', 'privatemsg_filter'), $account); + $results = db_query($query['query']); $tag_data = array(); - while ($result = db_fetch_object($query)) { + while ($result = db_fetch_object($results)) { $tag_data[$result->tag_id] = $result->tag; } return $tag_data; @@ -402,7 +288,7 @@ } if (isset($query['tags'])) { - $query['tags'] = implode(' ', $query['tags']); + $query['tags'] = implode(',', $query['tags']); } } @@ -431,7 +317,7 @@ * Implementation of hook_form_alter(). */ function privatemsg_filter_form_privatemsg_list_alter(&$form, $form_state) { - if (privatemsg_user_access('use privatemsg_filter')) { + if (privatemsg_user_access('filter private messages')) { $form += privatemsg_filter_dropdown($form_state, $form['#account']); } } @@ -489,9 +375,9 @@ } function privatemsg_filter_privatemsg_view_messages_alter(&$content, $thread) { - if (count($thread['messages']) > 0 && db_result(db_query('SELECT COUNT(*) FROM {pm_tags}')) > 0) { + if (count($thread['messages']) > 0) { $content['tags']['#value'] = drupal_get_form('privatemsg_filter_form'); - $content['tags']['#weight'] = 10; + $content['tags']['#weight'] = variable_get('privatemsg_filter_tagfield_weight', 10); } } @@ -499,11 +385,21 @@ global $user; $thread_id = arg(2); + // Get a list of current tags for this thread + $query = _privatemsg_assemble_query(array('used_tags', 'privatemsg_filter'), $user, $thread_id); + $results = db_query($query['query']); + $count = db_result(db_query($query['count'])); + $tags = ''; + while ($tag = db_fetch_array($results)) { + $tags .= $tag['tag']. ', '; + } + $form['tags'] = array( '#type' => 'fieldset', '#title' => t('Tags'), + '#access' => privatemsg_user_access('tag private messages'), '#collapsible' => TRUE, - '#collapsed' => TRUE, + '#collapsed' => empty($count) ? TRUE : FALSE, ); $form['tags']['user_id'] = array( '#type' => 'value', @@ -513,19 +409,15 @@ '#type' => 'value', '#value' => $thread_id, ); - - $sql = 'SELECT * FROM {pm_tags}'; - $query = db_query($sql); - $tag_array = array(); - - while ($result = db_fetch_object($query)) { - $checked = 0; - if (db_result(db_query('SELECT COUNT(*) FROM {pm_tags_index} WHERE tag_id = %d AND (uid = %d AND thread_id = %d)', $result->tag_id, $user->uid, $thread_id))) { - $checked = 1; - } - $form_data = array('#type' => 'checkbox', '#title' => $result->tag, '#default_value' => $checked, '#return_value' => 1); - $form['tags']['tag_'. $result->tag_id] = $form_data; - } + + $form['tags']['tags'] = array( + '#type' => 'textfield', + '#title' => t('Tags for this conversation'), + '#description' => t('Separate multiple tags with commas.'), + '#size' => 50, + '#default_value' => $tags, + '#autocomplete_path' => 'messages/filter/tag-autocomplete', + ); $form['tags']['submit'] = array( '#type' => 'submit', @@ -538,17 +430,93 @@ function privatemsg_filter_form_submit($form, &$form_state) { if (isset($form_state['values']['submit'])) { - $sql = 'SELECT * FROM {pm_tags}'; - $query = db_query($sql); - - while ($result = db_fetch_object($query)) { - if ($form_state['values']['tag_'. $result->tag_id] == 0) { - db_query('DELETE FROM {pm_tags_index} WHERE tag_id = %d AND (uid = %d AND thread_id = %d)', $result->tag_id, $form_state['values']['user_id'], $form_state['values']['thread_id']); - } - elseif (db_result(db_query('SELECT COUNT(*) FROM {pm_tags_index} WHERE tag_id = %d AND (uid = %d AND thread_id = %d)', $result->tag_id, $form_state['values']['user_id'], $form_state['values']['thread_id'])) == 0) { - db_query('INSERT INTO {pm_tags_index} (tag_id, uid, thread_id) VALUES (%d, %d, %d)', $result->tag_id, $form_state['values']['user_id'], $form_state['values']['thread_id']); + $tags = explode(',', $form_state['values']['tags']); + + // Step 1 - Delete all tag mapping. I cannot think of a better way to remove tags that are no longer in the textfield, so ideas welcome. + db_query('DELETE FROM {pm_tags_index} WHERE uid = %d AND thread_id = %d', $form_state['values']['user_id'], $form_state['values']['thread_id']); + + foreach ($tags as $tag) { + // Step 2 - We need to sanitise the tag. + // Since we allow tags to be passed via the url, there needs to be some sanity testing of each tag. + // Currently we replace blank spaces and a # with a "-", but this needs to be expanded to cover all the url special cases. + $tag = trim($tag); + if (empty($tag)) { + // Do not save a blank tag. + continue; + } + + // Step 3 - Make sure that the tag exists and if it does not, we need to create it. + $tag_id = db_result(db_query("SELECT tag_id FROM {pm_tags} WHERE tag = '%s'", $tag)); + if (empty($tag_id) && privatemsg_user_access('create private message tags')) { + db_query("INSERT INTO {pm_tags} (tag) VALUES ('%s')", $tag); + $tag_id = db_last_insert_id('pm_tags', 'tag_id'); } + elseif (empty($tag_id)) { + drupal_set_message(t('Tag %tag was ignored because you do not have permission to create new tags.', array('%tag' => $tag))); + continue; + } + + // Step 4 - map the tag to the thread and the user. + db_query('INSERT INTO {pm_tags_index} (tag_id, uid, thread_id) VALUES (%d, %d, %d)', $tag_id, $form_state['values']['user_id'], $form_state['values']['thread_id']); } - drupal_set_message(t('Tagging information has been saved.')); + + drupal_set_message(t('Tagging information has been saved.')); + } +} + +/** + * Return autocomplete results for tags. + * + * Most of this code has been lifted/modified from privatemsg_user_name_autocomplete(). + */ +function privatemsg_filter_tags_autocomplete($string) { + $tags = array(); + // 1: Parse $string and build a list of tags. + $fragments = explode(',', $string); + foreach ($fragments as $index => $tag) { + $tag = trim($tag); + $tags[$tag] = $tag; + } + + // 2: Find the next tag suggestion. + $fragment = array_pop($tags); + $matches = array(); + if (!empty($fragment)) { + $query = _privatemsg_assemble_query(array('tags_autocomplete', 'privatemsg_filter'), $fragment, $tags); + $result = db_query_range($query['query'], $fragment, 0, 10); + $prefix = count($tags) ? implode(", ", $tags) .", " : ''; + // 3: Build proper suggestions and print. + while ($tag = db_fetch_object($result)) { + $matches[$prefix . $tag->tag .", "] = $tag->tag; + } + } + // convert to object to prevent drupal bug, see http://drupal.org/node/175361 + drupal_json((object)$matches); +} + +function privatemsg_filter_sql_used_tags(&$fragments, $user, $thread_id = NULL) { + $fragments['primary_table'] = '{pm_tags} t'; + $fragments['select'][] = 't.tag'; + $fragments['select'][] = 't.tag_id'; + $fragments['inner_join'][] = 'INNER JOIN {pm_tags_index} ti on ti.tag_id = t.tag_id'; + if (!empty($thread_id)) { + $fragments['where'][] = 'ti.thread_id = %d'; + $fragments['query_args']['where'][] = $thread_id; + } + $fragments['where'][] = 'ti.uid = %d'; + $fragments['query_args']['where'][] = $user->uid; + + $fragments['order_by'][] = 't.tag ASC'; +} + +function privatemsg_filter_sql_tags_autocomplete(&$fragments, $search, $tags) { + $fragments['primary_table'] = '{pm_tags} pmt'; + $fragments['select'][] = 'pmt.tag'; + $fragments['where'][] = "pmt.tag LIKE '%s'"; + $fragments['query_args']['where'][] = $search .'%%'; + if (!empty($tags)) { + $fragments['where'][] = "pmt.tag NOT IN (". db_placeholders($tags, 'text') .")"; + $fragments['query_args']['where'] += $tags; } + $fragments['order_by'][] = 'pmt.tag ASC'; } \ No newline at end of file