From 5bca5bb998d4c04cf1e4e02eeb016e6c9c334d6d Mon Sep 17 00:00:00 2001
From: Sascha Grossenbacher <saschagros@gmail.com>
Date: Sat, 2 Apr 2011 09:40:04 +0200
Subject: [PATCH] Issue #1099406 by Berdir: Replace role settings with permissions.

---
 .../user_relationship_blocks.module                |    4 -
 .../user_relationship_privatemsg.test              |   52 +++++---
 ...andler_field_user_relationships_status_link.inc |    2 +-
 user_relationships.admin.inc                       |   21 ---
 user_relationships.install                         |   31 ++---
 user_relationships.module                          |  141 +++++++++----------
 .../user_relationships_ui.actions.inc              |  153 +++++++++-----------
 .../user_relationships_ui.forms.inc                |   10 +--
 user_relationships_ui/user_relationships_ui.module |  122 +++++++++-------
 9 files changed, 247 insertions(+), 289 deletions(-)

diff --git a/user_relationship_blocks/user_relationship_blocks.module b/user_relationship_blocks/user_relationship_blocks.module
index 599da4b..90e4166 100644
--- a/user_relationship_blocks/user_relationship_blocks.module
+++ b/user_relationship_blocks/user_relationship_blocks.module
@@ -194,10 +194,6 @@ function user_relationship_blocks_block_configure($delta) {
 function user_relationship_blocks_block_view($delta) {
   global $user;
 
-  if (!user_access('can have relationships')) {
-    return FALSE;
-  }
-
   //pad array with nulls before calling list() to avoid php notices
   $exploded = explode(UR_BLOCK_SEPARATOR, $delta);
   while (count($exploded) < 3) {
diff --git a/user_relationship_privatemsg/user_relationship_privatemsg.test b/user_relationship_privatemsg/user_relationship_privatemsg.test
index 35a21fa..21b8dec 100644
--- a/user_relationship_privatemsg/user_relationship_privatemsg.test
+++ b/user_relationship_privatemsg/user_relationship_privatemsg.test
@@ -32,9 +32,26 @@ class UserRelationshipsPrivatemsgRecipientTestCase extends DrupalWebTestCase {
    * Tests sending a message to related users.
    */
   function testSendtoRelationship() {
-    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'can have relationships', 'view relationship recipients', 'administer user relationships', 'maintain own relationships', 'write privatemsg to relationships', 'access user profiles'));
-    $userA = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'can have relationships', 'view relationship recipients', 'write privatemsg to relationships'));
-    $userB = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'can have relationships', 'view relationship recipients'));
+
+    // Create relationship.
+    $relationship = array(
+      'name' => $this->randomName(),
+      'plural_name' => $this->randomName(),
+      'requires_approval' => FALSE,
+      'expires_val' => 0,
+    );
+    user_relationships_type_save((object)$relationship);
+
+    // Flush permission cache.
+    user_relationships_types_load(TRUE);
+    $this->checkPermissions(array(), TRUE);
+
+    $have_permission = 'can have ' . $relationship['name'] . ' relationships';
+    $request_permission = 'can request ' . $relationship['name'] . ' relationships';
+
+    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', $have_permission, $request_permission, 'view relationship recipients', 'administer user relationships', 'maintain own relationships', 'write privatemsg to relationships', 'access user profiles'));
+    $userA = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', $have_permission, $request_permission, 'view relationship recipients', 'write privatemsg to relationships'));
+    $userB = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', $have_permission, $request_permission, 'view relationship recipients'));
 
     $this->drupalLogin($admin);
 
@@ -44,14 +61,6 @@ class UserRelationshipsPrivatemsgRecipientTestCase extends DrupalWebTestCase {
     );
     $this->drupalPost('admin/config/people/relationships/settings', $edit, t('Save configuration'));
 
-    // Create relationship.
-    $relationship = array(
-      'name' => $this->randomName(),
-      'plural_name' => $this->randomName(),
-      'requires_approval' => FALSE,
-    );
-    $this->drupalPost('admin/config/people/relationships/add', $relationship, t('Submit'));
-
     // Become related to user A and B.
     $this->drupalGet('relationship/' . $userA->uid . '/request/1');
     $this->drupalPost(NULL, array(), t('Send'));
@@ -128,23 +137,32 @@ class UserRelationshipsPrivatemsgRecipientTestCase extends DrupalWebTestCase {
    * Test a relationship with bath api processing.
    */
   function testManyRelations() {
-    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'can have relationships', 'view relationship recipients', 'administer user relationships', 'maintain own relationships', 'write privatemsg to relationships', 'access user profiles'));
-
-    $this->drupalLogin($admin);
 
-    // Create relationship.
+        // Create relationship.
     $relationship = array(
       'name' => $this->randomName(),
       'plural_name' => $this->randomName(),
       'requires_approval' => FALSE,
+      'expires_val' => 0,
     );
-    $this->drupalPost('admin/config/people/relationships/add', $relationship, t('Submit'));
+    user_relationships_type_save((object)$relationship);
+
+    // Flush permission cache.
+    user_relationships_types_load(TRUE);
+    $this->checkPermissions(array(), TRUE);
+
+    $have_permission = 'can have ' . $relationship['name'] . ' relationships';
+    $request_permission = 'can request ' . $relationship['name'] . ' relationships';
+
+    $admin = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', $have_permission, $request_permission, 'view relationship recipients', 'administer user relationships', 'maintain own relationships', 'write privatemsg to relationships', 'access user profiles'));
+
+    $this->drupalLogin($admin);
 
     // Create 25 users (more than are allowed to be process directly) and relate
     // them to the admin.
     $users = array();
     for ($i = 0; $i < 25; $i++) {
-      $users[$i] = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', 'can have relationships', 'view relationship recipients', 'write privatemsg to relationships'));
+      $users[$i] = $this->drupalCreateUser(array('read privatemsg', 'write privatemsg', $have_permission, $request_permission, 'view relationship recipients', 'write privatemsg to relationships'));
       // Become related to that user.
       $this->drupalGet('relationship/' . $users[$i]->uid . '/request/1');
       $this->drupalPost(NULL, array(), t('Send'));
diff --git a/user_relationship_views/views_handler_field_user_relationships_status_link.inc b/user_relationship_views/views_handler_field_user_relationships_status_link.inc
index be39cfe..7e3c79c 100644
--- a/user_relationship_views/views_handler_field_user_relationships_status_link.inc
+++ b/user_relationship_views/views_handler_field_user_relationships_status_link.inc
@@ -24,7 +24,7 @@ class views_handler_field_user_relationships_status_link extends views_handler_f
     global $user;
 
     //Do not show to guests or users witout permission to have relationships.
-    if (!$user->uid && user_access('can have relationships')) {
+    if (!$user->uid) {
       return;
     }
 
diff --git a/user_relationships.admin.inc b/user_relationships.admin.inc
index 6c9c840..c6d8603 100644
--- a/user_relationships.admin.inc
+++ b/user_relationships.admin.inc
@@ -229,27 +229,6 @@ function user_relationships_admin_type_edit($form, &$form_state, $relationship_t
     ),
   );
 
-  $form['roles'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Allowed Roles'),
-    '#group' => 'tabs',
-    '#weight' => 10,
-  );
-
-  $form['roles']['roles'] = array(
-    '#type' => 'checkboxes',
-    '#options' => user_roles(TRUE),
-    '#default_value' => isset($relationship_type->roles) ? $relationship_type->roles : array(),
-    '#title' => t('Role request access'),
-    '#description' => t('You may choose which roles are allowed to request this relationship. If none are selected, all roles are allowed.'),
-  );
-  $form['roles']['roles_receive'] = array(
-    '#type' => 'checkboxes',
-    '#options' => user_roles(TRUE),
-    '#default_value' => isset($relationship_type->roles_receive)  && is_array($relationship_type->roles_receive) ? $relationship_type->roles_receive : array(),
-    '#title' => t('Role receive access'),
-    '#description' => t('You may choose which roles are allowed to receive this relationship. If none are selected, all roles are allowed to receive the relationship.'),
-  );
   $form['rtid'] = array(
     '#type'   => 'value',
     '#value'  => isset($relationship_type->rtid) ? (int)$relationship_type->rtid : NULL,
diff --git a/user_relationships.install b/user_relationships.install
index 7341f6b..6ce657f 100644
--- a/user_relationships.install
+++ b/user_relationships.install
@@ -45,28 +45,6 @@ function user_relationships_schema() {
     'primary key' => array('rtid')
   );
 
-  $schema['user_relationship_type_roles'] = array(
-    'fields' => array(
-      'rtid'              => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-      'rid'              => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-    ),
-    'primary key' => array('rtid', 'rid'),
-    'indexes' => array(
-      'rtid' => array('rtid'),
-    )
-  );
-
-  $schema['user_relationship_type_roles_receive'] = array(
-    'fields' => array(
-      'rtid'              => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-      'rid'              => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-    ),
-    'primary key' => array('rtid', 'rid'),
-    'indexes' => array(
-      'rtid' => array('rtid'),
-    )
-  );
-
   return $schema;
 }
 
@@ -107,3 +85,12 @@ function user_relationships_update_7000() {
     variable_del($variable->name);
   }
 }
+
+/**
+ * Remove user relationship type roles tables.
+ */
+function user_relationships_update_7001() {
+  drupal_set_message(('Allowed roles settings for user relationship types must now be set by configuring the corresponding permissions explicitly.'));
+  db_drop_table('user_relationship_type_roles');
+  db_drop_table('user_relationship_type_roles_receive');
+}
\ No newline at end of file
diff --git a/user_relationships.module b/user_relationships.module
index 2b59576..69ee2a4 100644
--- a/user_relationships.module
+++ b/user_relationships.module
@@ -199,20 +199,26 @@ function _user_relationships_generate_query($param = array(), $options = array()
   return $query;
 }
 
-
 /**
- * hook_perm()
+ * Implements hook_permission().
  */
 function user_relationships_permission() {
-  return array('can have relationships' => array(
-    'title' => t('Can have relationships'),
-    'description' => t('The user is allowed to have and accept relationships.'),
-  ));
+  $permissions = array();
+  foreach (user_relationships_types_load() as $type) {
+    $permissions['can have ' . $type->name . ' relationships'] = array(
+      'title' => t('Can have @name relationships', array('@name' => $type->name)),
+      'description' => t('The user is allowed to have and accept relationships of that type.'),
+    );
+    $permissions['can request ' . $type->name . ' relationships'] = array(
+      'title' => t('Can request @name relationships', array('@name' => $type->name)),
+      'description' => t('The user is allowed to request relationships of that type.'),
+    );
+  }
+  return $permissions;
 }
 
-
 /**
- * hook_cron()
+ * Implements hook_cron()
  */
 function user_relationships_cron() {
   $now = REQUEST_TIME;
@@ -355,27 +361,10 @@ function user_relationships_types_load($reset = FALSE) {
   if ($reset || !isset($relationship_types_list)) {
     // Clear the cached list, since some relationships may have disappeared.
     $relationship_types_list = db_query("SELECT * FROM {user_relationship_types}")->fetchAllAssoc('rtid');
-    if (empty($relationship_types_list)) {
-      // No relationships, avoid querying role permissions.
-      return $relationship_types_list;
-    }
-    // Load role permissions for all types.
-    $result = db_query('SELECT rtid, rid FROM {user_relationship_type_roles} WHERE rtid IN (:rtids) ORDER BY rtid, rid', array(':rtids' => array_keys($relationship_types_list)));
-    foreach ($result as $mapping) {
-      // roles is an associative array {role id} => {role id}.
-      $relationship_types_list[$mapping->rtid]->roles[$mapping->rid] = $mapping->rid;//] = $mapping->name;
-    }
 
-    // Load role receive permissions for all types.
-    $results = db_query('SELECT rtid, rid FROM {user_relationship_type_roles_receive} WHERE rtid IN (:rtids) ORDER BY rtid, rid', array(':rtids' => array_keys($relationship_types_list)));
-    foreach ($results as $mapping) {
-      // roles_receive is an associative array {role id} => {role id}.
-      $relationship_types_list[$mapping->rtid]->roles_receive[$mapping->rid] = $mapping->rid;
-    }
+    module_invoke_all('user_relationships_type_load', $relationship_types_list);
   }
 
-  module_invoke_all('user_relationships_type_load', $relationship_types_list);
-
   return $relationship_types_list;
 }
 
@@ -740,68 +729,70 @@ function user_relationships_translate_user_info(&$relationship) {
 }
 
 /**
- * Check whether a user is allowed to request a certain relationship type
+ * Check whether a user is allowed to request a certain relationship type.
  *
- * @param $requester requesting user object or uid
- * @param $relationship_type loaded relationship type object or rtid
- * @return TRUE iff requester is allowed to request this type of relationship
+ * @param $requester
+ *   requesting user object
+ * @param $relationship_type
+ *   relationship type object
+ * @return
+ *   TRUE if requester is allowed to request this type of relationship.
  */
-function user_relationships_can_request($requester, $relationship_type) {
-  //validate arguments
-  if (is_numeric($requester)) {
-    $requester = user_load($requester);
-  }
-  if (is_numeric($relationship_type)) {
-    $relationship_type = user_relationships_type_load($relationship_type);
-  }
-  if (!is_object($requester) || !is_object($relationship_type)) {
-    return FALSE;
-  }
-  if ($requester->uid == 1) {
-    return TRUE;
-  }
-  //if no roles have been set, any user can request
-  if (!isset($relationship_type->roles) || !count($relationship_type->roles)) {
-    return TRUE;
-  }
-  //check user has at least one required role
-  foreach ($relationship_type->roles as $role_id) {
-    if (isset($requester->roles[$role_id])) {
-      return TRUE;
-    }
-  }
-  return FALSE;
+function user_relationships_can_request($requester, $relationship_type = NULL) {
+  return user_relationships_user_access('can request @relationship relationships', $relationship_type, $requester);
 }
 
 /**
- * Check whether a user is allowed to receive a certain relationship type
+ * Check whether a user is allowed to receive a certain relationship type.
+ *
+ * @param $requestee
+ *   Requesting user object.
+ * @param $relationship_type
+ *   Relationship type for which should be checked. NULl to check for any.
  *
- * @param $requestee requesting user object or uid
- * @param $relationship_type loaded relationship type object or rtid
- * @return TRUE iff receiver is allowed to request this type of relationship
+ * @return
+ *   TRUE if receiver is allowed to request this type of relationship
  */
-function user_relationships_can_receive($requestee, $relationship_type) {
-  //validate arguments
-  if (is_numeric($relationship_type)) {
-    $relationship_type = user_relationships_type_load($relationship_type);
-  }
-  if (is_numeric($requestee)) {
-    $requestee = user_load($requestee);
+function user_relationships_can_receive($requestee, $relationship_type = NULL) {
+  return user_relationships_user_access('can have @relationship relationships', $relationship_type, $requestee);
+}
+
+/**
+ * Check if a user has a given permission.
+ *
+ * @param $permission
+ *   The permission that should be checked. Use @relationship for the
+ *   relationship type placeholder.
+ * @param $relationship
+ *   For which relationship type the permission should be checked. If NULL,
+ *   all relationship types are checked and TRUE is returned if $account has the
+ *   permission for at least one relationship type.
+ * @param $account
+ *   The account to check, if not given use currently logged in user.
+ *
+ * @return
+ *   TRUE if the user has the given permission for that relationship type or for
+ *   any type if no specific relationship was passed in, FALSE otherwise.
+ */
+function user_relationships_user_access($permission, $relationship = NULL, $account = NULL) {
+  if (!$account) {
+    global $user;
+    $account = $user;
   }
-  if (!is_object($requestee) || !is_object($relationship_type)) {
-    return FALSE;
+
+  if ($relationship) {
+    $relationships = array($relationship);
   }
-  //if no roles have been set to receive the relationship, any user can receive it
-  if (!isset($relationship_type->roles_receive) || !count($relationship_type->roles_receive)) {
-    return TRUE;
+  else {
+    $relationships = user_relationships_types_load();
   }
-  //check user has at least one required role
-  foreach ($relationship_type->roles_receive as $role_id) {
-    if (isset($requestee->roles[$role_id])) {
+
+  foreach ($relationships as $r) {
+    $relationship_permission = str_replace('@relationship', $r->name, $permission);
+    if (user_access($relationship_permission, $account)) {
       return TRUE;
     }
   }
-  return FALSE;
 }
 
 /**
diff --git a/user_relationships_ui/user_relationships_ui.actions.inc b/user_relationships_ui/user_relationships_ui.actions.inc
index 5e26966..7253812 100644
--- a/user_relationships_ui/user_relationships_ui.actions.inc
+++ b/user_relationships_ui/user_relationships_ui.actions.inc
@@ -13,102 +13,87 @@ function user_relationships_ui_request_validate($form, &$form_state) {
   $requester = user_load($form_state['values']['requester']);
   $requestee = user_load($form_state['values']['requestee']);
   $rtid = $form_state['values']['rtid'];
-
-  if (user_access('can have relationships', $requestee)) {
-    //check that a type has been chosen
-    if (!$rtid || !($rtype = user_relationships_type_load($rtid))) {
-      form_set_error('rtid', user_relationships_get_message('relationship_type_not_set'));
-      //need to handle requests from ajax forms separately
-      if (isset($_GET['ajax'])) {
-        drupal_goto();
-      }
-      else {
-        return;
-      }
+  $rtype = user_relationships_type_load($rtid);
+
+  //check that a type has been chosen
+  $current_relationships = user_relationships_load(array('between' => array($requester->uid, $requestee->uid)), array('sort' => 'rtid'));
+  //check for multiple relationships
+  if (!variable_get('user_relationships_allow_multiple', TRUE) && count($current_relationships)) {
+  form_set_error('rtid', user_relationships_get_message('too_many_relationships'));
+    if (isset($_GET['ajax'])) {
+      drupal_goto();
     }
-    $current_relationships = user_relationships_load(array('between' => array($requester->uid, $requestee->uid)), array('sort' => 'rtid'));
-    //check for multiple relationships
-    if (!variable_get('user_relationships_allow_multiple', TRUE) && count($current_relationships)) {
-    form_set_error('rtid', user_relationships_get_message('too_many_relationships'));
-      if (isset($_GET['ajax'])) {
-        drupal_goto();
-      }
-      else {
-        return;
-      }
+    else {
+      return;
     }
-    //check user is allowed to request this type
-    if (!user_relationships_can_request($requester, $rtype)) {
-      $rtype->requester = $requester;
-      $rtype->requestee = $requestee;
-      form_set_error('rtid', user_relationships_get_message('relationship_type_not_allowed', $rtype));
-      if (isset($_GET['ajax'])) {
-        drupal_goto();
-      }
-      else {
-        return;
-      }
+  }
+  //check user is allowed to request this type
+  if (!user_relationships_can_request($requester, $rtype)) {
+    $rtype->requester = $requester;
+    $rtype->requestee = $requestee;
+    form_set_error('rtid', user_relationships_get_message('relationship_type_not_allowed', $rtype));
+    if (isset($_GET['ajax'])) {
+      drupal_goto();
     }
-
-    //check user is allowed to receive this type
-    if (!user_relationships_can_receive($requestee, $rtype)) {
-      $rtype->requester = $requester;
-      $rtype->requestee = $requestee;
-      form_set_error('rtid', user_relationships_get_message('relationship_type_not_allowed', $rtype));
-      if (isset($_GET['ajax'])) {
-        drupal_goto();
-      }
-      else {
-        return;
-      }
+    else {
+      return;
     }
+  }
 
-    //check if this request contradicts existing relationships or requests of this type
-    //gather rtid's of relationships that have already been requested from requester to requestee
-    $test_relationships = array();
-    foreach ($current_relationships as $key => $value) {
-      foreach ($value as $val_rel) {
-        //existing two way relationships count no matter the direction
-        if (!$val_rel->is_oneway) {
-          $test_relationships[$key]=$key;
-          continue;
-        }
-        //if it's one way, but not reciprocal, then it counts no matter the direction
-        if (!$val_rel->is_reciprocal) {
-          $test_relationships[$key]=$key;
-          continue;
-        }
-        //remaining case is a reciprocal relationship - it counts unless the request is in the opposite direction
-        if ($requester->uid == $val_rel->requester_id) {
-          $test_relationships[$key]=$key;
-        }
-      }
-    }
-    //check if there aren't any available (not yet used) types that can be established
-    $select = db_select('user_relationship_types');
-    $select->addExpression('COUNT(*)', 'count');
-    if ($test_relationships) {
-      $select->condition('rtid', $test_relationships, 'NOT IN');
-    }
-    if (!$select->execute()->fetchField()) {
-      drupal_set_message(user_relationships_get_message('too_many_relationships'), 'error');
+  //check user is allowed to receive this type
+  if (!user_relationships_can_receive($requestee, $rtype)) {
+    $rtype->requester = $requester;
+    $rtype->requestee = $requestee;
+    form_set_error('rtid', user_relationships_get_message('relationship_type_not_allowed', $rtype));
+    if (isset($_GET['ajax'])) {
       drupal_goto();
     }
-    //check if desided relationship type is among the unused ones
-    elseif (isset($test_relationships[$rtid])) {
-      $message_name = $test_relationships[$rtid]->approved ? 'existing_relationship' : 'existing_request';
-      form_set_error('rtid', user_relationships_get_message($message_name, NULL, array(
-        '!requester'                => theme('username', array('account' => $requester)),
-        '!requestee'                => theme('username', array('account' => $requestee)),
-        '%relationship_name'        => $current_relationships[$rtid][0]->name,
-        '%relationship_plural_name' => $current_relationships[$rtid][0]->plural_name
-      )));
+    else {
+      return;
+    }
+  }
+
+  //check if this request contradicts existing relationships or requests of this type
+  //gather rtid's of relationships that have already been requested from requester to requestee
+  $test_relationships = array();
+  foreach ($current_relationships as $key => $value) {
+    foreach ($value as $val_rel) {
+      //existing two way relationships count no matter the direction
+      if (!$val_rel->is_oneway) {
+        $test_relationships[$key]=$key;
+        continue;
+      }
+      //if it's one way, but not reciprocal, then it counts no matter the direction
+      if (!$val_rel->is_reciprocal) {
+        $test_relationships[$key]=$key;
+        continue;
+      }
+      //remaining case is a reciprocal relationship - it counts unless the request is in the opposite direction
+      if ($requester->uid == $val_rel->requester_id) {
+        $test_relationships[$key]=$key;
+      }
     }
   }
-  else {
-    drupal_set_message(user_relationships_get_message('not_accepting_requests'));
+  //check if there aren't any available (not yet used) types that can be established
+  $select = db_select('user_relationship_types');
+  $select->addExpression('COUNT(*)', 'count');
+  if ($test_relationships) {
+    $select->condition('rtid', $test_relationships, 'NOT IN');
+  }
+  if (!$select->execute()->fetchField()) {
+    drupal_set_message(user_relationships_get_message('too_many_relationships'), 'error');
     drupal_goto();
   }
+  //check if desided relationship type is among the unused ones
+  elseif (isset($test_relationships[$rtid])) {
+    $message_name = $test_relationships[$rtid]->approved ? 'existing_relationship' : 'existing_request';
+    form_set_error('rtid', user_relationships_get_message($message_name, NULL, array(
+      '!requester'                => theme('username', array('account' => $requester)),
+      '!requestee'                => theme('username', array('account' => $requestee)),
+      '%relationship_name'        => $current_relationships[$rtid][0]->name,
+      '%relationship_plural_name' => $current_relationships[$rtid][0]->plural_name
+    )));
+  }
 }
 
 /**
diff --git a/user_relationships_ui/user_relationships_ui.forms.inc b/user_relationships_ui/user_relationships_ui.forms.inc
index 1bd4d29..73fb37f 100644
--- a/user_relationships_ui/user_relationships_ui.forms.inc
+++ b/user_relationships_ui/user_relationships_ui.forms.inc
@@ -13,7 +13,7 @@ module_load_include('inc', 'user_relationships_ui', 'user_relationships_ui.actio
  * @param $form_values array $form['values'] when called from form_alter()
  */
 function user_relationships_ui_request_form($requester, $requestee, $form_values = NULL) {
-  $relationships = _user_relationships_ui_get_requestable_rtypes($requester, $requestee);
+  $relationships = user_relationships_ui_get_requestable_rtypes($requester, $requestee);
   //try to find out desired relationship type
   $default_relationship = NULL;
   if (isset($form_values['rtid'])) {//given through form
@@ -91,14 +91,6 @@ function user_relationships_ui_request($form, &$form_state, $requestee) {
     );
     return $form;
   }
-  elseif (!user_access('can have relationships', $requestee)) {
-    $form['error'] = array(
-      '#prefix' => '<div>',
-      '#suffix' => '</div>',
-      '#markup' => user_relationships_get_message('not_accepting_requests') . $script
-    );
-    return $form;
-  }
   elseif ($user->uid == $requestee->uid) {
     $form['error'] = array(
       '#prefix' => '<div>',
diff --git a/user_relationships_ui/user_relationships_ui.module b/user_relationships_ui/user_relationships_ui.module
index c7ff42b..9c0e34b 100644
--- a/user_relationships_ui/user_relationships_ui.module
+++ b/user_relationships_ui/user_relationships_ui.module
@@ -53,14 +53,22 @@ function _user_relationships_ui_autocomplete_types($string = '') {
 }
 
 /**
- * List of possible relationship actions with between two users
- * @param $viewer - user object for the visitor
- * @param $viewed - user object for the user being looked at
- * @param action_types - associative array of kinds of links to show (all by default). Only the existence of specific array keys is needed:
- *                       add, remove, requested, received
+ * List of possible relationship actions with between two users.
+ *
+ * @param $viewer
+ *   User object for the visitor.
+ * @param $viewed
+ *   User object for the user being looked at.
+ * @param action_types
+ *   Associative array of kinds of links to show (all by default).
+ *   Only the existence of specific array keys is needed: add, remove,
+ *   requested, received.
+ *
+ * @return
+ *   An array with actions as strings.
  */
-function _user_relationships_ui_actions_between(&$viewer, &$viewed, $action_types = array('add' => 1, 'remove' => 1, 'requested' => 1, 'received' => 1)) {
-  if (!user_access('can have relationships') || $viewer->uid == $viewed->uid) {
+function _user_relationships_ui_actions_between($viewer, $viewed, $action_types = array('add' => 1, 'remove' => 1, 'requested' => 1, 'received' => 1)) {
+  if ($viewer->uid == $viewed->uid) {
     return;
   }
 
@@ -87,38 +95,18 @@ function _user_relationships_ui_actions_between(&$viewer, &$viewed, $action_type
   }
 
   if (isset($action_types['add'])) {
-    // Compute if any more relationships can be created
-    $types_count = (int)db_query("SELECT COUNT(*) FROM {user_relationship_types}")->fetchField();
-    $existing_relationships = user_relationships_load(array('between' => array($viewer->uid, $viewed->uid)), array('sort' => 'rtid'));
-    $all_relationships = user_relationships_types_load();
-    $relationships_count = 0;
-
-    // Unset the relationships which already exist
-    foreach ($existing_relationships as $rtid => $relationship_type) {
-      foreach ($relationship_type as $relationship) {
-        if (!$relationship->is_oneway || !$relationship->is_reciprocal || $relationship->requester_id == $viewer->uid) {
-          unset($all_relationships[$rtid]);
-          $relationships_count++;
-        }
-      }
-    }
-
-    if (!$relationships_count || (variable_get('user_relationships_allow_multiple', TRUE) && ($relationships_count < $types_count))) {
-      //if configured, create direct links
+    $relationships = user_relationships_ui_get_requestable_rtypes($viewer, $viewed, 'full');
+    if ($relationships) {
+      // If configured, create direct links.
       if (variable_get('user_relationships_show_direct_links', 1)) {
-        //draw a single link, or one for each relationship type
-        foreach ($all_relationships as $rtid => $relationship) {
-          //check this type can be requested
-          if (!user_relationships_can_request($viewer, $relationship) || !user_relationships_can_receive($viewed, $relationship) || !user_access('maintain own relationships')) {
-            continue;
-          }
+        // Create a single link, or one for each relationship type.
+        foreach ($relationships as $rtid => $relationship) {
           $list[] = theme('user_relationships_request_relationship_direct_link', array('relate_to' => $viewed, 'relationship_type' => $relationship));
         }
       }
-      //just one generic link pointing to a page with dropdown
+      // just one generic link pointing to a page with dropdown.
       else {
         $list[] = theme('user_relationships_request_relationship_link', array('relate_to' => $viewed));
-
       }
     }
   }
@@ -139,36 +127,57 @@ function _user_relationships_ui_actions_between(&$viewer, &$viewed, $action_type
 }
 
 /**
- * Get relationship types that a user can request
- * TODO: factor out of .module into an include file
- * @param $requester requester user or uid
- * @param $requestee requestee user or uid
- * @return array {rtid} => {relationship type name} that requester may send to requestee
+ * Get relationship types that a user can request from another user.
+ *
+ * @param $requester
+ *   Requesting user object.
+ * @param $requestee
+ *   The reqestee user object.
+ * @param $return
+ *   What should be returned, either name for the translated relationship name
+ *   or full for the whole object. Defaults to name.
+ *
+ * @return
+ *   An array of relationship types a user can request from another, keyed by
+ *   the relationship type id and either the name or full object as value,
+ *   depending on the return argument.
  */
-function _user_relationships_ui_get_requestable_rtypes($requester, $requestee) {
+function user_relationships_ui_get_requestable_rtypes($requester, $requestee, $return = 'name') {
   $current_relationships = user_relationships_load(array('between' => array($requester->uid, $requestee->uid)), array('sort' => 'rtid'));
 
   $relationship_types = user_relationships_types_load();
   $relationships = array();
   foreach ($relationship_types as $rtype) {
-    //exclude already established relationships
-    if (!isset($current_relationships[$rtype->rtid])) {
-      $relationships[$rtype->rtid] = ur_tt("user_relationships:rtid:$rtype->rtid:name", $rtype->name);
+
+    // Exclude types that are not allowed.
+    if (!user_relationships_can_request($requester, $rtype) || !user_relationships_can_receive($requestee, $rtype)) {
       continue;
     }
-    $relationship = $current_relationships[$rtype->rtid];
-    if (is_array($relationship) && count($relationship)) {
-      $relationship = $relationship[0];
+
+    // If there is a relationship o that type already, make further checks.
+    if (isset($current_relationships[$rtype->rtid])) {
+      $relationship = $current_relationships[$rtype->rtid];
+      if (is_array($relationship) && count($relationship)) {
+        $relationship = $relationship[0];
+      }
+
+      // Skip two-way relationships, one-way non-reciprocal relationships, or
+      // reciprocal where this direction already exists.
+      if (isset($current_relationships[$rtype->rtid]) && (!$rtype->is_oneway || !$rtype->is_reciprocal || (isset($relationship) && $relationship->requester_id == $requester->uid))) {
+        // If users can't have multiple relationships, we're done here.
+        // Return an empty array.
+        if (!variable_get('user_relationships_allow_multiple', TRUE)) {
+          return array();
+        }
+        continue;
+      }
     }
-    //skip two-way relationships, one-way non-reciprocal relationships, or reciprocal where this direction already exists
-    if (isset($current_relationships[$rtype->rtid]) && (!$rtype->is_oneway || !$rtype->is_reciprocal || (isset($relationship) && $relationship->requester_id == $requester->uid))) {
-      continue;
+    if ($return == 'name') {
+      $relationships[$rtype->rtid] = ur_tt("user_relationships:rtid:$rtype->rtid:name", $rtype->name);
     }
-    //exclude types that are not allowed
-    if (!user_relationships_can_request($requester, $rtype) || !user_relationships_can_receive($requestee, $rtype)) {
-      continue;
+    else {
+      $relationships[$rtype->rtid] = $rtype;
     }
-    $relationships[$rtype->rtid] = ur_tt("user_relationships:rtid:$rtype->rtid:name", $rtype->name);
   }
   return $relationships;
 }
@@ -188,12 +197,13 @@ function user_relationships_ui_check_access($types, $account = NULL) {
     return TRUE;
   }
 
-  if (!is_array($types)) {
-    $types = array($types);
+  // If the user does not any have permission, deny access.
+  if (!user_relationships_can_receive($account)) {
+    return FALSE;
   }
 
-  if (!user_access('can have relationships')) {
-    return FALSE;
+  if (!is_array($types)) {
+    $types = array($types);
   }
 
   foreach ($types as $type) {
-- 
1.7.4.1

