Merge branch 'MDL-27242-master' of git://github.com/sammarshallou/moodle
authorSam Hemelryk <sam@moodle.com>
Mon, 17 Oct 2011 04:28:32 +0000 (17:28 +1300)
committerSam Hemelryk <sam@moodle.com>
Mon, 17 Oct 2011 04:28:32 +0000 (17:28 +1300)
course/modedit.php
course/moodleform_mod.php
lang/en/condition.php
lib/conditionlib.php
lib/db/upgrade.php
lib/form/datetimeselector.php
version.php

index a68ddcc..111e655 100644 (file)
@@ -302,12 +302,6 @@ if ($mform->is_cancelled()) {
         if (!empty($CFG->enableavailability)) {
             $cm->availablefrom             = $fromform->availablefrom;
             $cm->availableuntil            = $fromform->availableuntil;
-            // The form time is midnight, but because we want it to be
-            // inclusive, set it to 23:59:59 on that day.
-            if ($cm->availableuntil) {
-                $cm->availableuntil = strtotime('23:59:59',
-                    $cm->availableuntil);
-            }
             $cm->showavailability          = $fromform->showavailability;
             condition_info::update_cm_from_form($cm,$fromform,true);
         }
@@ -393,12 +387,6 @@ if ($mform->is_cancelled()) {
         if(!empty($CFG->enableavailability)) {
             $newcm->availablefrom             = $fromform->availablefrom;
             $newcm->availableuntil            = $fromform->availableuntil;
-            // The form time is midnight, but because we want it to be
-            // inclusive, set it to 23:59:59 on that day.
-            if ($newcm->availableuntil) {
-                $newcm->availableuntil = strtotime('23:59:59',
-                    $newcm->availableuntil);
-            }
             $newcm->showavailability          = $fromform->showavailability;
         }
         if (isset($fromform->showdescription)) {
index ce5666b..b4fbb2f 100644 (file)
@@ -308,7 +308,7 @@ abstract class moodleform_mod extends moodleform {
         // Conditions: Don't let them set dates which make no sense
         if (array_key_exists('availablefrom', $data) &&
             $data['availablefrom'] && $data['availableuntil'] &&
-            $data['availablefrom'] > $data['availableuntil']) {
+            $data['availablefrom'] >= $data['availableuntil']) {
             $errors['availablefrom'] = get_string('badavailabledates', 'condition');
         }
 
@@ -429,10 +429,23 @@ abstract class moodleform_mod extends moodleform {
 
         if (!empty($CFG->enableavailability)) {
             // Conditional availability
-            $mform->addElement('header', 'availabilityconditionsheader', get_string('availabilityconditions', 'condition'));
-            $mform->addElement('date_selector', 'availablefrom', get_string('availablefrom', 'condition'), array('optional'=>true));
+
+            // Available from/to defaults to midnight because then the display
+            // will be nicer where it tells users when they can access it (it
+            // shows only the date and not time).
+            $date = usergetdate(time());
+            $midnight = make_timestamp($date['year'], $date['mon'], $date['mday']);
+
+            // From/until controls
+            $mform->addElement('header', 'availabilityconditionsheader',
+                    get_string('availabilityconditions', 'condition'));
+            $mform->addElement('date_time_selector', 'availablefrom',
+                    get_string('availablefrom', 'condition'),
+                    array('optional' => true, 'defaulttime' => $midnight));
             $mform->addHelpButton('availablefrom', 'availablefrom', 'condition');
-            $mform->addElement('date_selector', 'availableuntil', get_string('availableuntil', 'condition'), array('optional'=>true));
+            $mform->addElement('date_time_selector', 'availableuntil',
+                    get_string('availableuntil', 'condition'),
+                    array('optional' => true, 'defaulttime' => $midnight));
 
             // Conditions based on grades
             $gradeoptions = array();
index 5c0fd77..ed05e32 100644 (file)
@@ -57,6 +57,7 @@ $string['requires_completion_3'] = 'Not available unless the activity <strong>{$
 $string['requires_date'] = 'Available from {$a}.';
 $string['requires_date_before'] = 'Available until {$a}.';
 $string['requires_date_both'] = 'Available from {$a->from} to {$a->until}.';
+$string['requires_date_both_single_day'] = 'Available on {$a}.';
 $string['requires_grade_any'] = 'Not available until you have a grade in <strong>{$a}</strong>.';
 $string['requires_grade_max'] = 'Not available unless you get an appropriate score in <strong>{$a}</strong>.';
 $string['requires_grade_min'] = 'Not available until you achieve a required score in <strong>{$a}</strong>.';
index 83b79d3..f3279a1 100644 (file)
@@ -331,24 +331,83 @@ WHERE
             }
         }
 
-        // Dates
+        // The date logic is complicated. The intention of this logic is:
+        // 1) display date without time where possible (whenever the date is
+        //    midnight)
+        // 2) when the 'until' date is e.g. 00:00 on the 14th, we display it as
+        //    'until the 13th' (experience at the OU showed that students are
+        //    likely to interpret 'until <date>' as 'until the end of <date>').
+        // 3) This behaviour becomes confusing for 'same-day' dates where there
+        //    are some exceptions.
+        // Users in different time zones will typically not get the 'abbreviated'
+        // behaviour but it should work OK for them aside from that.
+
+        // The following cases are possible:
+        // a) From 13:05 on 14 Oct until 12:10 on 17 Oct (exact, exact)
+        // b) From 14 Oct until 12:11 on 17 Oct (midnight, exact)
+        // c) From 13:05 on 14 Oct until 17 Oct (exact, midnight 18 Oct)
+        // d) From 14 Oct until 17 Oct (midnight 14 Oct, midnight 18 Oct)
+        // e) On 14 Oct (midnight 14 Oct, midnight 15 Oct)
+        // f) From 13:05 on 14 Oct until 0:00 on 15 Oct (exact, midnight, same day)
+        // g) From 0:00 on 14 Oct until 12:05 on 14 Oct (midnight, exact, same day)
+        // h) From 13:05 on 14 Oct (exact)
+        // i) From 14 Oct (midnight)
+        // j) Until 13:05 on 14 Oct (exact)
+        // k) Until 14 Oct (midnight 15 Oct)
+
+        // Check if start and end dates are 'midnights', if so we show in short form
+        $shortfrom = self::is_midnight($this->cm->availablefrom);
+        $shortuntil = self::is_midnight($this->cm->availableuntil);
+
+        // For some checks and for display, we need the previous day for the 'until'
+        // value, if we are going to display it in short form
+        if ($this->cm->availableuntil) {
+            $daybeforeuntil = strtotime("-1 day", usergetmidnight($this->cm->availableuntil));
+        }
+
+        // Special case for if one but not both are exact and they are within a day
+        if ($this->cm->availablefrom && $this->cm->availableuntil &&
+                $shortfrom != $shortuntil && $daybeforeuntil < $this->cm->availablefrom) {
+            // Don't use abbreviated version (see examples f, g above)
+            $shortfrom = false;
+            $shortuntil = false;
+        }
+
+        // When showing short end date, the display time is the 'day before' one
+        $displayuntil = $shortuntil ? $daybeforeuntil : $this->cm->availableuntil;
+
         if ($this->cm->availablefrom && $this->cm->availableuntil) {
-            $information .= get_string('requires_date_both', 'condition',
-                (object)array(
-                    'from' => self::show_time($this->cm->availablefrom, false),
-                    'until' => self::show_time($this->cm->availableuntil, true)));
+            if ($shortfrom && $shortuntil && $daybeforeuntil == $this->cm->availablefrom) {
+                $information .= get_string('requires_date_both_single_day', 'condition',
+                        self::show_time($this->cm->availablefrom, true));
+            } else {
+                $information .= get_string('requires_date_both', 'condition', (object)array(
+                         'from' => self::show_time($this->cm->availablefrom, $shortfrom),
+                         'until' => self::show_time($displayuntil, $shortuntil)));
+            }
         } else if ($this->cm->availablefrom) {
             $information .= get_string('requires_date', 'condition',
-                self::show_time($this->cm->availablefrom, false));
+                self::show_time($this->cm->availablefrom, $shortfrom));
         } else if ($this->cm->availableuntil) {
             $information .= get_string('requires_date_before', 'condition',
-                self::show_time($this->cm->availableuntil, true));
+                self::show_time($displayuntil, $shortuntil));
         }
 
         $information = trim($information);
         return $information;
     }
 
+    /**
+     * Checks whether a given time refers exactly to midnight (in current user
+     * timezone).
+     * @param int $time Time
+     * @return bool True if time refers to midnight, false if it's some other
+     *   time or if it is set to zero
+     */
+    private static function is_midnight($time) {
+        return $time && usergetmidnight($time) == $time;
+    }
+
     /**
      * Determines whether this particular course-module is currently available
      * according to these criteria.
@@ -467,7 +526,8 @@ WHERE
                 $available = false;
 
                 $information .= get_string('requires_date', 'condition',
-                    self::show_time($this->cm->availablefrom, false));
+                        self::show_time($this->cm->availablefrom,
+                            self::is_midnight($this->cm->availablefrom)));
             }
         }
 
@@ -491,30 +551,15 @@ WHERE
     }
 
     /**
-     * Shows a time either as a date (if it falls exactly on the day) or
-     * a full date and time, according to user's timezone.
-     *
+     * Shows a time either as a date or a full date and time, according to
+     * user's timezone.
      * @param int $time Time
-     * @param bool $until True if this date should be treated as the second of
-     *   an inclusive pair - if so the time will be shown unless date is 23:59:59.
-     *   Without this the date shows for 0:00:00.
+     * @param bool $dateonly If true, uses date only
      * @return string Date
      */
-    private function show_time($time, $until) {
-        // Break down the time into fields
-        $userdate = usergetdate($time);
-
-        // Handle the 'inclusive' second date
-        if($until) {
-            $dateonly = $userdate['hours']==23 && $userdate['minutes']==59 &&
-                $userdate['seconds']==59;
-        } else {
-            $dateonly = $userdate['hours']==0 && $userdate['minutes']==0 &&
-                $userdate['seconds']==0;
-        }
-
-        return userdate($time, get_string(
-            $dateonly ? 'strftimedate' : 'strftimedatetime', 'langconfig'));
+    private function show_time($time, $dateonly) {
+        return userdate($time,
+                get_string($dateonly ? 'strftimedate' : 'strftimedatetime', 'langconfig'));
     }
 
     /**
index ad4056b..cea5a0f 100644 (file)
@@ -6792,6 +6792,24 @@ FROM
         upgrade_main_savepoint(true, 2011100700.02);
     }
 
+    if ($oldversion < 2011101200.01) {
+        // The conditional availability date system used to rely on dates being
+        // set to 23:59:59 for the end date, but now that exact times are
+        // supported, it uses midnight on the following day.
+        
+        // The query is restricted on 'time mod 10 = 9' in order that
+        // it is safe to run this upgrade twice if something goes wrong.
+        $DB->execute('UPDATE {course_modules} SET availableuntil = availableuntil + 1 ' .
+                'WHERE availableuntil > 0 AND ' . $DB->sql_modulo('availableuntil', 10) . ' = 9');
+        
+        // Because availableuntil is stored in modinfo, we need to clear modinfo
+        // for all courses.
+        rebuild_course_cache(0, true);
+
+        // Main savepoint reached
+        upgrade_main_savepoint(true, 2011101200.01);
+    }
+    
     return true;
 }
 
index 94b7dfe..957d7a3 100644 (file)
@@ -40,12 +40,13 @@ class MoodleQuickForm_date_time_selector extends MoodleQuickForm_group{
     *
     * startyear => integer start of range of years that can be selected
     * stopyear => integer last year that can be selected
+    * defaulttime => default time value if the field is currently not set
     * timezone => float/string timezone
     * applydst => apply users daylight savings adjustment?
     * step     => step to increment minutes by
     * optional => if true, show a checkbox beside the date to turn it on (or off)
     */
-    var $_options = array('startyear' => 1970, 'stopyear' => 2020,
+    var $_options = array('startyear' => 1970, 'stopyear' => 2020, 'defaulttime' => 0,
                     'timezone' => 99, 'applydst' => true, 'step' => 5, 'optional' => false);
 
    /**
@@ -159,7 +160,10 @@ class MoodleQuickForm_date_time_selector extends MoodleQuickForm_group{
                 }
                 $requestvalue=$value;
                 if ($value == 0) {
-                    $value = time();
+                    $value = $this->_options['defaulttime'];
+                    if (!$value) {
+                        $value = time();
+                    }
                 }
                 if (!is_array($value)) {
                     $currentdate = usergetdate($value);
index 0c2e508..91e3536 100644 (file)
@@ -31,7 +31,7 @@ defined('MOODLE_INTERNAL') || die();
 
 
 
-$version  = 2011101200.00;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2011101200.01;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes