diff --git a/includes/webform.pages.inc b/includes/webform.pages.inc index f6295dd..57d2abf 100644 --- a/includes/webform.pages.inc +++ b/includes/webform.pages.inc @@ -80,16 +80,48 @@ function webform_configure_form(&$form_state, $node) { '#maxlength' => 255, ); - // Submission limit settings. + // Submission limit settings for all submissions. + $form['submission']['total_submit_limit'] = array( + '#type' => 'item', + '#title' => t('Total submissions limit'), + '#theme' => 'webform_advanced_total_submit_limit_form', + '#description' => t('Limit the total number of allowed submissions.'), + ); + $form['submission']['total_submit_limit']['enforce_total_limit'] = array( + '#type' => 'radios', + '#options' => array('no' => t('Unlimited'), 'yes' => 'Limit to !count total submission(s) !timespan'), + '#default_value' => $node->webform['total_submit_limit'] == -1 ? 'no' : 'yes', + '#parents' => array('enforce_total_limit'), + ); + $form['submission']['total_submit_limit']['total_submit_limit'] = array( + '#type' => 'textfield', + '#maxlength' => 8, + '#size' => 8, + '#default_value' => $node->webform['total_submit_limit'] != -1 ? $node->webform['total_submit_limit'] : '', + '#parents' => array('total_submit_limit'), + ); + $form['submission']['total_submit_limit']['total_submit_interval'] = array( + '#type' => 'select', + '#options' => array( + '-1' => t('ever'), + '3600' => t('every hour'), + '86400' => t('every day'), + '604800' => t('every week'), + ), + '#default_value' => $node->webform['total_submit_interval'], + '#parents' => array('total_submit_interval'), + ); + + // Submission limit per user settings. $form['submission']['submit_limit'] = array( '#type' => 'item', - '#title' => t('Submission limit'), + '#title' => t('Per user submission limit'), '#theme' => 'webform_advanced_submit_limit_form', '#description' => t('Limit the number of submissions per user. A user is identified by their user login if logged-in, or by their IP Address and Cookie if anonymous. Use of cookies may be modified in the global Webform settings.', array('!url' => url('admin/settings/webform'))), ); $form['submission']['submit_limit']['enforce_limit'] = array( '#type' => 'radios', - '#options' => array('no' => t('Unlimited'), 'yes' => 'Limit to !count submission(s) !timespan'), + '#options' => array('no' => t('Unlimited'), 'yes' => 'Limit each user to !count submission(s) !timespan'), '#default_value' => $node->webform['submit_limit'] == -1 ? 'no' : 'yes', '#parents' => array('enforce_limit'), ); @@ -281,6 +313,16 @@ function webform_configure_form_submit($form, &$form_state) { $node->webform['submit_interval'] = $form_state['values']['submit_interval']; } + // Set the total submit limit to -1 if set to unlimited. + if ($form_state['values']['enforce_total_limit'] == 'no') { + $node->webform['total_submit_limit'] = -1; + $node->webform['total_submit_interval'] = -1; + } + else { + $node->webform['total_submit_limit'] = $form_state['values']['total_submit_limit']; + $node->webform['total_submit_interval'] = $form_state['values']['total_submit_interval']; + } + // Set submit notice. $node->webform['submit_notice'] = $form_state['values']['submit_notice']; @@ -303,7 +345,22 @@ function theme_webform_advanced_submit_limit_form($form) { '!count' => preg_replace('/(]*>)(.*?)(<\/div>)/s', '$2', drupal_render($form['submit_limit'])), '!timespan' => preg_replace('/(]*>)(.*?)(<\/div>)/s', '$2', drupal_render($form['submit_interval'])), ); - $form['enforce_limit']['yes']['#title'] = t('Limit to !count submission(s) !timespan', $replacements); + $form['enforce_limit']['yes']['#title'] = t('Limit each user to !count submission(s) !timespan', $replacements); + return drupal_render($form); +} + +/** + * Theme the total submit limit fieldset on the webform node form. + */ +function theme_webform_advanced_total_submit_limit_form($form) { + $form['total_submit_limit']['#attributes']['class'] = 'webform-set-active'; + $form['total_submit_interval']['#attributes']['class'] = 'webform-set-active'; + // Remove div wrappers around limit options. + $replacements = array( + '!count' => preg_replace('/(]*>)(.*?)(<\/div>)/s', '$2', drupal_render($form['total_submit_limit'])), + '!timespan' => preg_replace('/(]*>)(.*?)(<\/div>)/s', '$2', drupal_render($form['total_submit_interval'])), + ); + $form['enforce_total_limit']['yes']['#title'] = t('Limit to !count total submission(s) !timespan', $replacements); return drupal_render($form); } diff --git a/includes/webform.submissions.inc b/includes/webform.submissions.inc index d588eca..5ac6bd5 100644 --- a/includes/webform.submissions.inc +++ b/includes/webform.submissions.inc @@ -795,6 +795,38 @@ function _webform_submission_limit_check($node) { } /** + * Check if the total number of submissions has exceeded the limit on this form. + * + * @param $node + * The webform node to be checked. + * @return + * Boolean TRUE if the form has exceeded it's limit. FALSE otherwise. + */ +function _webform_total_submission_limit_check($node) { + + // Check if submission limiting is enabled. + if ($node->webform['total_submit_limit'] == '-1') { + return FALSE; // No check enabled. + } + + // Retrieve submission data from the database. + $query = 'SELECT count(*) ' . + 'FROM {webform_submissions} ' . + 'WHERE submitted > %d AND nid = %d AND is_draft = 0'; + + // Fetch all the entries from the database within the submit interval. + $num_submissions_database = db_result(db_query($query, ($node->webform['total_submit_interval'] != -1) ? (time() - $node->webform['total_submit_interval']) : $node->webform['total_submit_interval'], $node->nid)); + + if ($num_submissions_database >= $node->webform['total_submit_limit']) { + // Limit exceeded. + return TRUE; + } + + // Limit not exceeded. + return FALSE; +} + +/** * Preprocess function for webform-submission.tpl.php. */ function template_preprocess_webform_submission(&$vars) { diff --git a/webform.install b/webform.install index c46b1c7..6f8b24e 100644 --- a/webform.install +++ b/webform.install @@ -98,6 +98,18 @@ function webform_schema() { 'not null' => TRUE, 'default' => -1, ), + 'total_submit_limit' => array( + 'description' => 'The total number of submissions allowed within an interval. -1 is unlimited.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => -1, + ), + 'total_submit_interval' => array( + 'description' => 'The amount of time in seconds that must pass before another submission can be submitted within the set limit.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => -1, + ), ), 'primary key' => array('nid'), ); @@ -1469,6 +1481,22 @@ function webform_update_6329() { } /** + * Add additional columns for total submission limit. + */ +function webform_update_6330() { + $ret = array(); + if (!db_column_exists('webform', 'total_submit_limit')) { + db_add_field($ret, 'webform', 'total_submit_limit', array('type' => 'int', 'not null' => TRUE, 'default' => -1)); + } + + if (!db_column_exists('webform', 'total_submit_interval')) { + db_add_field($ret, 'webform', 'total_submit_interval', array('type' => 'int', 'not null' => TRUE, 'default' => -1)); + } + + return $ret; +} + +/** * Recursively delete all files and folders in the specified filepath, then * delete the containing folder. * diff --git a/webform.module b/webform.module index 0a58799..ad06552 100644 --- a/webform.module +++ b/webform.module @@ -507,7 +507,7 @@ function webform_theme() { 'arguments' => array('node' => NULL, 'teaser' => NULL, 'page' => NULL, 'form' => NULL, 'enabled' => NULL), ), 'webform_view_messages' => array( - 'arguments' => array('node' => NULL, 'teaser' => NULL, 'page' => NULL, 'submission_count' => NULL, 'limit_exceeded' => NULL, 'allowed_roles' => NULL, 'closed' => NULL, 'cached' => FALSE), + 'arguments' => array('node' => NULL, 'teaser' => NULL, 'page' => NULL, 'submission_count' => NULL, 'limit_exceeded' => NULL, 'total_limit_exceeded' => NULL, 'allowed_roles' => NULL, 'closed' => NULL, 'cached' => FALSE), ), 'webform_form' => array( 'arguments' => array('form' => NULL), @@ -584,6 +584,10 @@ function webform_theme() { 'arguments' => array('form' => NULL), 'file' => 'includes/webform.pages.inc', ), + 'webform_advanced_total_submit_limit_form' => array( + 'arguments' => array('form' => NULL), + 'file' => 'includes/webform.pages.inc', + ), // webform.report.inc. 'webform_results_per_page' => array( 'arguments' => array('total_count' => NULL, 'pager_count' => NULL), @@ -1096,6 +1100,8 @@ function webform_node_defaults() { 'submit_text' => '', 'submit_limit' => '-1', 'submit_interval' => '-1', + 'total_submit_limit' => '-1', + 'total_submit_interval' => '-1', 'status' => '1', 'record_exists' => FALSE, 'roles' => array('1', '2'), @@ -1259,6 +1265,7 @@ function webform_node_view(&$node, $teaser, $page) { $submission_count = 0; $enabled = TRUE; $logging_in = FALSE; + $total_limit_exceeded = FALSE; $limit_exceeded = FALSE; $closed = FALSE; $allowed_roles = array(); @@ -1311,6 +1318,17 @@ function webform_node_view(&$node, $teaser, $page) { } } + // Check if the user can add another submission if there is a limit on total + // submissions. + if ($node->webform['total_submit_limit'] != -1) { // -1: Submissions are never throttled. + module_load_include('inc', 'webform', 'includes/webform.submissions'); + + // Disable the form if the limit is exceeded and page cache is not active. + if (($total_limit_exceeded = _webform_total_submission_limit_check($node)) && !$cached) { + $enabled = FALSE; + } + } + // Check if this user has a draft for this webform. $is_draft = FALSE; if (($node->webform['allow_draft'] || $node->webform['auto_save']) && $user->uid != 0) { @@ -1334,7 +1352,7 @@ function webform_node_view(&$node, $teaser, $page) { // Print out messages for the webform. if ($node->build_mode != NODE_BUILD_PREVIEW && !isset($node->webform_block) && !$logging_in) { - theme('webform_view_messages', $node, $teaser, $page, $submission_count, $limit_exceeded, $allowed_roles, $closed, $cached); + theme('webform_view_messages', $node, $teaser, $page, $submission_count, $limit_exceeded, $total_limit_exceeded, $allowed_roles, $closed, $cached); } if (isset($output)) { @@ -1380,6 +1398,8 @@ function theme_webform_view($node, $teaser, $page, $form, $enabled) { * for anonymous users. * @param $limit_exceeded * Boolean value if the submission limit for this user has been exceeded. + * @param $total_limit_exceeded + * Boolean value if the total submission limit has been exceeded. * @param $allowed_roles * A list of user roles that are allowed to submit this webform. * @param $closed @@ -1391,7 +1411,7 @@ function theme_webform_view($node, $teaser, $page, $form, $enabled) { * is cached, such as "Submissions for this form are closed", because they * apply to all users equally. */ -function theme_webform_view_messages($node, $teaser, $page, $submission_count, $limit_exceeded, $allowed_roles, $closed, $cached) { +function theme_webform_view_messages($node, $teaser, $page, $submission_count, $limit_exceeded, $total_limit_exceeded, $allowed_roles, $closed, $cached) { global $user; $type = 'status'; @@ -1435,6 +1455,14 @@ function theme_webform_view_messages($node, $teaser, $page, $submission_count, $ } $type = 'error'; } + elseif ($total_limit_exceeded && !$cached) { + if ($node->webform['total_submit_interval'] == -1 && $node->webform['total_submit_limit'] > 1) { + $message = t('This form has received the maximum number of entries.'); + } + else { + $message = t('You may not submit another entry at this time.'); + } + } // If the user has submitted before, give them a link to their submissions. if ($submission_count > 0 && $node->webform['submit_notice'] == 1 && !$cached) { @@ -1957,6 +1985,19 @@ function webform_client_form_validate($form, &$form_state) { $node = node_load($form_state['values']['details']['nid']); $finished = $form_state['values']['details']['finished']; + // Check that the submissions have not exceeded the total submission limit. + if ($node->webform['total_submit_limit'] != -1) { + module_load_include('inc', 'webform', 'includes/webform.submissions'); + // Check if the total number of entries was reached before the user submitted + // the form. + if (!$finished && $total_limit_exceeded = _webform_total_submission_limit_check($node)) { + // Show the user the limit has exceeded. + theme('webform_view_messages', $node, 0, 1, 0, NULL, $total_limit_exceeded, array_keys(user_roles()), FALSE, FALSE); + form_set_error('', NULL); + return; + } + } + // Check that the user has not exceeded the submission limit. // This usually will only apply to anonymous users when the page cache is // enabled, because they may submit the form even if they do not have access. @@ -1966,7 +2007,7 @@ function webform_client_form_validate($form, &$form_state) { if (!$finished && $limit_exceeded = _webform_submission_limit_check($node)) { // Assume that webform_view_messages will print out the necessary message, // then stop the processing of the form with an empty form error. - theme('webform_view_messages', $node, 0, 1, 0, $limit_exceeded, array_keys(user_roles()), FALSE, FALSE); + theme('webform_view_messages', $node, 0, 1, 0, $limit_exceeded, NULL, array_keys(user_roles()), FALSE, FALSE); form_set_error('', NULL); return; }