From b0fedcb3b86ef6321137fb63a49324afb881b8ee Mon Sep 17 00:00:00 2001
From: Sascha Grossenbacher <saschagros+test@gmail.com>
Date: Thu, 17 Mar 2011 11:22:40 +0100
Subject: [PATCH] Issue #870126 by Berdir: Added separate write permission for each role.

---
 privatemsg_roles/privatemsg_roles.module |   50 ++++++++++++++++++---
 privatemsg_roles/privatemsg_roles.test   |   72 ++++++++++++++++++++++++-----
 2 files changed, 102 insertions(+), 20 deletions(-)

diff --git a/privatemsg_roles/privatemsg_roles.module b/privatemsg_roles/privatemsg_roles.module
index f0bfe7f..004223f 100644
--- a/privatemsg_roles/privatemsg_roles.module
+++ b/privatemsg_roles/privatemsg_roles.module
@@ -9,9 +9,9 @@
  * Implements hook_perm().
  */
 function privatemsg_roles_permission() {
-  return array(
-    'write privatemsg to roles' => array(
-      'title' => t('Write private message to roles'),
+  $permissions = array(
+    'write privatemsg to all roles' => array(
+      'title' => t('Write private messages to all roles'),
       'description' => t('Allows to write messages to all users which belong to a specific role.'),
     ),
     'view roles recipients' => array(
@@ -19,6 +19,13 @@ function privatemsg_roles_permission() {
       'description' => t('Ability to view roles recipients and the name of these roles.'),
     ),
   );
+  foreach (user_roles(TRUE) as $role) {
+    $permissions['write privatemsg to role ' . $role] = array(
+      'title' => t('Write private messages to role %role', array('%role' => $role)),
+      'description' => t('Allows to write messages to all users which belong to a specific role.'),
+    );
+  }
+  return $permissions;
 }
 
 function privatemsg_roles_theme() {
@@ -42,13 +49,40 @@ function privatemsg_roles_privatemsg_recipient_type_info() {
       'autocomplete' => 'privatemsg_roles_autocomplete',
       'generate recipients' => 'privatemsg_roles_load_recipients',
       'count' => 'privatemsg_roles_count_recipients',
-      'write access' => 'write privatemsg to roles',
+      'write callback' => 'privatemsg_roles_write_access',
       'view access' => 'view roles recipients',
     ),
   );
 }
 
 /**
+ * Write permission check for roles recipients.
+ */
+function privatemsg_roles_write_access($recipient) {
+
+  // Check if user has permission to write to all roles.
+  if (user_access('write privatemsg to all roles')) {
+    return TRUE;
+  }
+
+  if ($recipient) {
+    if (empty($recipient->name)) {
+      $recipient = array_shift(privatemsg_roles_load_multiple(array($recipient->recipient)));
+    }
+    // Check permission for this recipient.
+    return user_access('write privatemsg to role ' . $recipient->name);
+  }
+  // Check if user has permission to write at least one role.
+  foreach (user_roles(TRUE) as $role) {
+    if (user_access('write privatemsg to role ' . $role)) {
+      return TRUE;
+    }
+  }
+  // No permission, return FALSE.
+  return FALSE;
+}
+
+/**
  * Load a number of roles based on their rid.
  */
 function privatemsg_roles_load_multiple($rids) {
@@ -115,9 +149,11 @@ function privatemsg_roles_autocomplete($fragment, $names, $limit) {
     ->execute();
   $roles = array();
   foreach ($result as $role) {
-    $role->type = 'role';
-    $role->recipient = $role->rid;
-    $roles[privatemsg_recipient_key($role)] = $role;
+    if (user_access('write privatemsg to all roles') || user_access('write privatemsg to role ' . $role->name)) {
+      $role->type = 'role';
+      $role->recipient = $role->rid;
+      $roles[privatemsg_recipient_key($role)] = $role;
+    }
   }
   return $roles;
 }
diff --git a/privatemsg_roles/privatemsg_roles.test b/privatemsg_roles/privatemsg_roles.test
index dd50f35..2219d04 100644
--- a/privatemsg_roles/privatemsg_roles.test
+++ b/privatemsg_roles/privatemsg_roles.test
@@ -22,7 +22,7 @@ class PrivatemsgRolesTestCase extends DrupalWebTestCase {
   }
 
   function testSendMessagetoRoleAPI() {
-    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'write privatemsg to roles'));
+    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'write privatemsg to all roles'));
     $user1 = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg'));
     $user2 = $this->drupalCreateUser();
 
@@ -44,7 +44,6 @@ class PrivatemsgRolesTestCase extends DrupalWebTestCase {
   }
 
   function testSendMessagetoRoleCron() {
-    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'write privatemsg to roles'));
     $user1 = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg'));
 
     variable_set('privatemsg_recipient_small_threshold', 20);
@@ -59,9 +58,17 @@ class PrivatemsgRolesTestCase extends DrupalWebTestCase {
       user_save($users[$i], $edit);
     }
 
-    $recipient = user_role_load($user1->roles[5]);
+
+    // Update permissions.
+    $this->checkPermissions(array(), TRUE);
+
+    $recipient = user_role_load($user1->roles[4]);
     $recipient->recipient = $recipient->rid;
     $recipient->type = 'role';
+
+    // Create user with specific role permission.
+    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'write privatemsg to role ' . $recipient->name));
+
     privatemsg_new_thread(array($recipient), $subject = $this->randomName(10), $body = $this->randomName(50), array('author' => $admin));
 
     // Run cron.
@@ -97,7 +104,7 @@ class PrivatemsgRolesTestCase extends DrupalWebTestCase {
   }
 
   function testSendMessagetoRoleBatch() {
-    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'write privatemsg to roles'));
+    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'write privatemsg to all roles'));
     $user1 = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg'));
 
     variable_set('privatemsg_recipient_small_threshold', 20);
@@ -133,12 +140,17 @@ class PrivatemsgRolesTestCase extends DrupalWebTestCase {
 
   function testPermission() {
     $user1 = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg'));
-    $user2 = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg'));
-    $this->drupalLogin($user1);
+    // Update permissions.
+    $this->checkPermissions(array(), TRUE);
+    // Give permission to write only a specific role.
+    $role_name = user_role_load($user1->roles[4])->name;
+    $user2 = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'write privatemsg to role ' . $role_name));
+
+    $this->drupalLogin($user2);
 
     // Send a message to the role of user 1 and 2.
     $edit = array(
-      'recipient' => $user2->roles[5] . '[role]',
+      'recipient' => $user1->roles[DRUPAL_AUTHENTICATED_RID] . '[role]',
       'subject' => $this->randomName(10),
       'body[value]' => $this->randomName(50),
     );
@@ -147,23 +159,28 @@ class PrivatemsgRolesTestCase extends DrupalWebTestCase {
   }
 
   function testSendMessageToRole() {
-    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'write privatemsg to roles'));
     $user1 = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg'));
     $user2 = $this->drupalCreateUser(array('view roles recipients'));
 
     // Add role of user 1 to user 2;
     $edit = array('roles' => $user2->roles + $user1->roles);
     user_save($user2, $edit);
+
+    // Update permissions.
+    $this->checkPermissions(array(), TRUE);
+
+    $role_name = user_role_load($user1->roles[4])->name;
+    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'view roles recipients', 'write privatemsg to role ' . $role_name));
     $this->drupalLogin($admin);
 
+
     // Verify autocomplete feature.
-    $role_name = user_role_load($user1->roles[5])->name;
     $json = $this->drupalGet('messages/autocomplete/' . drupal_substr($role_name, 0, 2));
     $autocomplete = (array)json_decode($json);
     $this->assertEqual($autocomplete[$role_name . ', '], $role_name);
 
     // Access the form through a url that pre-fills the recipient field.
-    $this->drupalGet('messages/new/role_5');
+    $this->drupalGet('messages/new/role_4');
 
     // Send a message to the role of user 1 and 2.
     $edit = array(
@@ -171,7 +188,7 @@ class PrivatemsgRolesTestCase extends DrupalWebTestCase {
       'body[value]' => $this->randomName(50),
     );
     $this->drupalPost(NULL, $edit, t('Send message'));
-    $this->assertText(t('A message has been sent to @role (role).', array('@role' => user_role_load($user1->roles[5])->name)));
+    $this->assertText(t('A message has been sent to @role (role).', array('@role' => $role_name)));
 
     // Log in as user1 and check that the message is listed, is marked as new
     // and can be marked as read.
@@ -221,7 +238,7 @@ class PrivatemsgRolesTestCase extends DrupalWebTestCase {
   }
 
   function testSendMessageToRoleBlocked() {
-    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'write privatemsg to roles'));
+    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'write privatemsg to all roles'));
     $user1 = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg'));
     $user2 = $this->drupalCreateUser();
 
@@ -264,7 +281,7 @@ class PrivatemsgRolesTestCase extends DrupalWebTestCase {
   }
 
   function testNewUser() {
-    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'write privatemsg to roles'));
+    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'write privatemsg to all roles'));
     $user1 = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg'));
 
     // Send a message to the role of user 1.
@@ -288,4 +305,33 @@ class PrivatemsgRolesTestCase extends DrupalWebTestCase {
     $this->drupalGet('messages');
     $this->assertNoText($edit['subject'], t('Newly added user does not see the old message sent to his role'));
   }
+
+  /**
+   * Verify that deleting a user does not leave stale data behind.
+   */
+  function testDeleteUser() {
+    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'write privatemsg to all roles'));
+    $user = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg'));
+
+    // Send a message to the role of user 1.
+    $role_name = user_role_load(5)->name;
+    $this->drupalLogin($admin);
+    $edit = array(
+      'recipient' => $role_name . '[role]',
+      'subject' => $this->randomName(10),
+      'body[value]' => $this->randomName(50),
+    );
+    $this->drupalPost('messages/new', $edit, t('Send message'));
+    $this->assertText(t('A message has been sent to @role (role).', array('@role' => $role_name)));
+
+    $this->drupalLogin($user);
+
+    $this->drupalGet('messages');
+    $this->assertText($edit['subject'], t('Message sent to role is visible.'));
+
+    // Delete user and make sure that no recipient entries of him are left in
+    // table.
+    user_delete($user->uid);
+    $this->assertFalse(db_query_range("SELECT 1 FROM {pm_index} WHERE recipient = :recipient AND type IN ('user', 'hidden')", 0, 1, array(':recipient' => $user->uid))->fetchField());
+  }
 }
-- 
1.7.4.1

