From 6143532f307e46dae3698b6dcf5c0593222068d8 Mon Sep 17 00:00:00 2001
From: Earl Miles <merlin@logrus.com>
Date: Thu, 23 Apr 2009 20:53:36 +0000
Subject: [PATCH] Allow restricting contexts via access control to allow the
 add content UI to remove irrelevant content.

---
 delegator/plugins/tasks/page.inc    |  9 +++++
 includes/context-task-handler.inc   | 26 +++++++++++++-
 includes/context.inc                | 54 +++++++++++++++++++++++++++++
 plugins/access/node_type.inc        | 14 ++++++++
 plugins/contexts/node.inc           | 19 ++--------
 plugins/contexts/node_add_form.inc  |  1 +
 plugins/contexts/node_edit_form.inc |  1 +
 7 files changed, 107 insertions(+), 17 deletions(-)

diff --git a/delegator/plugins/tasks/page.inc b/delegator/plugins/tasks/page.inc
index cf0828f4..e89e9421 100644
--- a/delegator/plugins/tasks/page.inc
+++ b/delegator/plugins/tasks/page.inc
@@ -58,6 +58,7 @@ function delegator_page_delegator_tasks() {
       'handler type' => 'context',
       'get arguments' => 'delegator_page_get_arguments',
       'get context placeholders' => 'delegator_page_get_contexts',
+      'access restrictions' => 'delegator_page_access_restrictions',
       'uses handlers' => TRUE,
     ),
   );
@@ -341,6 +342,14 @@ function delegator_page_get_contexts($task, $subtask_id) {
   return ctools_context_get_placeholders_from_argument(delegator_page_get_arguments($task, $subtask_id));
 }
 
+/**
+ * Return a list of arguments used by this task.
+ */
+function delegator_page_access_restrictions($task, $subtask_id, $contexts) {
+  $page = delegator_page_load($subtask_id);
+  return ctools_access_add_restrictions($page->access, $contexts);
+}
+
 // --------------------------------------------------------------------------
 // Page task database info.
 
diff --git a/includes/context-task-handler.inc b/includes/context-task-handler.inc
index 9203ef27..5c5053e1 100644
--- a/includes/context-task-handler.inc
+++ b/includes/context-task-handler.inc
@@ -162,7 +162,9 @@ function ctools_context_handler_get_handler_contexts($contexts, $handler) {
  */
 function ctools_context_handler_get_all_contexts($task, $subtask_id, $handler) {
   $object = ctools_context_handler_get_task_object($task, $subtask_id, $handler);
-  return ctools_context_load_contexts($object, TRUE);
+  $contexts = ctools_context_load_contexts($object, TRUE);
+  ctools_context_handler_set_access_restrictions($task, $subtask_id, $handler, $contexts);
+  return $contexts;
 }
 
 /**
@@ -204,6 +206,28 @@ function ctools_context_handler_get_task_arguments($task, $subtask_id) {
   return array();
 }
 
+/**
+ * Set any access restrictions on the contexts for a handler.
+ *
+ * Both the task and the handler could add restrictions to the contexts
+ * based upon the access control. These restrictions might be useful
+ * to limit what kind of content appears in the add content dialog;
+ * for example, if we have an access item that limits a node context
+ * to only 'story' and 'page' types, there is no need for content that
+ * only applies to the 'poll' type to appear.
+ */
+function ctools_context_handler_set_access_restrictions($task, $subtask_id, $handler, &$contexts) {
+  // First, for the task:
+  if ($function = ctools_plugin_get_function($task, 'access restrictions')) {
+    $function($task, $subtask_id, $contexts);
+  }
+
+  // Then for the handler:
+  if (isset($handler->conf['access'])) {
+    ctools_access_add_restrictions($handler->conf['access'], $contexts);
+  }
+}
+
 /**
  * Form to choose context based selection rules for a task handler.
  *
diff --git a/includes/context.inc b/includes/context.inc
index 10edd6c2..7288dca4 100644
--- a/includes/context.inc
+++ b/includes/context.inc
@@ -40,6 +40,8 @@ class ctools_context {
   var $argument = NULL;
   var $keyword = '';
   var $original_argument = NULL;
+  var $restrictions = array();
+  var $empty = FALSE;
 
   function ctools_context($type = 'none', $data = NULL) {
     $this->type  = $type;
@@ -110,6 +112,12 @@ class ctools_context_required {
   function ctools_context_required($title) {
     $args = func_get_args();
     $this->title = array_shift($args);
+
+    // If we were given restrictions at the end, store them.
+    if (count($args) > 1 && is_array(end($args))) {
+      $this->restrictions = array_pop($args);
+    }
+
     if (count($args) == 1) {
       $args = array_shift($args);
     }
@@ -122,6 +130,21 @@ class ctools_context_required {
     // See which of these contexts are valid
     foreach ((array) $contexts as $cid => $context) {
       if ($context->is_type($this->keywords)) {
+        // Compare to see if our contexts were met.
+        if (!empty($this->restrictions) && !empty($context->restrictions)) {
+          foreach ($this->restrictions as $key => $values) {
+            // If we have a restriction, the context must either not have that
+            // restriction listed, which means we simply don't know what it is,
+            // or there must be an intersection of the restricted values on
+            // both sides.
+            if (!is_array($values)) {
+              $values = array($values);
+            }
+            if (!empty($context->restrictions[$key]) && !array_intersect($values, $context->restrictions[$key])) {
+              continue 2;
+            }
+          }
+        }
         $result[$cid] = $context;
       }
     }
@@ -1323,3 +1346,34 @@ function ctools_access_new_test($plugin) {
 
   return $test;
 }
+
+/**
+ * Apply restrictions to contexts based upon the access control configured.
+ *
+ * These restrictions allow the UI to not show content that may not
+ * be relevant to all types of a particular context.
+ */
+function ctools_access_add_restrictions($settings, $contexts) {
+  if (empty($settings['plugins'])) {
+    return;
+  }
+
+  if (!isset($settings['logic'])) {
+    $settings['logic'] = 'and';
+  }
+
+  // We're not going to try to figure out restrictions on the or.
+  if ($settings['logic'] == 'or' && count($settings['plugins']) > 1) {
+    return;
+  }
+
+  foreach ($settings['plugins'] as $test) {
+    $plugin = ctools_get_access_plugin($test['name']);
+    if ($plugin && $function = ctools_plugin_get_function($plugin, 'restrictions')) {
+      $required_context = isset($plugin['required context']) ? $plugin['required context'] : array();
+      $context = isset($test['context']) ? $test['context'] : array();
+      $contexts = ctools_context_select($contexts, $required_context, $context);
+      $function($test['settings'], $contexts);
+    }
+  }
+}
diff --git a/plugins/access/node_type.inc b/plugins/access/node_type.inc
index 5c7afdfe..e6cbb2a2 100644
--- a/plugins/access/node_type.inc
+++ b/plugins/access/node_type.inc
@@ -19,6 +19,7 @@ function ctools_node_type_ctools_access() {
     'settings form submit' => 'ctools_node_type_ctools_access_settings_submit',
     'summary' => 'ctools_node_type_ctools_acesss_summary',
     'required context' => new ctools_context_required(t('Node'), 'node'),
+    'restrictions' => 'ctools_node_type_ctools_access_restrictions',
   );
 
   return $args;
@@ -66,6 +67,19 @@ function ctools_node_type_ctools_access_check($conf, $context) {
   return TRUE;
 }
 
+/**
+ * Inform the UI that we've eliminated a bunch of possibilities for this
+ * context.
+ */
+function ctools_node_type_ctools_access_restrictions($conf, &$context) {
+  if (isset($context->restrictions['type'])) {
+    $context->restrictions['type'] = array_unique(array_merge($context->restrictions['type'], array_keys(array_filter($conf['type']))));
+  }
+  else {
+    $context->restrictions['type'] = array_keys(array_filter($conf['type']));
+  }
+}
+
 /**
  * Provide a summary description based upon the checked node_types.
  */
diff --git a/plugins/contexts/node.inc b/plugins/contexts/node.inc
index 12217a65..147963a8 100644
--- a/plugins/contexts/node.inc
+++ b/plugins/contexts/node.inc
@@ -36,16 +36,7 @@ function ctools_node_ctools_contexts() {
  * are not always created from the UI.
  */
 function ctools_context_create_node($empty, $data = NULL, $conf = FALSE) {
-  $types = array('node');
-
-  if (!empty($conf['types'])) {
-    foreach ($conf['types'] as $type) {
-      if ($type) {
-        $types[] = 'node-' . $type;
-      }
-    }
-  }
-  $context = new ctools_context($types);
+  $context = new ctools_context('node');
   $context->plugin = 'node';
 
   if ($empty) {
@@ -71,12 +62,8 @@ function ctools_context_create_node($empty, $data = NULL, $conf = FALSE) {
     $context->data     = $data;
     $context->title    = $data->title;
     $context->argument = $data->nid;
-    if (is_array($context->type)) {
-      $context->type[] = 'node-' . $data->type;
-    }
-    else {
-      $context->type = array($context->type, 'node-' . $data->type);
-    }
+
+    $context->restrictions['type'] = array($data->type);
     return $context;
   }
 }
diff --git a/plugins/contexts/node_add_form.inc b/plugins/contexts/node_add_form.inc
index bd1dc964..60dc5917 100644
--- a/plugins/contexts/node_add_form.inc
+++ b/plugins/contexts/node_add_form.inc
@@ -70,6 +70,7 @@ function ctools_context_create_node_add_form($empty, $data = NULL, $conf = FALSE
       $context->form_id    = $type . '_node_form';
       $context->form_title = t('Submit @name', array('@name' => $types[$type]->name));
       $context->node_type  = $type;
+      $context->restrictions['type'] = array($type);
       return $context;
     }
   }
diff --git a/plugins/contexts/node_edit_form.inc b/plugins/contexts/node_edit_form.inc
index 92c840d4..91fbb3e6 100644
--- a/plugins/contexts/node_edit_form.inc
+++ b/plugins/contexts/node_edit_form.inc
@@ -62,6 +62,7 @@ function ctools_context_create_node_edit_form($empty, $node = NULL, $conf = FALS
     $context->form_id    = $form_id;
     $context->form_title = $node->title;
     $context->node_type  = $node->type;
+    $context->restrictions['type'] = array($node->type);
     return $context;
   }
 }
-- 
GitLab