diff --git flag.inc flag.inc index 53b900c..76d9cf8 100644 --- flag.inc +++ flag.inc @@ -1400,6 +1400,10 @@ class flag_user extends flag_flag { $options += array( 'show_on_profile' => TRUE, 'access_uid' => '', + 'target_roles' => array ( + 'flag' => array (DRUPAL_AUTHENTICATED_RID), + 'unflag' => array (DRUPAL_AUTHENTICATED_RID), + ), ); return $options; } @@ -1408,10 +1412,34 @@ class flag_user extends flag_flag { parent::options_form($form); $form['access']['types'] = array( // A user flag doesn't support node types. - // TODO: Maybe support roles instead of node types. '#type' => 'value', '#value' => array(0 => 0), ); + + $form['access']['target_roles'] = array( + '#title' => t("Roles that can be flagged using this flag"), + '#access' => empty($this->locked['target_roles']), + '#description' => t("Users may only unflag content if they have access to flag the content initially. Checking authenticated user will allow to flag all logged-in users. Anonymous users can't be flagged."), + '#theme' => 'flag_form_roles', + ); + $form['access']['target_roles']['flag'] = array( + '#type' => 'checkboxes', + '#options' => user_roles(TRUE), + '#default_value' => $this->target_roles['flag'], + '#parents' => array('target_roles', 'flag'), + ); + $form['access']['target_roles']['unflag'] = array( + '#type' => 'checkboxes', + '#options' => user_roles(TRUE), + '#default_value' => $this->target_roles['unflag'], + '#parents' => array('target_roles', 'unflag'), + ); + // Disabled access breaks checkboxes unless #value is hard coded. + if (!empty($this->locked['target_roles'])) { + $form['access']['target_roles']['#type'] = 'value'; + $form['access']['target_roles']['#value'] = $this->target_roles; + } + $form['access']['access_uid'] = array( '#type' => 'checkbox', '#title' => t('Users may flag themselves'), @@ -1428,6 +1456,10 @@ class flag_user extends flag_flag { function form_input($form_values) { parent::form_input($form_values); + // Same massaging as for $flag->roles. + $this->target_roles['flag'] = array_values(array_filter($this->target_roles['flag'])); + $this->target_roles['unflag'] = array_values(array_filter($this->target_roles['unflag'])); + // The access_uid value is intentionally backwards from the UI, to avoid // confusion caused by checking a box to disable a feature. $this->access_uid = empty($form_values['access_uid']) ? 'others' : ''; @@ -1450,6 +1482,17 @@ class flag_user extends flag_flag { $access = parent::access($content_id, $action, $account); $account = isset($account) ? $account : $GLOBALS['user']; + // Check if target user can be flagged depending on his roles + // + // TODO: This is a mess. We only deny access here, and it's unclear + // whether we should allow other modules override our decision. + // See http://drupal.org/node/720672 + $content = _load_content($content_id); + $matched_roles = array_intersect($this->target_roles[$action], array_keys($content->roles)); + if (empty($matched_roles) && $account->uid != 1) { + return FALSE; + } + // Prevent users from flagging themselves. if ($this->access_uid == 'others' && $content_id == $account->uid) { $access = FALSE; @@ -1466,6 +1509,22 @@ class flag_user extends flag_flag { if (array_key_exists(0, $access)) { $access[0] = FALSE; } + + // Check if target user can be flagged depending on his roles + // + // TODO: See http://drupal.org/node/720672 + foreach ($content_ids as $content_id => $action) { + $roles = array(DRUPAL_AUTHENTICATED_RID); + // We could use IN (..) but that would make code more complicated. + $result = db_query('SELECT ur.rid FROM {users_roles} ur WHERE ur.uid = %d', $content_id); + while ($role = db_fetch_object($result)) { + $roles[] = $role->rid; + } + $matched_roles = array_intersect($this->target_roles[$action], $roles); + if (empty($matched_roles) && $account->uid != 1) { + $access[$content_id] = FALSE; + } + } // Prevent users from flagging themselves. if ($this->access_uid == 'others' && array_key_exists($account->uid, $access)) {