summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThe Great Git Migration2008-12-15 16:53:35 (GMT)
committer The Great Git Migration2008-12-15 16:53:35 (GMT)
commit67189554c76cc15f464f2e0f3935528365938bed (patch)
tree8a13b215b8cfd89d88e0c2d86598d6aeeb1c5151
parent2438324b4ba3158c0fc614a4e0baa1b8968499e7 (diff)
This commit was manufactured as part of Drupal's Great Git Migration to6.x-1.0-rc1
create branch 'DRUPAL-6--1'. Cherrypick from master 2008-12-15 16:53:34 UTC Oleg Terenchuk <litwol@gmail.com> '#339565 by litwol: Fixed count query argument replacement': pm_block_user/pm_block_user.info pm_block_user/pm_block_user.install pm_block_user/pm_block_user.module privatemsg.test privatemsg_filter/privatemsg_filter.css privatemsg_filter/privatemsg_filter.info privatemsg_filter/privatemsg_filter.install privatemsg_filter/privatemsg_filter.module privatemsgapi/privatemsgapi.inc styles/privatemsg-list.css
-rwxr-xr-xpm_block_user/pm_block_user.info8
-rwxr-xr-xpm_block_user/pm_block_user.install34
-rwxr-xr-xpm_block_user/pm_block_user.module119
-rw-r--r--privatemsg.test134
-rw-r--r--privatemsg_filter/privatemsg_filter.css9
-rw-r--r--privatemsg_filter/privatemsg_filter.info8
-rw-r--r--privatemsg_filter/privatemsg_filter.install69
-rw-r--r--privatemsg_filter/privatemsg_filter.module489
-rw-r--r--privatemsgapi/privatemsgapi.inc160
-rw-r--r--styles/privatemsg-list.css3
10 files changed, 1033 insertions, 0 deletions
diff --git a/pm_block_user/pm_block_user.info b/pm_block_user/pm_block_user.info
new file mode 100755
index 0000000..6df1c65
--- /dev/null
+++ b/pm_block_user/pm_block_user.info
@@ -0,0 +1,8 @@
+; $Id$
+name = Block user messages
+description = Allows users to block other users from sending them messages.
+version = VERSION
+package = Mail
+core = 6.x
+dependencies[] = privatemsg
+
diff --git a/pm_block_user/pm_block_user.install b/pm_block_user/pm_block_user.install
new file mode 100755
index 0000000..28fb190
--- /dev/null
+++ b/pm_block_user/pm_block_user.install
@@ -0,0 +1,34 @@
+<?php
+// $Id$
+
+function pm_block_user_schema() {
+ $schema = array();
+
+ $schema['pm_block_user'] = array(
+ 'description' => t('{pm_block_user} holds data mapping which authors who cannot messages to which recipients '),
+ 'fields' => array(
+ 'author' => array(
+ 'description' => t('ID of the author'),
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'unsigned' => TRUE,
+ ),
+ 'recipient' => array(
+ 'description' => t('ID of the recipient'),
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'unsigned' => TRUE,
+ ),
+ ),
+ );
+
+ return $schema;
+}
+function pm_block_user_install() {
+ drupal_install_schema('pm_block_user');
+
+}
+
+function pm_block_user_uninstall() {
+ drupal_uninstall_schema('pm_block_user');
+}
diff --git a/pm_block_user/pm_block_user.module b/pm_block_user/pm_block_user.module
new file mode 100755
index 0000000..036d71f
--- /dev/null
+++ b/pm_block_user/pm_block_user.module
@@ -0,0 +1,119 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Allows users to block other users from sending them any messages
+ */
+
+/**
+ * Implementation of hook_menu().
+ */
+function pm_block_user_menu() {
+ $items['messages/block/%user'] = array(
+ 'title' => 'Block user messages',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('pm_block_user_form', 2),
+ 'access arguments' => array('read privatemsg'),
+ 'type' => MENU_CALLBACK,
+ 'weight' => -10,
+ );
+ return $items;
+}
+
+function pm_block_user_form($form_state, $author) {
+ global $user;
+
+ $form['author'] = array(
+ '#type' => 'value',
+ '#value' => $author->uid,
+ );
+ $form['recipient'] = array(
+ '#type' => 'value',
+ '#value' => $user->uid,
+ );
+ $form['author_name'] = array(
+ '#type' => 'value',
+ '#value' => $author->name,
+ );
+ $form['destination'] = array(
+ '#type' => 'value',
+ '#value' => isset($_GET['destination']) ? $_GET['destination'] : 'messages/',
+ );
+
+ if (db_result(db_query('SELECT COUNT(recipient) FROM {pm_block_user} WHERE author = %d AND recipient = %d', $author->uid, $user->uid))) {
+ $form['block_action'] = array(
+ '#type' => 'value',
+ '#value' => 'unblock_user',
+ );
+ return confirm_form($form,
+ t('You have previously blocked "@author" from sending you any more messages. Are you sure you want to unblock this user?', array('@author' => $author->name)),
+ isset($_GET['destination']) ? $_GET['destination'] : 'messages/',
+ t('This action cannot be undone.'),
+ t('Unblock @author', array('@author' => $author->name)),
+ t('Cancel')
+ );
+ }
+ else {
+ $form['block_action'] = array(
+ '#type' => 'value',
+ '#value' => 'block_user',
+ );
+ return confirm_form($form,
+ t('Are you sure you want to block "@author" from sending you any more messages?', array('@author' => $author->name)),
+ isset($_GET['destination']) ? $_GET['destination'] : 'messages/',
+ t('This action cannot be undone.'),
+ t('Block @author', array('@author' => $author->name)),
+ t('Cancel')
+ );
+ }
+}
+
+function pm_block_user_form_submit($form, &$form_state) {
+
+ if ($form_state['values']['confirm']) {
+ switch ($form_state['values']['block_action']) {
+ case 'block_user':
+ db_query('INSERT INTO {pm_block_user} (author, recipient) VALUES (%d, %d)', $form_state['values']['author'], $form_state['values']['recipient']);
+ drupal_set_message(t('@author has been blocked from sending you any further messages.', array('@author' => $form_state['values']['author_name'])));
+ break;
+ case 'unblock_user':
+ db_query('DELETE FROM {pm_block_user} WHERE author = %d AND recipient = %d', $form_state['values']['author'], $form_state['values']['recipient']);
+ drupal_set_message(t('@author is now allowed to send you new messages.', array('@author' => $form_state['values']['author_name'])));
+ break;
+ }
+ }
+ $form_state['redirect'] = $form_state['values']['destination'];
+}
+
+/**
+ * Implementation of hook_privatemsg_block_message.
+ */
+ function pm_block_user_privatemsg_block_message($author, $recipient) {
+ global $user;
+ $result = db_result(db_query('SELECT COUNT(*) FROM {pm_block_user} WHERE author = %d AND recipient = %d', $author->uid, $recipient->uid));
+ if ($result <> 0) {
+ return t('!name has chosen to not recieve any more messages from you.', array('!name' => $recipient->name));
+ }
+}
+
+/**
+ * Implementation of hook_privatemsg_pm_controls.
+ */
+ function pm_block_user_privatemsg_pm_controls($pmid) {
+ global $user;
+ $author_id = db_result(db_query('SELECT author FROM {pm_message} WHERE mid = %d', $pmid));
+ $thread = db_result(db_query('SELECT thread_id FROM {pm_index} WHERE mid = %d', $pmid));
+
+ if ($user->uid <> $author_id) {
+ if (db_result(db_query('SELECT COUNT(recipient) FROM {pm_block_user} WHERE author = %d AND recipient = %d', $author_id, $user->uid))) {
+ $output = l(t('Unblock author'), 'messages/block/'. $author_id, array('query' => 'destination=messages/view/' . $thread));
+ }
+ else {
+ $output = l(t('Block author'), 'messages/block/'. $author_id, array('query' => 'destination=messages/view/' . $thread));
+ }
+ }
+ if (isset($output)) {
+ return $output;
+ }
+} \ No newline at end of file
diff --git a/privatemsg.test b/privatemsg.test
new file mode 100644
index 0000000..ec5c2d8
--- /dev/null
+++ b/privatemsg.test
@@ -0,0 +1,134 @@
+<?php
+//$Id$
+
+class PrivatemsgTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ // 'name' should start with what is being tested (menu item) followed by what about it
+ // is being tested (creation/deletion).
+ 'name' => t('Privatemsg functionality.'),
+ // 'description' should be one or more complete sentences that provide more details on what
+ // exactly is being tested.
+ 'description' => t('Test sending, receiving, listing, deleting messages and other features.'),
+ // 'group' should be a logical grouping of test cases, like a category. In most cases, that
+ // is the module the test case is for.
+ 'group' => t('Privatemsg'),
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ function setUp() {
+ parent::setUp('privatemsg');
+ }
+
+ /**
+ * Test user access to /messages
+ * Create user with no 'read privatemsg' permission. Try to access mailbox and see if it gives access denied error
+ * Create user with 'read privatemsg' permission. Try to access mailbox and see if it gives allows access
+ */
+ function testPrivatemsgReadPrivatemsgPermission() {
+ $user_no_read_msg = $this->drupalCreateUser(); // set up user with default permissions (meaning: no read privatemsg permission
+ $this->drupalLogin($user_no_read_msg);
+ $this->drupalGet('messages');
+ $this->assertResponse(403, t('HTTP Response 403: Access to mailbox was blocked to user without "<em>read privatemsg</em>" permission'));
+
+ $user_read_msg = $this->drupalCreateUser(array('read privatemsg')); // set up user with default permissions (meaning: no read privatemsg permission
+ $this->drupalLogin($user_read_msg);
+ $this->drupalGet('messages');
+ $this->assertResponse(200, t('HTTP Response 200: Access to mailbox was authorized to user with "<em>read privatemsg</em>" permission'));
+ }
+ /**
+ * Test user access to /messages/new
+ * Create user with no 'write privatemsg' permission. Try to access Write New Message page and see if it gives access denied error
+ * Create user with 'write privatemsg' permission. Try to access Write New Message page and see if it gives allows access
+ */
+ function testPrivatemsgWritePrivatemsgPermission() {
+ $user_no_write_msg = $this->drupalCreateUser(); // set up user with default permissions (meaning: no read privatemsg permission
+ $this->drupalLogin($user_no_write_msg);
+ $this->drupalGet('messages/new');
+ $this->assertResponse(403, t('HTTP Response 403: Access to Write New Message page was blocked to user without "<em>write privatemsg</em>" permission'));
+
+ $user_write_msg = $this->drupalCreateUser(array('write privatemsg')); // set up user with default permissions (meaning: no read privatemsg permission
+ $this->drupalLogin($user_write_msg);
+ $this->drupalGet('messages/new');
+ $this->assertResponse(200, t('HTTP Response 200: Access to Write New Message page was authorized to user with "<em>write privatemsg</em>" permission'));
+ }
+
+ /**
+ * Test sending message from the /messages/new page between two people
+ */
+ function testPrivatemsgWriteNewPrivatemsgFormSubmit() {
+ /**
+ * create an author and recipient users
+ */
+ $author = $this->drupalCreateUser(array('write privatemsg'));
+ $recipient = $this->drupalCreateUser(array('read privatemsg'));
+
+ /**
+ * login using author
+ * Fill navigate to privatemsg/new form, fill it out and submit
+ */
+ $this->drupalLogin($author);
+ $this->drupalGet('messages/new');
+
+ //assert if form is present //submit the form only if we found it
+ $xpath = '//form[@id="privatemsg-new"]';
+ if ( $this->assertTrue($this->xpath($xpath), 'Write New Message form successfuly found.', 'privatemsg') ) {
+ $edit = array( //create new message
+ 'recipient' => $recipient->name,
+ 'subject' => $this->randomName(20),
+ 'body' => $this->randomName(100),
+ );
+ //submit our message
+ $this->drupalPost('messages/new', $edit, t('Send message'));
+ //check if we got successful confirmation
+ if ( $this->assertText(t('A message has been sent to @recipients.', array('@recipients' => $recipient->name)), 'Message sent confirmation displayed', 'privatemsg') ) {
+ /**
+ * Login using recipient and try to read the message by going to inbox first
+ * We do the test inside this conditional block because sending messages test much pass before we proceed to reading messages
+ */
+ $this->drupalLogin($recipient);
+ $this->drupalGet('messages');
+
+ //assert if we see the subject of the message
+ if ( $this->assertText(t('@text', array('@text' => $edit['subject'])), 'Sent Message subject found.', 'privatemsg') ) {
+ $this->clickLink(t('@text', array('@text' => $edit['subject']))); //navigate into the message
+ $this->assertText($edit['body'], 'Found Message body.', 'privatemsg'); //confirm that we can read the message that was sent
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Implementation of tearDown().
+ */
+ function tearDown() {
+ //we dont really need to do this. i'm adding it just to keep it in front of my eyes so i can memorize it.
+ parent::tearDown();
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/privatemsg_filter/privatemsg_filter.css b/privatemsg_filter/privatemsg_filter.css
new file mode 100644
index 0000000..a866826
--- /dev/null
+++ b/privatemsg_filter/privatemsg_filter.css
@@ -0,0 +1,9 @@
+
+form#privatemsg-filter-dropdown #edit-author-wrapper, form#privatemsg-filter-dropdown #edit-tags-wrapper {
+ float: left;
+ margin-right: 3em;
+}
+
+form#privatemsg-filter-dropdown #privatemsg-filter-buttons {
+ clear: left;
+} \ No newline at end of file
diff --git a/privatemsg_filter/privatemsg_filter.info b/privatemsg_filter/privatemsg_filter.info
new file mode 100644
index 0000000..e77dbc3
--- /dev/null
+++ b/privatemsg_filter/privatemsg_filter.info
@@ -0,0 +1,8 @@
+; $Id$
+name = Privatemsg filter
+description = Allow users to filter messages using tags or other criteria.
+version = HEAD
+package = Mail
+core = 6.x
+dependencies[] = privatemsg
+
diff --git a/privatemsg_filter/privatemsg_filter.install b/privatemsg_filter/privatemsg_filter.install
new file mode 100644
index 0000000..d8e8913
--- /dev/null
+++ b/privatemsg_filter/privatemsg_filter.install
@@ -0,0 +1,69 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * install file for privatemsg_filter
+ */
+
+
+function privatemsg_filter_schema() {
+ $schema = array();
+
+ $schema['pm_tags'] = array(
+ 'description' => t('{pm_tags} holds the names of tags and their id.'),
+ 'fields' => array(
+ 'tag_id' => array(
+ 'description' => t('Tag ID'),
+ 'type' => 'serial',
+ 'not null' => TRUE,
+ 'unsigned' => TRUE,
+ ),
+ 'tag' => array(
+ 'description' => t('The name of the tag'),
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ ),
+ ),
+ 'primary key' => array('tag_id')
+ );
+
+ $schema['pm_tags_index'] = array(
+ 'description' => t('{pm_tags_index} holds mapping information between tags, threads the users.'),
+ 'fields' => array(
+ 'tag_id' => array(
+ 'description' => t('Tag ID'),
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'unsigned' => TRUE,
+ ),
+ 'uid' => array(
+ 'description' => t('ID of the user'),
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'unsigned' => TRUE,
+ ),
+ 'thread_id' => array(
+ 'description' => t('id of the thread'),
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'unsigned' => TRUE,
+ ),
+ ),
+ 'primary key' => array('tag_id', 'uid', 'thread_id'),
+ 'indexes' => array(
+ 'uid' => array('uid'),
+ ),
+ );
+
+ return $schema;
+}
+function privatemsg_filter_install() {
+ drupal_install_schema('privatemsg_filter');
+
+}
+
+function privatemsg_filter_uninstall() {
+ drupal_uninstall_schema('privatemsg_filter');
+}
diff --git a/privatemsg_filter/privatemsg_filter.module b/privatemsg_filter/privatemsg_filter.module
new file mode 100644
index 0000000..2d83ab2
--- /dev/null
+++ b/privatemsg_filter/privatemsg_filter.module
@@ -0,0 +1,489 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Allows users to tag private messages and to filter based upon those tags.
+ */
+
+/**
+ * Implementation of hook_perm().
+ */
+function privatemsg_filter_perm() {
+ return array(
+ 'use privatemsg_filter',
+ 'create privatemsg_filter',
+ 'delete privatemsg_filter',
+ );
+}
+
+/**
+ * Implementation of hook_menu().
+ */
+function privatemsg_filter_menu() {
+ $items['messages/tags'] = array(
+ 'title' => 'Tags',
+ 'page callback' => 'privatemsg_filter_page',
+ 'access arguments' => array('use privatemsg_filter'),
+ 'type' => MENU_LOCAL_TASK,
+ );
+ return $items;
+}
+
+function privatemsg_filter_page() {
+ $content = '';
+ drupal_set_title('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 .= '<h2>'. t('Current tags:') .'</h2>';
+ $content .= implode(', ', $tag_array) .'.';
+ }
+
+ if (user_access('create privatemsg_filter')) {
+ $content .= drupal_get_form('privatemsg_filter_add_tags');
+ }
+ if (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'),
+ );
+
+ 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))));
+ }
+}
+
+function privatemsg_filter_get_filter($account) {
+ $filter = array();
+ if (isset($_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);
+ }
+ }
+ }
+
+ if (isset($_GET['author'])) {
+ foreach (explode(' ', $_GET['author']) as $author) {
+ $author_data = privatemsg_filter_get_author_data($account);
+ if (isset($author_data[$author])) {
+ $filter[$author] = $author;
+ }
+ elseif (in_array($author, $author_data)) {
+ $filter['author'][array_search($author, $author_data)] = array_search($author, $author_data);
+ }
+ }
+ }
+
+ 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_author_data($account) {
+ static $author_data;
+
+ if (is_array($author_data)) {
+ return $author_data;
+ }
+ $sql = 'SELECT DISTINCT pm.author, u.name FROM {pm_message} pm INNER JOIN pm_index pmi ON pm.mid = pmi.mid INNER JOIN {users} u ON pm.author = u.uid WHERE pmi.uid = %d AND u.uid > 0 ORDER BY u.name';
+ $query = db_query($sql, $account->uid);
+
+ $author_data = array();
+ while ($result = db_fetch_object($query)) {
+ $author_data[$result->author] = $result->name;
+ }
+ return $author_data;
+}
+
+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 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);
+
+ $tag_data = array();
+ while ($result = db_fetch_object($query)) {
+ $tag_data[$result->tag_id] = $result->tag;
+ }
+ return $tag_data;
+}
+
+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,
+ );
+ $form['filter']['search'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Search Subjects'),
+ '#weight' => -20
+ );
+
+ $form['filter']['author'] = array(
+ '#type' => 'select',
+ '#title' => t('Authors'),
+ '#options' => privatemsg_filter_get_author_data($account),
+ '#multiple' => TRUE,
+ '#size' => 5,
+ '#weight' => -10
+ );
+
+ // 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('Tags'),
+ '#options' => $tag_data,
+ '#multiple' => TRUE,
+ '#size' => 5,
+ '#weight' => 0
+ );
+ }
+ $form['filter']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Filter'),
+ '#prefix' => '<div id="privatemsg-filter-buttons">',
+ '#weight' => 10,
+ );
+
+ $form['filter']['save'] = array(
+ '#type' => 'submit',
+ '#value' => t('Save Filter'),
+ '#suffix' => '</div>',
+ '#weight' => 11,
+ );
+
+ if ($filter = privatemsg_filter_get_filter($account)) {
+ 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'])) {
+ $form['filter']['author']['#default_value'] = $filter['author'];
+ }
+ if (isset($filter['tags'])) {
+ $form['filter']['tags']['#default_value'] = $filter['tags'];
+ }
+ if (isset($filter['search'])) {
+ $form['filter']['search']['#default_value'] = $filter['search'];
+ }
+
+ $form['filter']['reset'] = array(
+ '#type' => 'submit',
+ '#value' => t('Reset'),
+ '#suffix' => '</div>',
+ '#weight' => 12
+ );
+ unset($form['filter']['save']['#suffix']);
+}
+
+function privatemsg_filter_dropdown_submit($form, &$form_state) {
+ 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('messages', privatemsg_filter_create_get_query($form_state['values']));
+ return;
+ break;
+ case t('Reset'):
+ $_SESSION['privatemsg_filter'] = array();
+ break;
+ }
+ $form_state['redirect'] = 'messages';
+}
+
+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 ('. implode(', ', $filter['tags']) .')';
+ $result = db_query($sql);
+ while ($row = db_fetch_object($result)) {
+ $query['tags'][] = $row->tag;
+ }
+
+ if (isset($query['tags'])) {
+ $query['tags'] = implode(' ', $query['tags']);
+ }
+ }
+
+ if (isset($filter['author']) && !empty($filter['author'])) {
+ array_map('user_load', $filter['author']);
+ foreach ($filter['author'] as $author) {
+ if (is_object($author) && isset($author->uid) && isset($author->name)) {
+ $query['author'][] = $author->name;
+ }
+ elseif ($author_obj = user_load($author)) {
+ $query['author'][] = $author_obj->name;
+ }
+ }
+ 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_privatemsg_list_messages_alter().
+ */
+function privatemsg_filter_privatemsg_list_messages_alter(&$content, $account) {
+ if (!empty($content['list']['content']) || privatemsg_filter_get_filter($account)) {
+ $content['tags']['content'] = drupal_get_form('privatemsg_filter_dropdown', $account);
+ $content['tags']['#weight'] = -5;
+ }
+}
+
+
+/**
+ * Hook into the query builder to add the tagging info to the correct query
+ */
+function privatemsg_filter_privatemsg_list_alter(&$fragments) {
+ // Filter the message listing by any set tags.
+ if ($filter = privatemsg_filter_get_filter(user_load($fragments['query_args'][0]))) {
+
+ if (isset($filter['tags']) && !empty($filter['tags'])) {
+ $count = 0;
+ foreach ($filter['tags'] as $tag) {
+ $fragments['inner_join'][] = "INNER JOIN {pm_tags_index} pmti$count ON (pmti$count.thread_id = pmi.thread_id AND pmti$count.uid = pmi.uid)";
+ $fragments['where'][] = "pmti$count.tag_id = %d";
+ $fragments['query_args'][] = $tag;
+ $count++;
+ }
+ }
+
+ if (isset($filter['author']) && !empty($filter['author'])) {
+ $count = 0;
+ foreach ($filter['author'] as $author) {
+ $fragments['inner_join'][] = "INNER JOIN {users} u$count ON (u$count.uid = pmi.uid)";
+ $fragments['where'][] = "u$count.uid = %d";
+ $fragments['query_args'][] = $author;
+ $count++;
+ }
+ }
+
+ if (isset($filter['search']) && !empty($filter['search'])) {
+ $fragments['where'][] = "pm.subject LIKE '%s'";
+ $fragments['query_args'][] = '%%'. $filter['search'] .'%%';
+ }
+ }
+}
+
+function privatemsg_filter_privatemsg_view_messages_alter(&$content, $count) {
+ if ($count > 0) {
+ $content['tags']['content'] = drupal_get_form('privatemsg_filter_form');
+ $content['tags']['#weight'] = 10;
+ }
+}
+
+function privatemsg_filter_form(&$form_state) {
+ global $user;
+ $thread_id = arg(2);
+
+ $form['tags'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Tags'),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ );
+ $form['tags']['user_id'] = array(
+ '#type' => 'value',
+ '#value' => $user->uid,
+ );
+ $form['tags']['thread_id'] = array(
+ '#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']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Tag this message'),
+ '#submit' => array('privatemsg_filter_form_submit'),
+ );
+
+ return $form;
+}
+
+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']);
+ }
+ }
+ drupal_set_message(t('Tagging information has been saved.'));
+ }
+} \ No newline at end of file
diff --git a/privatemsgapi/privatemsgapi.inc b/privatemsgapi/privatemsgapi.inc
new file mode 100644
index 0000000..b14ce83
--- /dev/null
+++ b/privatemsgapi/privatemsgapi.inc
@@ -0,0 +1,160 @@
+<?php
+
+
+
+/**
+ * Message sending helper functions
+ */
+/**
+ * Saves message to group association
+ *
+ * group could be thread!
+ *
+ * @param $pmid - privatemsg id
+ * @param $gid - group id
+ */
+function _save_privatemsg_group($pmid, $gid) {
+ //make sure that group and msg id are numeric
+ if (!is_numeric($pmid) || !is_numeric($gid)) {
+ return FALSE;
+ }
+ db_query("INSERT INTO {privatemsg_group} (pmid, gid) VALUES (%d, %d)", $pmid, $gid);
+}
+
+/**
+ * Save group to users association
+ *
+ * This message is called only when a new message is being sent
+ * 'new message' or 'forward message' are qualified new messages for which group_user must be created
+ *
+ * @param $gid - group id
+ * @param $users - array of user ID
+ */
+function _save_privatemsg_group_user($gid, $users = array()) {
+ //make sure all conditions are met for this function to work
+ if (!is_numeric($gid) || !is_array($user) || empty($user)) {
+ return FALSE;
+ }
+ //build the query, regardless of how many users added, this will execute only one query
+ $query = "INSERT INTO {privatemsg_group_user} (gid, uid) VALUES ";
+ $values = array();
+ $replacement = array();
+ foreach ( $users as $index => $user ) {
+ $values[] = "(%d, %d)";
+ $replacement[] = $gid;
+ $replacement[] = $uid;
+ }
+
+ $query .= implode(", ", $values);
+ db_query($query, $replacement);
+}
+
+/**
+ * Privatemsg load single msg api
+ *
+ */
+function _privatemsg_load($pmid, $uid = NULL) {
+ $query = _privatemsg_assemble_query('privatemsg_load', $pmid, $uid);
+// drupal_set_message('<pre>'. print_r($query, 1) . '</pre>');
+
+ $result = db_query($query['query']);
+ $message = db_fetch_array($result);
+ return $message;
+}
+
+function _privatemsg_assemble_query($query_id) {
+
+ $SELECT = array();
+ $INNER_JOIN = array();
+ $WHERE = array();
+ $GROUP_BY = array();
+ $ORDER_BY = array();
+ $QUERY_ARGS = array();
+ $primary_table = '';
+
+ $fragments = array(
+ 'select' => $SELECT,
+ 'inner_join' => $INNER_JOIN,
+ 'where' => $WHERE,
+ 'group_by' => $GROUP_BY,
+ 'order_by' => $ORDER_BY,
+ 'query_args' => $QUERY_ARGS,
+ 'primary_table' => $primary_table,
+ );
+
+ /**
+ * Begin: dynamic arguments
+ */
+ $args = func_get_args();
+ unset($args[0]);
+ //we do the merge because we call call_user_func_array and not drupal_alter
+ //this is necessary because otherwise we would not be able to use $args correctly (otherwise it doesnt unfold)
+ if (!empty($args)) {
+ $alterargs = array_merge(array($query_id, &$fragments,), $args);
+ }
+ else {
+ $alterargs = array($query_id, &$fragments,);
+ }
+ /**
+ * END: Dynamic arguments
+ */
+ call_user_func_array('drupal_alter', $alterargs);
+
+ $SELECT = $fragments['select'];
+ $INNER_JOIN = $fragments['inner_join'];
+ $WHERE = $fragments['where'];
+ $GROUP_BY = $fragments['group_by'];
+ $ORDER_BY = $fragments['order_by'];
+ $QUERY_ARGS = $fragments['query_args'];
+ $primary_table = $fragments['primary_table'];
+
+ if(empty($primary_table)) {
+ $primary_table = '{privatemsg} pm';
+ }
+
+ // Perform the whole query assembly only if we have something to select.
+ if (!empty($SELECT)) {
+ $str_select = implode(", ", $SELECT);
+ $query = "SELECT {$str_select} FROM ". $primary_table;
+
+ // Also build a count query which can be passed to pager_query to get a "page count" as that does not play well with queries including "GROUP BY".
+ // In most cases, "COUNT(*)" is enough to get the count query, but in queries involving a GROUP BY, we want a count of the number of groups we have, not the count of elements inside each group.
+ // So we test if there is GROUP BY and if there is, count the number of distinct groups. If not, we go the normal wal and do a plain COUNT(*).
+ if (!empty($GROUP_BY)) {
+ // PostgreSQL does not support COUNT(sometextfield, someintfield), so I'm only using the first one
+ // Works fine for thread_id/list but may generate an error when a more complex GROUP BY is used.
+ $str_group_by_count = current($GROUP_BY);
+ $count = "SELECT COUNT(DISTINCT {$str_group_by_count}) FROM ". $primary_table;
+ }
+ else {
+ $count = "SELECT COUNT(*) FROM ". $primary_table;
+ }
+
+ if (!empty($INNER_JOIN)) {
+ $str_inner_join = implode(' ', $INNER_JOIN);
+ $query .= " {$str_inner_join}";
+ $count .= " {$str_inner_join}";
+ }
+ if (!empty($WHERE)) {
+ $str_where = '('. implode(') AND (', $WHERE) .')';
+ $query .= " WHERE {$str_where}";
+ $count .= " WHERE {$str_where}";
+ }
+ if (!empty($GROUP_BY)) {
+ $str_group_by = ' GROUP BY '. implode(", ", $GROUP_BY) ;
+ $query .= " {$str_group_by}";
+ }
+ if (!empty($ORDER_BY)) {
+ $str_order_by = ' ORDER BY '. implode(", ", $ORDER_BY) ;
+ $query .= " {$str_order_by}";
+ }
+ if (!empty($QUERY_ARGS)) {
+ _db_query_callback($QUERY_ARGS, TRUE);
+ $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
+ _db_query_callback($QUERY_ARGS, TRUE);
+ $count = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $count);
+ }
+ return array('query' => $query, 'count' => $count);
+ }
+ return FALSE;
+}
diff --git a/styles/privatemsg-list.css b/styles/privatemsg-list.css
new file mode 100644
index 0000000..a54570f
--- /dev/null
+++ b/styles/privatemsg-list.css
@@ -0,0 +1,3 @@
+.privatemsg-list-subject.privatemsg-unread {
+ font-weight: bold;
+} \ No newline at end of file