? signup-autoclose.patch ? ~signup-DRUPAL-6--1.patch Index: signup.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/signup/signup.module,v retrieving revision 1.205.2.36 diff -u -p -r1.205.2.36 signup.module --- signup.module 8 Oct 2009 00:01:29 -0000 1.205.2.36 +++ signup.module 22 Oct 2009 20:54:08 -0000 @@ -201,6 +201,7 @@ function signup_cron() { module_load_include('inc', 'signup', 'includes/cron'); _signup_initialize_scheduler_backend(); _signup_cron_send_reminders(); + _signup_cron_autoopen(); _signup_cron_autoclose(); } @@ -238,6 +239,9 @@ function _signup_build_query($common_sql if (!empty($full_sql['group_by'])) { $sql .= ' GROUP BY '. implode(', ', $full_sql['group_by']); } + if (!empty($full_sql['having'])) { + $sql .= ' HAVING '. implode(', ', $full_sql['having']); + } return $sql; } @@ -767,6 +771,8 @@ function signup_nodeapi(&$node, $op, $te if ($node->nid) { $node->signup_total = db_result(db_query("SELECT COUNT(*) FROM {signup_log} WHERE nid = %d", $node->nid)); $node->signup_effective_total = db_result(db_query("SELECT SUM(count_towards_limit) FROM {signup_log} WHERE nid = %d", $node->nid)); + $node->signup_open_at = $signup->open_at; + $node->signup_close_at = $signup->close_at; } } else { Index: includes/admin.settings.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/signup/includes/admin.settings.inc,v retrieving revision 1.2.2.5 diff -u -p -r1.2.2.5 admin.settings.inc --- includes/admin.settings.inc 24 Jan 2009 08:52:46 -0000 1.2.2.5 +++ includes/admin.settings.inc 22 Oct 2009 20:54:08 -0000 @@ -13,12 +13,19 @@ function signup_settings_form() { module_load_include('inc', 'signup', 'includes/node_settings'); if (signup_site_has_dates()) { - $form['signup_close_early'] = array( + $form['signup_open_before'] = array( + '#title' => t('Open x hours before start'), + '#type' => 'textfield', + '#default_value' => variable_get('signup_open_before', 100), + '#size' => 5, '#maxlength' => 10, + '#description' => t('The default number of hours before the event which signups will begin. Use negative numbers to open signups after the event start (example: -12).'), + ); + $form['signup_close_before'] = array( '#title' => t('Close x hours before'), '#type' => 'textfield', - '#default_value' => variable_get('signup_close_early', 1), + '#default_value' => variable_get('signup_close_before', 1), '#size' => 5, '#maxlength' => 10, - '#description' => t('The number of hours before the event which signups will no longer be allowed. Use negative numbers to close signups after the event start (example: -12).'), + '#description' => t('The default number of hours before the event which signups will no longer be allowed. Use negative numbers to close signups after the event start (example: -12).'), ); }; $form['node_defaults'] = array( Index: includes/cron.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/signup/includes/cron.inc,v retrieving revision 1.1.2.2 diff -u -p -r1.1.2.2 cron.inc --- includes/cron.inc 14 Aug 2009 23:26:10 -0000 1.1.2.2 +++ includes/cron.inc 22 Oct 2009 20:54:08 -0000 @@ -79,49 +79,95 @@ function _signup_cron_send_reminders() { /** * Helper function that handles auto-closing time-based nodes during cron. * - * Loops over all the node types that are signup-enabled. For each one, it - * invokes the method for the installed event/date backend module to get the - * right query fragments, and builds a query to find all nodes of that type - * where signups should be closed (e.g. events that already started, etc). + * Determine current time in UTC and fetch all open signup enabled nodes with a signup close time before current UTC time. + * Requires Date API or PHP5.2+ * * @see signup_cron() - * @see signup_autoclose_sql() + * @see _signup_cron_autoopen() * @see _signup_build_query() */ function _signup_cron_autoclose() { - $type_autoclose_sql = array(); - foreach (signup_content_types() as $type) { - $type_sql = signup_autoclose_sql($type); - if (!empty($type_sql)) { - $type_autoclose_sql[$type] = $type_sql; - } + + // Get current time in UTC for comparison. If Date_API is unavailable, try PHP5.2 functions. Use basic date() and time() computations if both fail. + if (function_exists(date_make_date)) { + $current_time = date_format_date(date_make_date('now', 'UTC'), 'custom', DATE_FORMAT_DATETIME); } - if (empty($type_autoclose_sql)) { - // No node types support auto-close, so bail out now. - return; + elseif (function_exists(date_create)) { + $current_time = date_format(date_create('now',timezone_open('UTC')), 'Y-m-d H:i:s'); } - - $autoclose_common_sql = array( + else { + $time = time(); + $time = $time + date('Z',$time); + $current_time = date('Y-m-d H:i:s',$time); + } + + $autoclose_sql = array( 'primary' => '{node} n', 'fields' => array('n.nid', 'n.type'), - 'where' => array('s.status = 1', "n.type = '%s'"), + 'where' => array('s.status = 1', "s.close_at <= '$current_time'", "s.close_at > '0000-00-00 00:00:00'"), 'joins' => array('INNER JOIN {signup} s ON s.nid = n.nid'), ); - foreach ($type_autoclose_sql as $type => $autoclose_sql) { - $sql = _signup_build_query($autoclose_common_sql, $autoclose_sql); - $result = db_query($sql, $type); - - // Loop through the results, calling the signup closing function. - while ($signup = db_fetch_object($result)) { - signup_close_signup($signup->nid, $cron = 'yes'); - $node = node_load($signup->nid); - foreach (module_implements('signup_close') as $module) { - $function = $module .'_signup_close'; - $function($node); - } - watchdog('signup', 'Signups closed for %title by cron.', array('%title' => $node->title), WATCHDOG_NOTICE, l(t('view'), 'node/'. $node->nid)); + $sql = _signup_build_query($autoclose_sql, array()); + $result = db_query($sql, $type); + + // Loop through the results, calling the signup closing function. + while ($signup = db_fetch_object($result)) { + signup_close_signup($signup->nid, $cron = 'yes'); + $node = node_load($signup->nid); + foreach (module_implements('signup_close') as $module) { + $function = $module .'_signup_close'; + $function($node); } + watchdog('signup', 'Signups closed for %title by cron.', array('%title' => $node->title), WATCHDOG_NOTICE, l(t('view'), 'node/'. $node->nid)); } } +/** + * Helper function that handles auto-opening time-based nodes during cron. + * + * Determine current time in UTC and fetch all closed signup enabled nodes with a signup open time before current UTC time. + * Requires Date API or PHP5.2+ + * + * @see signup_cron() + * @see _signup_cron_autoclose() + * @see _signup_build_query() + */ +function _signup_cron_autoopen() { + + // Get current time in UTC for comparison. If Date_API is unavailable, try PHP5.2 functions. Use basic date() and time() computations if both fail. + if (function_exists(date_make_date)) { + $current_time = date_format(date_make_date('now', 'UTC'),DATE_FORMAT_DATETIME); + } + elseif (function_exists(date_create)) { + $current_time = date_format(date_create('now',timezone_open('UTC')),'Y-m-d H:i:s'); + } + else { + $time = time(); + $time = $time + date('Z',$time); + $current_time = date('Y-m-d H:i:s',$time); + } + + $autoopen_sql = array( + 'primary' => '{node} n', + 'fields' => array('n.nid', 'n.type'), + 'where' => array('s.status = 0', "s.open_at <= '$current_time'", "s.close_at > '$current_time'", "s.open_at > '0000-00-00 00:00:00'", "s.close_at > '0000-00-00 00:00:00'"), + 'having' => array('(SUM(l.count_towards_limit) < s.close_signup_limit OR SUM(l.count_towards_limit) IS NULL)'), + 'joins' => array('INNER JOIN {signup} s ON s.nid = n.nid','LEFT JOIN {signup_log} l ON l.nid = s.nid'), + 'group_by' => array('s.close_signup_limit'), + ); + + $sql = _signup_build_query($autoopen_sql, array()); + $result = db_query($sql, $type); + + // Loop through the results, calling the signup open function. + while ($signup = db_fetch_object($result)) { + signup_open_signup($signup->nid, $cron = 'yes'); + $node = node_load($signup->nid); + foreach (module_implements('signup_open') as $module) { + $function = $module .'_signup_open'; + $function($node); + } + watchdog('signup', 'Signups opened for %title by cron.', array('%title' => $node->title), WATCHDOG_NOTICE, l(t('view'), 'node/'. $node->nid)); + } +} Index: includes/date.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/signup/includes/date.inc,v retrieving revision 1.16.2.4 diff -u -p -r1.16.2.4 date.inc --- includes/date.inc 4 Mar 2009 19:19:34 -0000 1.16.2.4 +++ includes/date.inc 22 Oct 2009 20:54:08 -0000 @@ -549,3 +549,38 @@ function _signup_date_format_date($node, return $date_out; } +/** + * Collect the start time of the event + * + * A similar function for event.module based nodes will be required. + * A parameter should be added to allow returned time for different timezones. + * + * @param $node + * The node to return the start time for + * @return $date + * The start time for the signup enabled event. Returns as UTC time. + */ + +function _signup_date_node_start_at(&$node) { + // Get the date field information for this content type. + $field = signup_date_field($node->type); + + // Grab whatever date value we actually have, regardless of format. + $date_value = $node->{$field['field_name']}[0]['value']; + // Figure out the timezone handling for this date. + if ($field['tz_handling'] == 'date') { + $tz = $node->{$field['field_name']}[0]['timezone']; + } + else { + $tz = date_default_timezone_name(); + } + $db_tz = date_get_timezone_db($field['tz_handling'], $tz); + // Create a date object + $date = date_make_date($date_value, $db_tz, $field['type']); + // Make sure the date object is going to print UTC values. + date_timezone_set($date, timezone_open('UTC')); + + $date = date_format_date($date, 'custom', DATE_DATETIME); + + return $date; +} Index: includes/event.6x-2.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/signup/includes/event.6x-2.inc,v retrieving revision 1.2.2.1 diff -u -p -r1.2.2.1 event.6x-2.inc --- includes/event.6x-2.inc 9 Jan 2009 03:49:54 -0000 1.2.2.1 +++ includes/event.6x-2.inc 22 Oct 2009 20:54:08 -0000 @@ -108,3 +108,17 @@ function _signup_event_get_node_schedule return isset($node->event_start) ? 'event' : 'none'; } +/** + * Collect the start time of the event + * + * A parameter should be added to allow returned time for different timezones. + * + * @param $node + * The node to return the start time for + * @return $date + * The start time for the signup enabled event. Returns as UTC time. + */ + +function _signup_event_node_start_at(&$node) { + return $node->event['start_utc']; +} Index: includes/node_form.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/signup/includes/node_form.inc,v retrieving revision 1.4.2.2 diff -u -p -r1.4.2.2 node_form.inc --- includes/node_form.inc 16 Sep 2009 00:42:57 -0000 1.4.2.2 +++ includes/node_form.inc 22 Oct 2009 20:54:08 -0000 @@ -63,14 +63,27 @@ function signup_save_node($node, $op) { $needs_defaults = empty($has_record); } } + //Needs the time information from the full node, so loading of the full node is now done before loading of defaults. + $node = node_load($node->nid); if ($needs_defaults) { $values = db_fetch_array(db_query("SELECT forwarding_email, send_confirmation, confirmation_email, close_signup_limit, send_reminder, reminder_days_before, reminder_email FROM {signup} WHERE nid = 0")); + + // Get the date field information for this content type. + $field = signup_date_field($node->type); + + //Calculate open and close time for signups. + $open_at = date_make_date(signup_node_start_at($node), 'UTC'); + $close_at = date_make_date(signup_node_start_at($node), 'UTC'); + date_modify($open_at, '-'.variable_get('signup_open_before',100).'hours'); + date_modify($close_at, '-'.variable_get('signup_close_before', 1).'hours'); + $values['open_at'] = date_format_date($open_at, 'custom', DATE_FORMAT_DATETIME); + $values['close_at'] = date_format_date($close_at, 'custom', DATE_FORMAT_DATETIME); $values[] = $node->nid; - db_query("INSERT INTO {signup} (forwarding_email, send_confirmation, confirmation_email, close_signup_limit, send_reminder, reminder_days_before, reminder_email, nid) VALUES ('%s', %d, '%s', %d, %d, %d, '%s', %d)", $values); + + db_query("INSERT INTO {signup} (forwarding_email, send_confirmation, confirmation_email, close_signup_limit, send_reminder, reminder_days_before, reminder_email, open_at, close_at, nid) VALUES ('%s', %d, '%s', %d, %d, %d, '%s', '%s', '%s', %d)", $values); } - $node = node_load($node->nid); if (_signup_node_completed($node) && !empty($node->signup_status)) { // If this is an time-based node, and it's already past the close in // advance time (e.g. someone just changed the node start time), and Index: includes/node_settings.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/signup/includes/node_settings.inc,v retrieving revision 1.1.2.4 diff -u -p -r1.1.2.4 node_settings.inc --- includes/node_settings.inc 21 Sep 2009 05:23:09 -0000 1.1.2.4 +++ includes/node_settings.inc 22 Oct 2009 20:54:08 -0000 @@ -73,6 +73,48 @@ function signup_node_settings_form($form } if ($has_date) { + if ($node->nid) { + // Use Drupal's date element to get a basic input for open and close times. + $open_date = explode('-',$node->singup_open_at); + $close_date = explode('-',$node->singup_close_at); + $form['signup_open_at'] = array( + '#type' => 'date', + '#title' => t('Time to open signup'), + '#default_value' => array('year'=>$open_date[0],'month'=>$open_date[1],'day'=>$open_date[2]), + '#description' => t('The time on which singups should be opened for this node.'), + ); + $form['signup_close_at'] = array( + '#type' => 'date', + '#title' => t('Time to close signup'), + '#default_value' => array('year'=>$close_date[0],'month'=>$close_date[1],'day'=>$close_date[2]), + '#description' => t('The time on which signups should be closed for this node.'), + ); + + if (module_exists('date_api')) { + // Compute the times in user or site timezone + $timezone = date_default_timezone_name(); + $open_at = date_make_date($node->signup_open_at, 'UTC'); + $close_at = date_make_date($node->signup_close_at, 'UTC'); + date_timezone_set($open_at, timezone_open($timezone)); + date_timezone_set($close_at, timezone_open($timezone)); + + //Modify the form elements to utilize the Date API. + $form['signup_open_at']['#type'] = 'date_select'; + $form['signup_open_at']['#default_value'] = date_format_date($open_at, 'custom', DATE_FORMAT_DATETIME); + $form['signup_open_at']['#date_format'] = DATE_FORMAT_DATETIME; + $form['signup_open_at']['#timezone'] = $timezone; + $form['signup_close_at']['#type'] = 'date_select'; + $form['signup_close_at']['#default_value'] = date_format_date($close_at,'custom',DATE_FORMAT_DATETIME); + $form['signup_close_at']['#date_format'] = DATE_FORMAT_DATETIME; + $form['signup_close_at']['#timezone'] = $timezone; + } + + // If the date_popup module is enabled we want to use the popup element + if (module_exists('date_popup')) { + $form['signup_open_at']['#type'] = 'date_popup'; + $form['signup_close_at']['#type'] = 'date_popup'; + } + } // Define a sub-tree to wrap the next 2 form elements together in an // inline div for better display. $form['signup_reminder'] = array( @@ -169,13 +211,34 @@ function signup_node_settings_form_submi $values['send_reminder'] = isset($form_state['values']['signup_send_reminder']) ? $form_state['values']['signup_send_reminder'] : 0; $values['reminder_days_before'] = isset($form_state['values']['signup_reminder_days_before']) ? $form_state['values']['signup_reminder_days_before'] : 0; $values['reminder_email'] = isset($form_state['values']['signup_reminder_email']) ? $form_state['values']['signup_reminder_email'] : ''; + + if (isset($form_state['values']['signup_open_at']) && isset($form['signup_open_at']['#date_timezone'])) { + if ($form['signup_open_at']['#type'] == 'date_select' || $form['signup_open_at']['#type'] == 'date_popup') { + $open_at = date_make_date($form_state['values']['signup_open_at'], $form['signup_open_at']['#date_timezone']); + date_timezone_set($open_at, timezone_open('UTC')); + $values['signup_open_at'] = date_format_date($open_at, 'custom', DATE_FORMAT_DATETIME); + } + elseif ($form['signup_open_at']['#type'] == 'date') { + $values['signup_open_at'] = $form_state['values']['signup_open_at']['year'].'-'.$form_state['values']['signup_open_at']['month'].'-'.$form_state['values']['signup_open_at']['day']; + } + } + if (isset($form_state['values']['signup_close_at']) && isset($form['signup_close_at']['#date_timezone'])) { + if ($form['signup_close_at']['#type'] == 'date_select' || $form['signup_close_at']['#type'] == 'date_popup') { + $close_at = date_make_date($form_state['values']['signup_close_at'], $form['signup_close_at']['#date_timezone']); + date_timezone_set($close_at, timezone_open('UTC')); + $values['signup_close_at'] = date_format_date($close_at, 'custom', DATE_FORMAT_DATETIME); + } + elseif ($form['signup_close_at']['#type'] == 'date') { + $values['signup_close_at'] = $form_state['values']['signup_close_at']['year'].'-'.$form_state['values']['signup_close_at']['month'].'-'.$form_state['values']['signup_close_at']['day']; + } + } } // Either way, we want to make sure we're updating the values for the // current node, not nid 0... $node = $form['#node']; $values[] = $node->nid; - db_query("UPDATE {signup} SET forwarding_email = '%s', send_confirmation = %d, confirmation_email = '%s', close_signup_limit = %d, send_reminder = %d, reminder_days_before = %d, reminder_email = '%s' WHERE nid = %d", $values); + db_query("UPDATE {signup} SET forwarding_email = '%s', send_confirmation = %d, confirmation_email = '%s', close_signup_limit = %d, send_reminder = %d, reminder_days_before = %d, reminder_email = '%s', open_at = '%s', close_at = '%s' WHERE nid = %d", $values); // See if the limit changed, and if so, take any necessary action. if ($node->signup_close_signup_limit != $form_state['values']['signup_close_signup_limit']) { Index: includes/scheduler.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/signup/includes/scheduler.inc,v retrieving revision 1.4 diff -u -p -r1.4 scheduler.inc --- includes/scheduler.inc 6 Nov 2008 10:20:48 -0000 1.4 +++ includes/scheduler.inc 22 Oct 2009 20:54:08 -0000 @@ -124,29 +124,36 @@ function signup_reminder_sql($node_type) } } -function signup_autoclose_sql($node_type) { +function signup_admin_sql($node_type) { switch (_signup_get_node_type_scheduler($node_type)) { case 'event': - return _signup_event_autoclose_sql($node_type); + return _signup_event_admin_sql($node_type); case 'date': - return _signup_date_autoclose_sql($node_type); + return _signup_date_admin_sql($node_type); default: return array(); } } -function signup_admin_sql($node_type) { - switch (_signup_get_node_type_scheduler($node_type)) { +/** + * Get the start time for the node. + */ +function signup_node_start_at(&$node) { + if (is_numeric($node)) { + $node = node_load($node); + } + switch (_signup_get_node_scheduler($node)) { case 'event': - return _signup_event_admin_sql($node_type); + //Function not yet present, must be written to autoopen/close signups with event. + return _signup_event_node_start_at($node); case 'date': - return _signup_date_admin_sql($node_type); + return _signup_date_node_start_at($node); default: - return array(); + return FALSE; } }