Have you ever wanted to grant access to a certain list of users so they could access a Drupal Webform's submission results? The default permissions that come with Webform don't provide much granularity in this scenario, so a custom solution needs to be implemented.
Luckily Webform has a few hooks to make our lives easier.
By adding an unlimited value user reference field to the Webform content type (e.g. field_webform_results_access) and implementing the two hooks above, this can be accomplished. The user reference field will allow you to attach users to a webform node, then if that user is listed in that field on the webform node, then they can access the webform submission results. We just have to write a little code to accomplish this, for example:
/**
* Implementation of hook_webform_results_access().
*/
function my_module_webform_results_access($node, $account = NULL) {
return my_module_webform_access($node, $account);
}
/**
* Implementation of hook_webform_submission_access().
*/
function my_module_webform_submission_access($node, $submission, $op = 'view', $account = NULL) {
return my_module_webform_access($node, $account);
}
/**
* Returns true if account is a value in the webform results user
* reference field on the webform content type.
*
* @param object $node
* The webform node.
* @param object $account
* The user account, optional. Defaults to current user.
*
* @return bool
* Returns true if user is listed, false otherwise.
*/
function my_module_webform_access ($node, $account = NULL) {
global $user;
$account = isset($account) ? $account : $user;
$access = false;
if (isset($node->field_webform_results_access[0]['uid'])) {
// This webform has user(s) specified for submission results access control.
if (user_access("administer nodes") || user_access("edit any webform content")) {
$access = true;
}
else {
// For each user specified, make sure the current user is one of them,
// otherwise don't show the results.
foreach ($node->field_webform_results_access as $i => $user_reference) {
if ($user_reference['uid'] == $account->uid) {
$access = true;
break;
}
}
}
}
return $access;
}
That's all folks, just flush all of your caches and you should be all set. Add some user's to the user reference field on your webform nodes and then they'll be able to access the submission results on that webform.
Older Versions of Webform
Before Webform offered the hooks mentioned above (I'm not sure when the hooks were introduced, I didn't notice them until Webform 3.17), we had to take a slightly different approach to accomplish the same task. We needed to work with hook_menu_alter and our theme's template.php file, for example this is how I accomplished the same thing in Webform 3.2:
function my_module_menu_alter ($items) {
// attach a custom access callback function to webform results and submissions
if (module_exists("webform")) {
// webform results menu paths
$result_menu_paths = array(
'node/%webform_menu/webform-results',
'node/%webform_menu/webform-results/submissions',
'node/%webform_menu/webform-results/analysis',
'node/%webform_menu/webform-results/analysis/%webform_menu_component',
'node/%webform_menu/webform-results/table',
'node/%webform_menu/webform-results/download',
);
foreach ($result_menu_paths as $result_menu_path) {
$items[$result_menu_path]['access callback'] = 'my_module_webform_results_access';
}
// webform submission menu paths
$submission_menu_paths = array(
'node/%webform_menu/submissions',
'node/%webform_menu/submission/%webform_menu_submission',
'node/%webform_menu/submission/%webform_menu_submission/view',
);
foreach ($submission_menu_paths as $submission_menu_path) {
$items[$submission_menu_path]['access callback'] = 'my_module_webform_submission_access';
}
}
}
// override of webform_results_access
function my_module_webform_results_access ($node, $account = NULL) {
global $user;
$account = isset($account) ? $account : $user;
// this is webform's default way of dealing with access, if this doesn't pass, fall back to our custom access check
$webform_access = node_access('view', $node, $account) && (user_access('access all webform results', $account) || (user_access('access own webform results', $account) && $account->uid == $node->uid));
if ($webform_access) {
return true;
}
else {
return my_module_webform_access($node);
}
}
// override of webform_submission_access
function my_module_webform_submission_access($node, $submission, $op = 'view', $account = NULL) {
global $user;
$account = isset($account) ? $account : $user;
$access_all = user_access('access all webform results', $account);
$access_own_submission = isset($submission) && user_access('access own webform submissions', $account) && (($account->uid && $account->uid == $submission->uid) || isset($_SESSION['webform_submission'][$submission->sid]));
$access_node_submissions = user_access('access own webform results', $account) && $account->uid == $node->uid;
$general_access = $access_all || $access_own_submission || $access_node_submissions || my_module_webform_access($node);
// Disable the page cache for anonymous users in this access callback,
// otherwise the "Access denied" page gets cached.
if (!$account->uid && user_access('access own webform submissions', $account)) {
webform_disable_page_cache();
}
switch ($op) {
case 'view':
return $general_access;
case 'edit':
return $general_access && (user_access('edit all webform submissions', $account) || (user_access('edit own webform submissions', $account) && $account->uid == $submission->uid));
case 'delete':
return $general_access && (user_access('delete all webform submissions', $account) || (user_access('delete own webform submissions', $account) && $account->uid == $submission->uid));
case 'list':
return user_access('access all webform results', $account) || (user_access('access own webform submissions', $account) && ($account->uid || isset($_SESSION['webform_submission']))) || (user_access('access own webform results', $account) && $account->uid == $node->uid);
}
}
// webform submission results user access cck field check
function my_module_webform_access ($node) {
global $user;
$account = isset($account) ? $account : $user;
$access = false;
if (isset($node->field_webform_results_access[0]['uid'])) { // this webform has uniqname(s) specified for access control
if (user_access("administer nodes") || user_access("edit any webform content")) {
$access = true;
}
else {
// for each uniqname specified, make sure the current user is one of them, otherwise don't show the results
foreach ($node->field_webform_results_access as $i => $user_reference) {
if ($user_reference['uid'] == $account->uid) {
$access = true;
break;
}
}
}
}
return $access;
}
And then a few simple template.php overriddes for themeing the webform properly [ the only difference is adding a call to my_theme_webform_access($node) ] :
/**
* MY THEME OVERRIDE - Theme the header of the submissions table.
*
* This is done in it's own function so that webform can retrieve the header and
* use it for sorting the results.
*/
function my_theme_webform_results_submissions_header($node) {
global $user;
$columns = array(
array('data' => t('#'), 'field' => 'sid', 'sort' => 'asc'),
array('data' => t('Submitted'), 'field' => 'submitted'),
);
if (
user_access('access all webform results') ||
(user_access('access own webform results') && $user->uid == $node->uid) ||
my_theme_webform_access($node)
) {
$columns[] = array('data' => t('User'), 'field' => 'name');
$columns[] = array('data' => t('IP Address'), 'field' => 'remote_addr');
}
$columns[] = array('data' => t('Operations'), 'colspan' => module_exists('print') ? 5 : 3);
return $columns;
}
/**
* MY THEME OVERRIDE - Theme the submissions tab of the webform results page.
*
* @param $node
* The node whose results are being displayed.
* @param $submissions
* An array of all submissions for this webform.
* @param $total_count
* The total number of submissions to this webform.
* @param $pager_count
* The number of results to be shown per page.
*/
function my_theme_webform_results_submissions($node, $submissions, $total_count = 0, $pager_count = 0) {
global $user;
drupal_add_css(drupal_get_path('module', 'webform') . '/css/webform-admin.css', 'theme', 'all', FALSE);
// This header has to be generated separately so we can add the SQL necessary
// to sort the results.
$header = theme('webform_results_submissions_header', $node);
$operation_column = end($header);
$operation_total = $operation_column['colspan'];
$rows = array();
foreach ($submissions as $sid => $submission) {
$row = array(
$submission->is_draft ? t('@sid (draft)', array('@sid' => $sid)) : $sid,
format_date($submission->submitted, 'small'),
);
if (
user_access('access all webform results') ||
(user_access('access own webform results') && $user->uid == $node->uid) ||
my_theme_webform_access($node)
) {
$row[] = theme('username', $submission);
$row[] = $submission->remote_addr;
}
$row[] = l(t('View'), "node/$node->nid/submission/$sid");
$operation_count = 1;
if (module_exists('print_pdf') && user_access('access PDF version')) {
$row[] = l(t('PDF'), "printpdf/$node->nid/submission/$sid", array('query' => drupal_get_destination()));
$operation_count++;
}
if (module_exists('print') && user_access('access print')) {
$row[] = l(t('Print'), "print/$node->nid/submission/$sid");
$operation_count++;
}
if ((user_access('edit own webform submissions') && $user->uid == $submission->uid) || user_access('edit all webform submissions')) {
$row[] = l(t('Edit'), "node/$node->nid/submission/$sid/edit", array('query' => drupal_get_destination()));
$operation_count++;
}
if ((user_access('delete own webform submissions') && $user->uid == $submission->uid) || user_access('delete all webform submissions')) {
$row[] = l(t('Delete'), "node/$node->nid/submission/$sid/delete", array('query' => drupal_get_destination()));
$operation_count++;
}
if ($operation_count < $operation_total) {
$row[count($row) - 1] = array('data' => $row[count($row) - 1], 'colspan' => $operation_total - $operation_count + 1);
}
$rows[] = $row;
}
if (count($rows) == 0) {
$rows[] = array(array('data' => t('There are no submissions for this form. <a href="!url">View this form</a>.', array('!url' => url('node/' . $node->nid))), 'colspan' => 4 + $operation_total));
}
$output = '';
$output .= theme('webform_results_per_page', $total_count, $pager_count);
$output .= theme('table', $header, $rows);
if (arg(2) == 'submissions') {
$output .= theme('links', array('webform' => array('title' => t('Go back to the form'), 'href' => 'node/' . $node->nid)));
}
if ($pager_count) {
$output .= theme('pager', NULL, $pager_count, 0);
}
return $output;
}
As you can see, there is a lot more code involved in doing this without the new hooks introduced by later version of Webform 3.x. So, you might as well just update your webform module to the latest version.
Add new comment