flexiaccess.users.inc in Flexi Access 7
Form handling for per user ACL.
File
flexiaccess.users.incView source
<?php
/**
* @file
* Form handling for per user ACL.
*/
/**
* Build form to handle ACLs for user.
*
* See http://passingcuriosity.com/2011/drupal-7-forms-tables/.
*/
function flexiaccess_user($form, &$form_state, $user) {
if (module_exists('acl')) {
/**
* First, a utility function to help code re-use.
*/
function addrow($row, &$form, $user) {
$cell_node = array(
'#type' => 'markup',
'#markup' => '<strong>' . t('#!nid: !title', array(
'!nid' => $row->nid,
'!title' => $row->title,
)) . '</strong>',
);
$cell_view = array(
'#type' => 'checkbox',
'#title' => t('View'),
'#default_value' => $row->grant_view,
);
$cell_update = array(
'#type' => 'checkbox',
'#title' => t('Update'),
'#default_value' => $row->grant_update,
);
$cell_delete = array(
'#type' => 'checkbox',
'#title' => t('Delete'),
'#default_value' => $row->grant_delete,
);
$form['acl'][] = array(
'node' => &$cell_node,
'nid' => array(
'#type' => 'value',
'#value' => $row->nid,
),
'view' => &$cell_view,
'update' => &$cell_update,
'delete' => &$cell_delete,
);
}
/* end function addrow */
$query = db_select('acl_user', 'u');
$query
->join('acl', 'a', 'a.acl_id = u.acl_id');
$query
->join('acl_node', 'n', 'a.acl_id = n.acl_id');
$query
->join('node', 'node', 'n.nid = node.nid');
$query
->fields('a', array(
'acl_id',
))
->fields('n', array(
'nid',
))
->fields('node', array(
'title',
))
->fields('node', array(
'uid',
))
->fields('node', array(
'type',
));
$query
->addExpression('SUM(n.grant_view)', 'grant_view');
$query
->addExpression('SUM(n.grant_update)', 'grant_update');
$query
->addExpression('SUM(n.grant_delete)', 'grant_delete');
$query
->condition('a.module', 'flexiaccess')
->condition('u.uid', $user->uid)
->groupBy('n.nid');
$result = $query
->execute();
$form_state['user'] = $user;
// The permissions table:
$form['acl'] = array(
'#title' => t('Node based ACL'),
'#prefix' => '<div id="flexiaccess-user-acl-table"><p><em>' . t('Manage the nodes which this user has access to. Remember to press “Commit updates” when done (otherwise, your changes will not be saved).') . '</em></p>',
'#suffix' => '</div>',
'#tree' => TRUE,
// @todo: Check this out.
// See: http://drupal.stackexchange.com/questions/90282/d7-fapi-unexpected-bahviour-when-combining-ajax-checkbox-and-a-table-theme
// '#theme' => 'table',
'#header' => array(
t("Node"),
t("View"),
t("Update"),
t("Delete"),
),
'#rows' => array(),
);
$form['add'] = array(
'#type' => 'textfield',
'#title' => t('Add node'),
'#size' => 60,
'#autocomplete_path' => 'flexiaccess/node_autocomplete',
);
$form['add_button'] = array(
'#type' => 'button',
'#name' => 'acl_user_' . $user->uid,
'#value' => t('Add Node'),
'#ajax' => array(
'callback' => 'flexiaccess_user_ajax_callback',
'wrapper' => 'flexiaccess-user',
'method' => 'replace',
'effect' => 'fade',
),
);
foreach ($result as $row) {
addrow($row, $form, $user);
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Commit updates'),
'#weight' => 10,
'#submit' => array(
'flexiaccess_user_submit',
),
);
// Determine whether we are rebuilding the form.
// This is 1 when a row is being added via ajax.
if ($form_state['rebuild']) {
// Check if there are previously added, but uncommitted rows.
if (empty($form_state['uncommitted'])) {
$form_state['uncommitted'] = array();
}
// Find the correct node titles.
if (!empty($form_state['uncommitted'])) {
$result = db_query('SELECT nid,title, 0 AS grant_view, 0 AS grant_update, 0 AS grant_delete FROM {node} WHERE nid IN (:nids)', array(
':nids' => $form_state['uncommitted'],
));
// Add the rows.
if ($result
->rowCount()) {
foreach ($result as $row) {
addrow($row, $form, $user);
}
}
}
}
$form['#tree'] = TRUE;
return $form;
}
}
/**
* AJAX callback to add a node to the table on the user page.
*/
function flexiaccess_user_ajax_callback($form, $form_state) {
// Return the part of the (rebuilt) form to be replaced.
return $form;
}
/**
* Menu callback.
*
* Retrieve a JSON object containing autocomplete suggestions for
* existing nodes.
*/
function flexiaccess_node_autocomplete($string = '') {
// TODO: What if range(0,50) does not show the required nodes?
// TODO: maybe break up search string in words and add separate OR'd
// conditions with foreach?
$matches = array();
if ($string) {
// Get active content types that have Flexi access managing their ACL.
$types = array_filter(variable_get('flexiaccess_types', array()));
if (!empty($types)) {
$result = db_select('node')
->fields('node', array(
'title',
'nid',
))
->condition('type', $types, 'IN')
->condition('title', '%' . db_like($string) . '%', 'LIKE')
->range(0, 50)
->execute();
foreach ($result as $node) {
$matches[$node->nid] = check_plain("{$node->nid} : {$node->title}");
}
}
}
drupal_json_output($matches);
}
/**
* Commit updates from user page.
*/
function flexiaccess_user_submit($form, &$form_state) {
if (empty($form_state['uncommitted'])) {
$form_state['uncommitted'] = array();
}
foreach ($form_state['values']['acl'] as $ac) {
if (in_array($ac['nid'], $form_state['uncommitted'])) {
// New relationship between user and node.
// Create acls for node where necessary.
_flexiaccess_create_acl_rows($ac['nid']);
}
// Add acls to user.
/*
* The following is easily accomplished with a single query.
* The correct way to do it, however, is to use the API, which
* unfortunately uses many queries.
* Would a single query be better at avoiding race conditions?
*/
foreach (array(
'view',
'update',
'delete',
) as $op) {
$acl_id = acl_get_id_by_name('flexiaccess', $op . '_' . $ac['nid']);
// Doing both add and remove here ensures that the latest form
// submission takes effect in the db:
if (1 == $ac[$op]) {
// Add permission.
acl_add_user($acl_id, $form_state['user']->uid);
}
else {
// This block will only be reached when multiple admins have
// edited the same permissions. Remove permission.
acl_remove_user($acl_id, $form_state['user']->uid);
}
}
// Apply changes for the node.
node_access_acquire_grants(node_load($ac['nid']));
}
cache_clear_all();
drupal_set_message(t('Your changes to the ACL has been saved.'));
}
function flexiaccess_user_validate($form, &$form_state) {
$types = array_filter(variable_get('flexiaccess_types', array()));
if (!is_numeric($form_state['values']['add'])) {
form_set_error('add', t('Enter a node ID, or type the title and select a node from the autocomplete list.'));
return;
}
$node = node_load($form_state['values']['add']);
if (!$node) {
form_set_error('add', t('Could not find a node with ID @nid', array(
'@nid' => $form_state['values']['add'],
)));
return;
}
if (!in_array($node->type, $types)) {
form_set_error('add', t('Flexiaccess is not configured to manage nodes of type <code>!type</code>.', array(
'!type' => $node->type,
)));
return;
}
// If all is OK, add the new nid to the list of uncommitted nodes.
$form_state['uncommitted'][] = $node->nid;
}
Functions
Name![]() |
Description |
---|---|
flexiaccess_node_autocomplete | Menu callback. |
flexiaccess_user | Build form to handle ACLs for user. |
flexiaccess_user_ajax_callback | AJAX callback to add a node to the table on the user page. |
flexiaccess_user_submit | Commit updates from user page. |
flexiaccess_user_validate |