Index: quiz.install
===================================================================
RCS file: /cvs/drupal/contributions/modules/quiz/quiz.install,v
retrieving revision 1.2
diff -u -r1.2 quiz.install
--- quiz.install	11 Oct 2006 15:21:53 -0000	1.2
+++ quiz.install	19 Oct 2006 18:55:55 -0000
@@ -19,10 +19,11 @@
                   shuffle TINYINT UNSIGNED NOT NULL,
                   backwards_navigation TINYINT UNSIGNED NOT NULL,
                   feedback_time TINYINT UNSIGNED NOT NULL,
-                  open DATETIME NOT NULL,
-                  close DATETIME NOT NULL,
+                  quiz_open int(10) unsigned default '0',
+                  quiz_close int(10) unsigned default '0',
                   takes TINYINT UNSIGNED NOT NULL,
                   time_limit INTEGER UNSIGNED DEFAULT 0 NOT NULL,
+                  quiz_always tinyint(1) NOT NULL default '0',
                   PRIMARY KEY(nid)
                 ) TYPE=MyISAM
                 /*!40100 DEFAULT CHARACTER SET utf8 */;");
@@ -61,9 +62,9 @@
                   rid INTEGER UNSIGNED NOT NULL,
                   quiz_nid INTEGER UNSIGNED NOT NULL,
                   uid INTEGER UNSIGNED NOT NULL,
-                  time_start DATETIME NOT NULL,
-                  time_end DATETIME NOT NULL,
-                  released DATETIME NOT NULL,
+                  time_start int(10) unsigned default '0',
+                  time_end int(10) unsigned default '0',
+                  released int(10) unsigned default '0',
                   score TINYINT NOT NULL,
                   PRIMARY KEY (rid),
                   INDEX (quiz_nid)
Index: quiz.module
===================================================================
RCS file: /cvs/drupal/contributions/modules/quiz/quiz.module,v
retrieving revision 1.73
diff -u -r1.73 quiz.module
--- quiz.module	19 Oct 2006 17:21:45 -0000	1.73
+++ quiz.module	19 Oct 2006 18:55:56 -0000
@@ -1,5 +1,7 @@
 <?php
-// $Id: quiz.module,v 1.73 2006/10/19 17:21:45 seanfuller Exp $
+// $Id: quiz.module,v 1.70 2006/10/12 23:26:52 seanfuller Exp $
+
+include(drupal_get_path('module', 'quiz').'/quiz_datetime.inc');
 
 /**
  * @file
@@ -191,21 +193,56 @@
     ),
     '#description' => t('Indicates at what point feedback for each question will be given to the student'),
   );
-  
-  list($d['year'], $d['month'], $d['day']) = explode('-', substr($node->open, 0, 10));
-  $form['open'] = array(
-    '#type' => 'date',
-    '#title' => t('Open date'),
-    '#default_value' => $d,
-    '#description' => t('The date students should be able to start taking this quiz'),
-  );
 
-  list($d['year'], $d['month'], $d['day']) = explode('-', substr($node->close, 0, 10));
-  $form['close'] = array(
+  // Set up the availability options
+  $form['quiz_availability'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Availability options'),
+    '#collapsed' => FALSE,
+    '#collapsible' => TRUE,
+  );
+  $form['quiz_availability']['quiz_always'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Always Available'),
+    '#default_value' => $node->quiz_always,
+    '#description' => t('Click this option to ignore the open and close dates.'),
+  );
+  // If we are previewing, quiz_open is an array so just pass it through
+  $open_array = array();
+  if(is_array($node->quiz_open)){
+  	$open_array = $node->quiz_open;
+  } 
+  // otherwise build the array from the timestamp
+  elseif(is_numeric($node->quiz_open)){
+    $open_array = array(
+      'day' => _quiz_date('j', $node->quiz_open),
+      'month' => _quiz_date('n', $node->quiz_open),
+      'year' => _quiz_date('Y', $node->quiz_open),
+    );
+  }
+  $form['quiz_availability']['quiz_open'] = array(
+    '#type' => 'date',
+    '#title' => t('Open Date'),
+    '#default_value' => $open_array,
+    '#description' => t('The date this quiz will become available.'),
+  );
+  $close_array = array();
+  if(is_array($node->quiz_close)){
+  	$close_array = $node->quiz_close;
+  } 
+  // otherwise build the array from the timestamp
+  elseif(is_numeric($node->quiz_close)){
+    $close_array = array(
+      'day' => _quiz_date('j', $node->quiz_close),
+      'month' => _quiz_date('n', $node->quiz_close),
+      'year' => _quiz_date('Y', $node->quiz_close),
+    );
+  }
+  $form['quiz_availability']['quiz_close'] = array(
     '#type' => 'date',
-    '#title' => t('Close date'),
-    '#default_value' => $d,
-    '#description' => t('The date the quiz will close and prevent students from taking the quiZ'),
+    '#title' => t('Close Date'),
+    '#default_value' => $close_array,
+    '#description' => t('The date this quiz will cease to be available.'),
   );
 
   $options = array('Unlimited');
@@ -328,9 +365,8 @@
     }
   }
 
-  if (mktime(0,0,0, $node->open['month'], $node->open['day'], $node->open['year']) > mktime(0,0,0, $node->close['month'], $node->close['day'], $node->close['year'])) {
-    form_set_error('close', t('Close date before open date'));
-    form_set_error('open', t('Open date after close date'));
+  if (mktime(0,0,0, $node->quiz_open['month'], $node->quiz_open['day'], $node->quiz_open['year']) > mktime(0,0,0, $node->quiz_close['month'], $node->quiz_close['day'], $node->quiz_close['year'])) {
+    form_set_error('quiz_close', t('Please make sure the close date is after the open date.'));
   }
   if (!is_numeric($node->pass_rate)) {
     form_set_error('pass_rate', t('The pass rate value must be a number between 0% and 100%.'));
@@ -347,18 +383,20 @@
  * Implementation of hook_insert().
  */
 function quiz_insert($node) {
-  $open = $node->open['year'].'-'.$node->open['month'].'-'.$node->open['day'];
-  $close = $node->close['year'].'-'.$node->close['month'].'-'.$node->close['day'];
-  db_query("INSERT INTO {quiz} (nid, number_of_questions, shuffle, backwards_navigation, feedback_time, open, close, takes, pass_rate, summary_pass, summary_default) VALUES(%d, %d, %d, %d, %d, '%s', '%s', %d, %d, '%s', '%s')", $node->nid, $node->number_of_questions, $node->shuffle, $node->backwards_navigation, $node->feedback_time, $open, $close, $node->takes, $node->pass_rate, $node->summary_pass, $node->summary_default);
+  quiz_validate_form_date($node, 'quiz_open');
+  quiz_validate_form_date($node, 'quiz_close');
+  $sql = "INSERT INTO {quiz} (nid, number_of_questions, shuffle, backwards_navigation, feedback_time, quiz_open, quiz_close, takes, pass_rate, summary_pass, summary_default, quiz_always)";
+  $sql .= " VALUES(%d, %d, %d, %d, %d, %d, %d, %d, %d, '%s', '%s', %d)";
+  db_query($sql, $node->nid, $node->number_of_questions, $node->shuffle, $node->backwards_navigation, $node->feedback_time, $node->quiz_open, $node->quiz_close, $node->takes, $node->pass_rate, $node->summary_pass, $node->summary_default, $node->quiz_always);
 }
 
 /**
  * Implementation of hook_update().
  */
 function quiz_update($node) {
-  $open = $node->open['year'].'-'.$node->open['month'].'-'.$node->open['day'];
-  $close = $node->close['year'].'-'.$node->close['month'].'-'.$node->close['day'];
-  db_query("UPDATE {quiz} SET number_of_questions = %d, shuffle = %d, backwards_navigation = %d, feedback_time = %d, open = '%s', close = '%s', takes = %d, pass_rate = %d, summary_pass = '%s', summary_default ='%s' WHERE nid = %d", $node->number_of_questions, $node->shuffle, $node->backwards_navigation, $node->feedback_time, $open, $close, $node->takes, $node->pass_rate, $node->summary_pass, $node->summary_default, $node->nid);
+  quiz_validate_form_date($node, 'quiz_open');
+  quiz_validate_form_date($node, 'quiz_close');
+  db_query("UPDATE {quiz} SET number_of_questions = %d, shuffle = %d, backwards_navigation = %d, feedback_time = %d, quiz_open = %d, quiz_close = %d, takes = %d, pass_rate = %d, summary_pass = '%s', summary_default ='%s', quiz_always = %d WHERE nid = %d", $node->number_of_questions, $node->shuffle, $node->backwards_navigation, $node->feedback_time, $node->quiz_open, $node->quiz_close, $node->takes, $node->pass_rate, $node->summary_pass, $node->summary_default, $node->quiz_always, $node->nid);
 }
 
 /**
@@ -423,19 +461,24 @@
     $takes
   );
   $output .= theme('table', $header, $rows);
-    
+
   // Format Quiz Dates
   $output .= '<h3>'. t('Quiz start/end') .'</h3>';
-  $output .= "<p>" . date("l, jS F Y", strtotime($node->open)) . " &mdash; " . date("l, jS F Y", strtotime($node->close)) ."</p>";
-  $output .= "<p><strong>Days quiz live for:</strong> " . floor((strtotime($node->close) - strtotime($node->open)) / 60 / 60 / 24) . "</p>";
-
-  $remaining = floor((strtotime($node->close) - time()) / 60 / 60 / 24);
-  $remaining = ($remaining < 0)?"Expired":$remaining;
-  $output .= "<p><strong>Days remaining:</strong> " . $remaining . "</p>";
-
-  $elapsed = floor((time() - strtotime($node->open)) / 60 / 60 / 24);
-  $elapsed = ($elapsed < 0)?(-$elapsed)." days to go":$elapsed;
-  $output .= "<p><strong>Days since start:</strong> " . $elapsed . "</p>";
+  if(!$node->quiz_always){
+    $output .= "<p>" . format_date($node->quiz_open) . " &mdash; " . format_date($node->quiz_close) ."</p>";
+    $output .= "<p><strong>Days quiz live for:</strong> " . floor(($node->quiz_close - $node->quiz_open) / 60 / 60 / 24) . "</p>";
+
+    $remaining = floor(($node->quiz_close - time()) / 60 / 60 / 24);
+    $remaining = ($remaining < 0)?"Expired":$remaining;
+    $output .= "<p><strong>Days remaining:</strong> " . $remaining . "</p>";
+
+    $elapsed = floor((time() - $node->quiz_open) / 60 / 60 / 24);
+    $elapsed = ($elapsed < 0)?(-$elapsed)." days to go":$elapsed;
+    $output .= "<p><strong>Days since start:</strong> " . $elapsed . "</p>";
+  } 
+  else {
+    $output .= '<p>'. t('This Quiz is always available.') .'</p>'."\n";
+  }
 
   // Format taxonomy selection (if applicable)
   if (function_exists(taxonomy_node_get_terms)) {
@@ -490,8 +533,8 @@
                           n.title title,
                           u.name name,
                           qr.rid rid,
-                          qr.time_start time_start,
-                          if (qr.time_end, qr.time_end, 'In Progress&hellip;') finished
+                          qr.time_start,
+                          qr.time_end
                         FROM {node} n, {quiz} q, {quiz_result} qr, {users} u
                         WHERE
                           n.type = 'quiz'
@@ -651,8 +694,21 @@
 
   // get the quiz node
   $quiz = node_load($nid);
+
+  // make sure this is available
+  if(!$quiz->quiz_always == 1){
+  	// compare current gm time to open and close dates (which should still be in gm time)
+    if(gmmktime() >= $quiz->quiz_close || gmmktime() < $quiz->quiz_open){
+      drupal_set_message(t('This quiz is not currently available.'), 'status');
+      if(!user_access('create quiz')){
+        return FALSE;
+      }
+    }
+  }
+
+  // get the results
   $results = _quiz_get_results($quiz->nid);
-  
+    
   // Check to see if the user alredy passed this quiz
   $passed = FALSE;
   while($next = next($results)){
@@ -685,7 +741,8 @@
 
   // Insert quiz_results record
   $rid = db_next_id('quiz_results_rid');
-  $result = db_query("INSERT INTO {quiz_result} (rid, quiz_nid, uid, time_start) VALUES (%d, %d, %d, NOW())", $rid, $nid, $uid);
+  $now = _quiz_user_time();
+  $result = db_query("INSERT INTO {quiz_result} (rid, quiz_nid, uid, time_start) VALUES (%d, %d, %d, %d)", $rid, $nid, $uid, $now);
   if ($result) {
     return $rid;
   }
@@ -1402,6 +1459,7 @@
   return $results;
 }
 
+
 /////////////////////////////////////////////////
 /// Theme functions
 /////////////////////////////////////////////////
@@ -1422,8 +1480,9 @@
       $result['title'],
       $result['name'],
       $result['rid'],
-      $result['time_start'],
-      $result['finished'],);
+      format_date($result['time_start'], 'small'),
+      ($result['time_end'] > 0) ? format_date($result['time_end'], 'small') : t('In Progress'),
+    );
   }
   
   $header = array(
@@ -1461,8 +1520,9 @@
       $result['title'],
       $result['name'],
       $result['rid'],
-      $result['time_start'],
-      $result['finished'],);
+      format_date($result['time_start'], 'small'),
+      ($result['time_end'] > 0) ? format_date($result['time_end'], 'small') : t('In Progress'),
+    );
   }
   
   $header = array(
Index: quiz_datetime.inc
===================================================================
RCS file: quiz_datetime.inc
diff -N quiz_datetime.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ quiz_datetime.inc	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,108 @@
+<?php
+// $Id: $
+
+/////////////////////////////////
+// Date and time routines for use with quiz module.
+// - Based on event module
+// - All references to event variables should be optional 
+/////////////////////////////////
+
+/**
+ * Returns a local timestamp based on the user or site time zone.
+ * 
+ * Taken straight from event.module
+ * @return integer timestamp
+ */
+function _quiz_user_time() {
+  global $user;
+
+  if (variable_get('configurable_timezones', 1) && $user->uid && strlen($user->timezone)) {
+    return (time() - date("Z")) + $user->timezone;
+  }
+  else {
+    return (time() - date("Z")) + variable_get('date_default_timezone', 0);
+  }
+}
+
+/**
+ * Validates the start and end times in a node form submission.
+ * - Changes 24 hour time to 12 hour time (if the module is configured to do this).
+ * - Adjusts times for time zone offsets.
+ * - Adapted from event.module
+ *
+ * @param $node The submitted node with form data.
+ * @param $date The name of the date ('start', 'end', 'open', or 'close') to validate and set.
+ */
+function quiz_validate_form_date(&$node, $date) {
+  $prefix = $node->$date;
+  // If we have all the parameters, re-calculate $node->event_$date .
+  if (isset($prefix['year']) && isset($prefix['month']) && isset($prefix['day'])) {
+    // Build a timestamp based on the date supplied and the configured timezone.
+    $node->$date = _quiz_mktime(0, 0, 0, $prefix['month'], $prefix['day'], $prefix['year'], 0);
+  }
+  else {
+    form_set_error('quiz_open', t('Please supply a valid date.'));
+  }
+}
+
+/**
+ * Formats local time values to GMT timestamp using time zone offset supplied.
+ * All time values in the database are GMT and translated here prior to insertion.
+ *
+ * Time zone settings are applied in the following order:
+ * 1. If supplied, time zone offset is applied
+ * 2. If user time zones are enabled, user time zone offset is applied
+ * 3. If neither 1 nor 2 apply, the site time zone offset is applied
+ *
+ * @param $format The date() format to apply to the timestamp.
+ * @param $timestamp The GMT timestamp value.
+ * @param $offset Time zone offset to apply to the timestamp.
+ * @return gmdate() formatted date value
+ */
+function _quiz_mktime($hour, $minute, $second, $month, $day, $year, $offset = NULL) {
+  global $user;
+  $timestamp = gmmktime($hour, $minute, $second, $month, $day, $year);
+  if (isset($offset)) {
+    return $timestamp - $offset;
+  }
+  elseif (variable_get('configurable_timezones', 1) && $user->uid && strlen($user->timezone) && (variable_get('event_timezone_display', 'event') == 'user')) {
+    return $timestamp - $user->timezone;
+  }
+  else {
+    return $timestamp - variable_get('date_default_timezone', 0);
+  }
+}
+
+/**
+ * Formats a GMT timestamp to local date values using time zone offset supplied.
+ * All timestamp values in event nodes are GMT and translated for display here.
+ *
+ * Pulled from event
+ *
+ * Time zone settings are applied in the following order
+ * 1. If supplied, time zone offset is applied
+ * 2. If user time zones are enabled, user time zone offset is applied
+ * 3. If neither 1 nor 2 apply, the site time zone offset is applied
+ *
+ * @param $format The date() format to apply to the timestamp.
+ * @param $timestamp The GMT timestamp value.
+ * @param $offset Time zone offset to apply to the timestamp.
+ * @return gmdate() formatted date value
+ */
+function _quiz_date($format, $timestamp, $offset = null) {
+  global $user;
+
+  if (isset($offset)) {
+    $timestamp += $offset;
+  }
+  elseif (variable_get('configurable_timezones', 1) && $user->uid && strlen($user->timezone)) {
+    $timestamp += $user->timezone;
+  }
+  else {
+    $timestamp += variable_get('date_default_timezone', 0);
+  }
+
+  // make sure we apply the site first day of the week setting for dow requests
+  $result = gmdate($format, $timestamp);
+  return  $result;
+}
