Commit 76ffc01a authored by Eric Rasmussen's avatar Eric Rasmussen
Browse files

[gh-590] Upgrade Workbench suite

parent e6a7855b
......@@ -3,7 +3,7 @@
* README file for Workbench.
*/
Workbench
Workbench
A framework for simplified content management.
CONTENTS
......@@ -93,7 +93,7 @@ immediately useful.
Allows a user to see content that is not Published on the site. This
becomes even more useful when Workbench Moderation is enabled.
A typical permission setup so that a user can take advangate of Workbench
A typical permission setup so that a user can take advantage of Workbench
looks like:
Node Permissions
......@@ -209,4 +209,4 @@ via Views UI as well.
-- publish permissions per content type
-- email notifications
-- integrate scheduler module for scheduled start/end publish dates
-- general UX improvements
\ No newline at end of file
-- general UX improvements
......@@ -5,18 +5,19 @@
* Default View for information about the current user.
*/
$view = new view;
$view = new view();
$view->name = 'workbench_current_user';
$view->description = 'Information about the current user.';
$view->tag = 'Workbench';
$view->base_table = 'users';
$view->human_name = '';
$view->human_name = 'Workbench: Current user';
$view->core = 7;
$view->api_version = '3.0';
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
/* Display: Defaults */
$handler = $view->new_display('default', 'Defaults', 'default');
$handler->display->display_options['use_more_always'] = FALSE;
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['access']['perm'] = 'access workbench';
$handler->display->display_options['cache']['type'] = 'none';
......@@ -33,66 +34,29 @@ $handler->display->display_options['fields']['uid']['table'] = 'users';
$handler->display->display_options['fields']['uid']['field'] = 'uid';
$handler->display->display_options['fields']['uid']['label'] = '';
$handler->display->display_options['fields']['uid']['exclude'] = TRUE;
$handler->display->display_options['fields']['uid']['alter']['alter_text'] = 0;
$handler->display->display_options['fields']['uid']['alter']['make_link'] = 0;
$handler->display->display_options['fields']['uid']['alter']['absolute'] = 0;
$handler->display->display_options['fields']['uid']['alter']['word_boundary'] = 0;
$handler->display->display_options['fields']['uid']['alter']['ellipsis'] = 0;
$handler->display->display_options['fields']['uid']['alter']['strip_tags'] = 0;
$handler->display->display_options['fields']['uid']['alter']['trim'] = 0;
$handler->display->display_options['fields']['uid']['alter']['html'] = 0;
$handler->display->display_options['fields']['uid']['hide_empty'] = 0;
$handler->display->display_options['fields']['uid']['empty_zero'] = 0;
$handler->display->display_options['fields']['uid']['link_to_user'] = 0;
$handler->display->display_options['fields']['uid']['alter']['word_boundary'] = FALSE;
$handler->display->display_options['fields']['uid']['alter']['ellipsis'] = FALSE;
$handler->display->display_options['fields']['uid']['link_to_user'] = FALSE;
/* Field: User: Picture */
$handler->display->display_options['fields']['picture']['id'] = 'picture';
$handler->display->display_options['fields']['picture']['table'] = 'users';
$handler->display->display_options['fields']['picture']['field'] = 'picture';
$handler->display->display_options['fields']['picture']['label'] = '';
$handler->display->display_options['fields']['picture']['alter']['alter_text'] = 0;
$handler->display->display_options['fields']['picture']['alter']['make_link'] = 0;
$handler->display->display_options['fields']['picture']['alter']['absolute'] = 0;
$handler->display->display_options['fields']['picture']['alter']['word_boundary'] = 1;
$handler->display->display_options['fields']['picture']['alter']['ellipsis'] = 1;
$handler->display->display_options['fields']['picture']['alter']['strip_tags'] = 0;
$handler->display->display_options['fields']['picture']['alter']['trim'] = 0;
$handler->display->display_options['fields']['picture']['alter']['html'] = 0;
$handler->display->display_options['fields']['picture']['element_label_colon'] = 0;
$handler->display->display_options['fields']['picture']['element_default_classes'] = 1;
$handler->display->display_options['fields']['picture']['hide_empty'] = 0;
$handler->display->display_options['fields']['picture']['empty_zero'] = 0;
$handler->display->display_options['fields']['picture']['element_label_colon'] = FALSE;
/* Field: User: Name */
$handler->display->display_options['fields']['name']['id'] = 'name';
$handler->display->display_options['fields']['name']['table'] = 'users';
$handler->display->display_options['fields']['name']['field'] = 'name';
$handler->display->display_options['fields']['name']['label'] = '';
$handler->display->display_options['fields']['name']['alter']['alter_text'] = 0;
$handler->display->display_options['fields']['name']['alter']['make_link'] = 0;
$handler->display->display_options['fields']['name']['alter']['absolute'] = 0;
$handler->display->display_options['fields']['name']['alter']['word_boundary'] = 0;
$handler->display->display_options['fields']['name']['alter']['ellipsis'] = 0;
$handler->display->display_options['fields']['name']['alter']['strip_tags'] = 0;
$handler->display->display_options['fields']['name']['alter']['trim'] = 0;
$handler->display->display_options['fields']['name']['alter']['html'] = 0;
$handler->display->display_options['fields']['name']['hide_empty'] = 0;
$handler->display->display_options['fields']['name']['empty_zero'] = 0;
$handler->display->display_options['fields']['name']['link_to_user'] = 1;
$handler->display->display_options['fields']['name']['overwrite_anonymous'] = 0;
$handler->display->display_options['fields']['name']['alter']['word_boundary'] = FALSE;
$handler->display->display_options['fields']['name']['alter']['ellipsis'] = FALSE;
/* Field: User: Edit link */
$handler->display->display_options['fields']['edit_node']['id'] = 'edit_node';
$handler->display->display_options['fields']['edit_node']['table'] = 'users';
$handler->display->display_options['fields']['edit_node']['field'] = 'edit_node';
$handler->display->display_options['fields']['edit_node']['label'] = '';
$handler->display->display_options['fields']['edit_node']['alter']['alter_text'] = 0;
$handler->display->display_options['fields']['edit_node']['alter']['make_link'] = 0;
$handler->display->display_options['fields']['edit_node']['alter']['absolute'] = 0;
$handler->display->display_options['fields']['edit_node']['alter']['word_boundary'] = 0;
$handler->display->display_options['fields']['edit_node']['alter']['ellipsis'] = 0;
$handler->display->display_options['fields']['edit_node']['alter']['strip_tags'] = 0;
$handler->display->display_options['fields']['edit_node']['alter']['trim'] = 0;
$handler->display->display_options['fields']['edit_node']['alter']['html'] = 0;
$handler->display->display_options['fields']['edit_node']['hide_empty'] = 0;
$handler->display->display_options['fields']['edit_node']['empty_zero'] = 0;
$handler->display->display_options['fields']['edit_node']['alter']['word_boundary'] = FALSE;
$handler->display->display_options['fields']['edit_node']['alter']['ellipsis'] = FALSE;
$handler->display->display_options['fields']['edit_node']['text'] = 'edit my profile';
/* Filter criterion: User: Current */
$handler->display->display_options['filters']['uid_current']['id'] = 'uid_current';
......@@ -102,6 +66,7 @@ $handler->display->display_options['filters']['uid_current']['value'] = '1';
/* Display: Block */
$handler = $view->new_display('block', 'Block', 'block_1');
$handler->display->display_options['defaults']['hide_admin_links'] = FALSE;
$translatables['workbench_current_user'] = array(
t('Defaults'),
t('more'),
......
......@@ -5,9 +5,9 @@ core = 7.x
configure = admin/config/workbench/settings
dependencies[] = views
; Information added by drupal.org packaging script on 2011-11-02
version = "7.x-1.1"
; Information added by drupal.org packaging script on 2013-01-18
version = "7.x-1.2"
core = "7.x"
project = "workbench"
datestamp = "1320263738"
datestamp = "1358534592"
......@@ -15,7 +15,7 @@ function workbench_menu() {
'title' => 'Workbench',
'description' => 'Workbench',
'page callback' => 'system_admin_menu_block_page',
'access arguments' => array('access workbench'),
'access arguments' => array('administer workbench'),
'position' => 'right',
'file' => 'system.admin.inc',
'file path' => drupal_get_path('module', 'system'),
......@@ -190,7 +190,7 @@ function workbench_preprocess_views_view_field(&$variables) {
if (empty($variables['output'])) {
// We could put the default picture here
$variables['output'] = theme('image', array(
'path' => drupal_get_path('module', 'workbench') . '/images/profile_default.jpg',
'path' => drupal_get_path('module', 'workbench') . '/images/profile_default.png',
'attributes' => array(
'width' => '100px',
),
......
......@@ -56,6 +56,13 @@ function workbench_content() {
if (isset($output[$key]['#view']) && $view = views_get_view($output[$key]['#view'])) {
$output[$key] += array('#markup' => '', '#view_display' => 'default');
$display_id = $output[$key]['#view_display'];
// Build contextual links.
if (module_exists('contextual')) {
$output[$key] += contextual_element_info();
views_add_contextual_links($output[$key]['contextual_links'], 'block', $view, $display_id);
}
if ($view->access($display_id)) {
$output[$key]['#markup'] .= $view->preview($display_id, array());
if ($title = $view->get_title()) {
......
......@@ -19,6 +19,12 @@ function theme_workbench_element($variables) {
$title = '<h3>' . check_plain($element['#title']) . '</h3>';
}
$contextual = '';
if (!empty($element['contextual_links'])) {
$contextual = drupal_render($element['contextual_links']);
$element['#attributes']['class'][] = 'contextual-links-region';
}
// Use #attributes to customize a wrapper <div>.
$attributes = '';
if (!empty($element['#attributes'])) {
......@@ -31,6 +37,6 @@ function theme_workbench_element($variables) {
}
// Build simple output.
$output = "<div{$attributes}>{$title}{$element['#children']}</div>";
$output = "<div{$attributes}>{$title}{$contextual}{$element['#children']}</div>";
return $output;
}
......@@ -22,7 +22,7 @@ class workbench_access_handler_field_edit_node extends views_handler_field {
if (!node_access('update', $node)) {
return '';
}
$text = !empty($this->options['text']) ? $this->options['text'] : t('edit');
$text = !empty($this->options['text']) ? $this->options['text'] : t('Edit');
return l($text, "node/$values->nid/edit", array('query' => drupal_get_destination()));
}
}
......@@ -12,8 +12,8 @@
class workbench_access_handler_field_section extends views_handler_field_prerender_list {
function init(&$view, &$options) {
parent::init($view, $options);
if ($view->base_table == 'node_revisions') {
$this->additional_fields['nid'] = array('table' => 'node_revisions', 'field' => 'nid');
if ($view->base_table == 'node_revision') {
$this->additional_fields['nid'] = array('table' => 'node_revision', 'field' => 'nid');
}
else {
$this->additional_fields['nid'] = array('table' => 'node', 'field' => 'nid');
......
......@@ -8,6 +8,11 @@
*/
class workbench_access_handler_filter_access extends views_handler_filter_many_to_one {
function init(&$view, &$options) {
parent::init($view, $options);
$this->value = array($options['access_id']);
}
function option_definition() {
$options = parent::option_definition();
$options['access_id'] = array('default' => NULL);
......@@ -21,11 +26,12 @@ class workbench_access_handler_filter_access extends views_handler_filter_many_t
);
}
function get_value_options() {
return workbench_access_active_options();
}
function value_form(&$form, &$form_state) {
$active = workbench_access_get_active_tree();
$tree = $active['tree'];
workbench_access_build_tree($tree, array_keys($active['active']));
$options = workbench_access_options($tree, $active['active']);
$options = $this->get_value_options();
$form['access_id'] = array(
'#type' => 'select',
'#title' => t('Sections'),
......@@ -42,14 +48,16 @@ class workbench_access_handler_filter_access extends views_handler_filter_many_t
);
}
function value_submit($form, &$form_state) {
$this->value = $form_state['values']['access_id'];
}
function exposed_form(&$form, &$form_state) {
// Prevent parent form errors by using a value.
$form['value'] = array('#type' => 'value', '#value' => '');
parent::exposed_form($form, $form_state);
// Build our form element.
$active = workbench_access_get_active_tree();
$tree = workbench_access_get_user_tree();
$options = workbench_access_options($tree, $active['active']);
$options = workbench_access_active_options();
$form['access_id'] = array(
'#type' => 'select',
'#multiple' => TRUE,
......@@ -70,8 +78,9 @@ class workbench_access_handler_filter_access extends views_handler_filter_many_t
global $user;
static $node_types;
// If not configured, do nothing.
// If workbench_access is not configured, do nothing.
$active = workbench_access_get_active_tree();
$access_table = $active['access_scheme']['field_table'];
$tree = $active['tree'];
if (empty($tree)) {
return;
......@@ -79,56 +88,78 @@ class workbench_access_handler_filter_access extends views_handler_filter_many_t
// Check the user's access.
$account = $user; // Not a clone, but that's ok, since we need this data on $user.
// Load workbench_access user data onto the account object.
if (!isset($account->workbench_access)) {
workbench_access_user_load_data($account);
}
// If empty, return nothing by forcing a null return.
if (empty($account->workbench_access)) {
// Get node types that do not use workbench_access for access control.
$node_types = array();
foreach (node_type_get_names() as $type => $name) {
if (!variable_get('workbench_access_node_type_' . $type, TRUE)) {
$node_types[$type] = $type;
}
}
// Here we start altering the query. All of our alters should be their own
// where group.
// If the user has no workbench_access rights, and all node types use
// workbench_access, force the query to return nothing.
if (empty($account->workbench_access) && empty($node_types)) {
$table = $this->view->base_table;
$this->query->add_where($this->options['group'], "$table.nid", -1, '=');
$group = $this->query->set_where_group('OR');
$this->query->add_where($group, "$table.nid", -1, '=');
return;
}
// No selection? Use the user's tree.
if (empty($this->value) || $this->value[0] == -5) {
// If there is no selection, use the user's own access tree.
if (empty($this->value[0]) || $this->value[0] == -5) {
workbench_access_build_tree($tree, array_keys($account->workbench_access));
$group = $this->query->set_where_group('OR');
$node_type_filter = TRUE;
}
// Build the selection tree.
else {
workbench_access_build_tree($tree, array_keys($this->value[0]));
$group = $this->query->set_where_group('AND');
$node_type_filter = FALSE;
}
// Build the query. Since we allow multi-select, this has to be a subquery.
$ids = array_keys($tree);
$table = $active['access_scheme']['field_table'];
$subquery = db_select($table, $table);
$subquery->addField($table, 'nid');
$subquery->distinct();
$subquery->condition($table . '.' . $active['access_scheme']['query_field'], $ids, 'IN');
$subquery->condition($table . '.access_scheme', $active['access_scheme']['access_scheme']);
// Filter out node types not governed by this module.
// See http://drupal.org/node/1082220.
if (!isset($node_types)) {
$node_types = array();
foreach (node_type_get_names() as $type => $name) {
$node_types[$type] = variable_get('workbench_access_node_type_' . $type, 1);
// Build the workbench_access where clause.
if (!empty($tree)) {
// Since we allow multi-select, this has to be a subquery.
$ids = array_keys($tree);
$table = $active['access_scheme']['field_table'];
$subquery = db_select($table, $table);
$subquery->addField($table, 'nid');
$subquery->distinct();
$subquery->condition($table . '.' . $active['access_scheme']['query_field'], $ids, 'IN');
$subquery->condition($table . '.access_scheme', $active['access_scheme']['access_scheme']);
$this->query->add_where($group, "{$this->query->base_table}.nid", $subquery, 'IN');
}
// If not all node types use workbench access for permissions, add them here.
if (!empty($node_types)) {
$table = $this->query->base_table;
// Ensure that we have a proper table when using a relationship from a non-node base table.
// @TODO: There may be cleaner ways to do this lookup.
if (isset($this->view->relationship['vid'])) {
$table = $this->view->relationship['vid']->alias;
}
if ($node_types == array_filter($node_types)) {
// If there were no node types that are not allowed, set the static
// variable to FALSE to indicate no restriction by node type.
$node_types = FALSE;
elseif (isset($this->view->relationship['nid'])) {
$table = $this->view->relationship['nid']->alias;
}
// If no filter is active, then we allow node types not under access control.
if ($node_type_filter) {
$this->query->add_where($group, "$table.type", $node_types, 'IN');
}
// If a filter is active, we disallow node types not under access control.
else {
$this->query->add_where($group, "$table.type", $node_types, 'NOT IN');
}
}
// If not all node types are allowed, filter out those not used.
// This has to go in the subquery, not the Views query.
if ($node_types !== FALSE) {
$alias = $subquery->join('node', 'n', "$table.nid = n.nid");
$subquery->condition("$alias.type", array_keys($node_types), 'IN');
}
// Now alter the query, which must have an nid in the base table.
$this->query->add_where($this->options['group'], $this->query->base_table . '.nid', $subquery, 'IN');
}
}
......@@ -19,6 +19,9 @@ function menu_workbench_access_info() {
'access_type_id' => array_filter(variable_get('workbench_access_menu', array('main-menu'))),
'description' => t('Uses the menu system for assigning hierarchical access control.'),
'configuration' => 'menu_workbench_access_configuration',
'form_field' => 'menu',
'storage_column' => 'mlid',
'translatable' => FALSE,
'node_table' => 'workbench_access_node',
'query_field' => 'access_id',
'field_table' => 'workbench_access_node',
......@@ -77,6 +80,12 @@ function menu_workbench_access_configuration(&$form, &$form_state) {
),
),
);
$form['menu_workbench_access_info']['workbench_access_menu_limit'] = array(
'#type' => 'checkbox',
'#title' => t('Limit available menu items based on Workbench Access.'),
'#description' => t('If checked, when creating nodes users will not be able to choose a parent menu item to which they do not have editorial access.'),
'#default_value' => variable_get('workbench_access_menu_limit', 1),
);
}
/**
......@@ -108,27 +117,33 @@ function menu_workbench_access_tree($info, $keys) {
$items[$key] = 0;
}
}
$tree = array();
foreach ($items as $name => $mlid) {
$data = menu_load($name);
$tree[$name] = array(
'access_id' => $data['menu_name'],
'access_type_id' => $data['menu_name'],
'name' => $data['title'],
'description' => $data['description'],
'weight' => 0,
'depth' => 0,
'parent' => 0,
);
$menu = menu_tree_all_data($name);
foreach ($menu as $link) {
if (empty($data['menu_name'])) {
break;
}
if ($mlid == 0) {
$tree[$name] = array(
'access_id' => $data['menu_name'],
'access_type_id' => $data['menu_name'],
'name' => $data['title'],
'description' => $data['description'],
'weight' => 0,
'depth' => 0,
'parent' => 0,
);
$mlid = TRUE;
}
// This call returns a nested array.
// @todo, given the use of a private function here, we might need our
// own lookup instead.
$menu = _menu_build_tree($name);
foreach ($menu['tree'] as $link) {
// Ensure that we start at the top of the current request.
if ($mlid > 0 && $link['link']['mlid'] == $mlid) {
$tree = array();
_workbench_access_menu_build_tree($tree, $link);
}
elseif ($mlid == 0) {
_workbench_access_menu_build_tree($tree, $link);
}
// If mlid is TRUE, we are at the root.
_workbench_access_menu_build_tree($tree, $link, $mlid);
}
}
if ($keys) {
......@@ -144,21 +159,31 @@ function menu_workbench_access_tree($info, $keys) {
* The workbench access tree being built.
* @param $link
* The menu link being inspected.
* @param $mlid
* The menu link id being acted upon. May be 0 if this is the top-level menu
* item. Switches to TRUE so that children of a matching item can be selected.
*/
function _workbench_access_menu_build_tree(&$tree, $link) {
function _workbench_access_menu_build_tree(&$tree, $link, $mlid = 0) {
$item = (object) $link['link'];
$tree[$item->mlid] = array(
'access_id' => $item->mlid,
'access_type_id' => $item->menu_name,
'name' => $item->link_title,
'description' => isset($item->options['attributes']['title']) ? $item->options['attributes']['title'] : '',
'weight' => $item->weight,
'depth' => $item->depth,
'parent' => ($item->plid == 0) ? $item->menu_name : $item->plid,
);
// If the item matches the expected link id, or is the top-level, continue.
if ($item->mlid == $mlid || $mlid === TRUE) {
$tree[$item->mlid] = array(
'access_id' => $item->mlid,
'access_type_id' => $item->menu_name,
'name' => $item->link_title,
'description' => isset($item->options['attributes']['title']) ? $item->options['attributes']['title'] : '',
'weight' => $item->weight,
'depth' => $item->depth,
'parent' => ($item->plid == 0) ? $item->menu_name : $item->plid,
);
// Access to the parent grants access to the children.
$mlid = TRUE;
}
// menu_tree_all_data() returns a nested array, so if we don't start at the
// top level of the tree, then we must check below links individually.
if (!empty($link['below'])) {
foreach ($link['below'] as $below) {
_workbench_access_menu_build_tree($tree, $below);
_workbench_access_menu_build_tree($tree, $below, $mlid);
}
}
}
......@@ -169,6 +194,7 @@ function _workbench_access_menu_build_tree(&$tree, $link) {
* Load data for a menu.
*/
function menu_workbench_access_load($scheme) {
$data = array();
// This might be a menu or a single menu item.
if ($menu = menu_load($scheme['access_id'])) {
$menu = (object) $menu;
......@@ -178,8 +204,8 @@ function menu_workbench_access_load($scheme) {
'description' => $menu->description,
);
}
else {
$item = (object) menu_link_load($scheme['access_id']);
elseif ($item = menu_link_load($scheme['access_id'])) {
$item = (object) $item;
$data = array(
'access_id' => $item->mlid,
'name' => $item->link_title,
......@@ -189,6 +215,7 @@ function menu_workbench_access_load($scheme) {
return $data;
}
/**
* Implements hook_menu_delete().
*
......@@ -207,7 +234,7 @@ function workbench_access_menu_delete($menu) {
* If an new link is added, check to see if we need to create a section.
*/
function workbench_access_menu_link_insert($link) {
if (variable_get('workbench_access', 'taxonomy') != 'menu' || !variable_get('workbench_access_auto_assign', 1)) {
if (variable_get('workbench_access') != 'menu' || !variable_get('workbench_access_auto_assign', 1)) {
return;
}
$active = array_filter(variable_get('workbench_access_menu', array()));
......@@ -222,6 +249,15 @@ function workbench_access_menu_link_insert($link) {
}
}
/**
* Implements hook_menu_link_update().
*
* If a menu link is updated, refresh the tree.
*/
function workbench_access_menu_link_update($link) {
workbench_access_reset_tree();
}