diff --git a/privatemsg.module b/privatemsg.module index 35f6cd6606b4cd3fc8f7b1d6c585798d8709eea7..aa9a438a0a19c3686180845312c08410c961444f 100644 --- a/privatemsg.module +++ b/privatemsg.module @@ -2123,37 +2123,55 @@ function privatemsg_list_submit($form, &$form_state) { $operation = $operations[$keys[1]]; } + // Only execute something if we have a valid callback and at least one checked thread. + if (!empty($operation['callback'])) { + privatemsg_operation_execute($operation, $form_state['values']['threads']); + } +} + +/** + * Execute an operation on a number of threads. + * + * @param $operation + * The operation that should be executed. + * @see hook_privatemsg_thread_operations() + * @param $threads + * An array of thread ids. The array is filtered before used, a checkboxes + * array can be directly passed to it. + */ +function privatemsg_operation_execute($operation, $threads) { // Filter out unchecked threads, this gives us an array of "checked" threads. - $threads = array_filter($form_state['values']['threads']); + $threads = array_filter($threads); + + if (empty($threads)) { + // Do not execute anything if there are no checked threads. + return; + } + // Add in callback arguments if present. + if (isset($operation['callback arguments'])) { + $args = array_merge(array($threads), $operation['callback arguments']); + } + else { + $args = array($threads); + } + // Execute the chosen action and pass the defined arguments. + call_user_func_array($operation['callback'], $args); - // Only execute something if we have a valid callback and atleast one checked thread. - if (!empty($operation['callback']) && !empty($threads)) { + // Check if that operation has defined an undo callback. + if (isset($operation['undo callback']) && $undo_function = $operation['undo callback']) { // Add in callback arguments if present. - if (isset($operation['callback arguments'])) { - $args = array_merge(array($threads), $operation['callback arguments']); + if (isset($operation['undo callback arguments'])) { + $undo_args = array_merge(array($threads), $operation['undo callback arguments']); } else { - $args = array($threads); - } - // Execute the chosen action and pass the defined arguments. - call_user_func_array($operation['callback'], $args); - - // Check if that operation has defined a undo callback - if (isset($operation['undo callback']) && $undo_function = $operation['undo callback']) { - // Add in callback arguments if present. - if (isset($operation['undo callback arguments'])) { - $undo_args = array_merge(array($threads), $operation['undo callback arguments']); - } - else { - $undo_args = array($threads); - } - // Store the undo callback in the session and display a "Undo" link. - // @todo: Provide a more flexible solution for such an undo action, operation defined string for example. - $_SESSION['privatemsg']['undo callback'] = array('function' => $undo_function, 'args' => $undo_args); - $undo = l(t('undone'), 'messages/undo/action', array('query' => drupal_get_destination())); - - drupal_set_message(t('The previous action can be !undo.', array('!undo' => $undo))); + $undo_args = array($threads); } + // Store the undo callback in the session and display a "Undo" link. + // @todo: Provide a more flexible solution for such an undo action, operation defined string for example. + $_SESSION['privatemsg']['undo callback'] = array('function' => $undo_function, 'args' => $undo_args); + $undo = url('messages/undo/action', array('query' => drupal_get_destination())); + + drupal_set_message(t('The previous action can be undone.', array('!undo' => $undo))); } } diff --git a/privatemsg_filter/privatemsg_filter.module b/privatemsg_filter/privatemsg_filter.module index 69ab2b7d75b8a6a03b52c29eb7d9abea20cec7f3..47190ce23a8a3b374fe7b0edc725c694634b91e4 100644 --- a/privatemsg_filter/privatemsg_filter.module +++ b/privatemsg_filter/privatemsg_filter.module @@ -120,6 +120,94 @@ function privatemsg_filter_settings_submit($form, &$form_state) { } } +/** + * 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_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)) { + // 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_id, $account = NULL) { + if (!is_array($threads)) { + $threads = array($threads); + } + if (empty($account)) { + global $user; + $account = drupal_clone($user); + } + + 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. + if (db_result(db_query('SELECT COUNT(*) FROM {pm_tags_index} WHERE tag_id = %d AND (uid = %d AND thread_id = %d)', $tag_id, $user->uid, $thread)) == 0) { + db_query('INSERT INTO {pm_tags_index} (tag_id, uid, thread_id) VALUES (%d, %d, %d)', $tag_id, $user->uid, $thread); + } + } +} + +/** + * 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_id = NULL, $account = NULL) { + if (!is_array($threads)) { + $threads = array($threads); + } + if (empty($account)) { + global $user; + $account = drupal_clone($user); + } + + if (is_null($tag_id)) { + //Delete all tag mapping. + foreach ($threads as $thread) { + db_query('DELETE FROM {pm_tags_index} WHERE uid = %d AND thread_id = %d', $account->uid, $thread); + } + } + else { + //Delete tag mapping for the specified tag. + foreach ($threads as $thread) { + db_query('DELETE FROM {pm_tags_index} WHERE uid = %d AND thread_id = %d AND tag_id = %d', $account->uid, $thread, $tag_id); + } + } +} + function privatemsg_filter_get_filter($account) { $filter = array(); if (isset($_GET['tags'])) { @@ -337,11 +425,76 @@ function privatemsg_filter_create_get_query($filter) * 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')) { $form += privatemsg_filter_dropdown($form_state, $form['#account']); } + + $tags = privatemsg_filter_get_tags_data($user); + if (privatemsg_user_access('filter private messages') && !empty($tags)) { + $options = array(); + $options[] = t('Apply Tag...'); + foreach ($tags as $tag_id => $tag) { + $options[$tag_id] = $tag; + } + $form['actions']['tag-add'] = array( + '#type' => 'select', + '#options' => $options, + '#default_value' => 0, + // Execute the submit button if a operation has been selected. + '#attributes' => array('onchange' => "$('#edit-tag-add-submit').click()"), + ); + $form['actions']['tag-add-submit'] = array( + '#type' => 'submit', + '#value' => t('Apply Tag'), + '#submit' => array('privatemsg_filter_add_tag_submit'), + '#attributes' => array('class' => 'privatemsg-action-button'), + ); + $options[0] = t('Remove Tag...'); + $form['actions']['tag-remove'] = array( + '#type' => 'select', + '#options' => $options, + '#default_value' => 0, + // Execute the submit button if a operation has been selected. + '#attributes' => array('onchange' => "$('#edit-tag-remove-submit').click()"), + ); + $form['actions']['tag-remove-submit'] = array( + '#type' => 'submit', + '#value' => t('Remove Tag'), + '#submit' => array('privatemsg_filter_remove_tag_submit'), + '#attributes' => array('class' => 'privatemsg-action-button'), + ); + } } +/** + * Form callback for adding a tag to threads. + */ +function privatemsg_filter_add_tag_submit($form, &$form_state) { + $operation = array( + 'callback' => 'privatemsg_filter_add_tags', + 'callback arguments' => array('tag_id' => $form_state['values']['tag-add']), + 'undo callback' => 'privatemsg_filter_remove_tags', + 'undo callback arguments' => array('tag_id' => $form_state['values']['tag-add']), + ); + drupal_set_message(t('The selected conversations have been tagged.')); + privatemsg_operation_execute($operation, $form_state['values']['threads']); +} + +/** + * 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']), + 'undo callback' => 'privatemsg_filter_add_tags', + 'undo callback arguments' => array('tag_id' => $form_state['values']['tag-remove']), + ); + drupal_set_message(t('The tag has been removed from the selected conversations.')); + privatemsg_operation_execute($operation, $form_state['values']['threads']); +} /** * Hook into the query builder to add the tagging info to the correct query @@ -459,34 +612,16 @@ function privatemsg_filter_form_submit($form, &$form_state) { $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)) { - // 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; - } - - // 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']); + 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_ids); } - drupal_set_message(t('Tagging information has been saved.')); + drupal_set_message(t('Tagging information has been saved.')); } }