Merge branch 'MDL-60764' of git://github.com/stronk7/moodle
authorDavid Monllao <davidm@moodle.com>
Fri, 10 Nov 2017 09:20:25 +0000 (10:20 +0100)
committerDavid Monllao <davidm@moodle.com>
Fri, 10 Nov 2017 09:20:25 +0000 (10:20 +0100)
15 files changed:
admin/tool/analytics/cli/guess_course_start_and_end.php
blocks/calendar_month/block_calendar_month.php
blocks/calendar_upcoming/block_calendar_upcoming.php
blocks/calendar_upcoming/upgrade.txt [new file with mode: 0644]
calendar/classes/external/calendar_upcoming_exporter.php
calendar/templates/calendar_upcoming_mini.mustache
calendar/upgrade.txt
lib/deprecatedlib.php
mod/scorm/report/graphs/classes/report.php
mod/scorm/report/interactions/classes/report.php
mod/workshop/form/rubric/edit_form.php
mod/workshop/form/rubric/lang/en/workshopform_rubric.php
theme/boost/scss/moodle/core.scss
theme/bootstrapbase/less/moodle/core.less
theme/bootstrapbase/style/moodle.css

index 4e5ea9b..e0c8974 100644 (file)
@@ -117,12 +117,21 @@ function tool_analytics_calculate_course_dates($course, $options) {
 
     $notification = $course->shortname . ' (id = ' . $course->id . '): ';
 
+    $originalenddate = null;
+    $guessedstartdate = null;
+    $guessedenddate = null;
+    $samestartdate = null;
+    $lowerenddate = null;
+
     if ($options['guessstart'] || $options['guessall']) {
 
         $originalstartdate = $course->startdate;
 
         $guessedstartdate = $courseman->guess_start();
-        if ($guessedstartdate == $originalstartdate) {
+        $samestartdate = ($guessedstartdate == $originalstartdate);
+        $lowerenddate = ($course->enddate && ($course->enddate < $guessedstartdate));
+
+        if ($samestartdate) {
             if (!$guessedstartdate) {
                 $notification .= PHP_EOL . '  ' . get_string('cantguessstartdate', 'tool_analytics');
             } else {
@@ -131,6 +140,9 @@ function tool_analytics_calculate_course_dates($course, $options) {
             }
         } else if (!$guessedstartdate) {
             $notification .= PHP_EOL . '  ' . get_string('cantguessstartdate', 'tool_analytics');
+        } else if ($lowerenddate) {
+            $notification .= PHP_EOL . '  ' . get_string('cantguessstartdate', 'tool_analytics') . ': ' .
+                get_string('enddatebeforestartdate', 'error') . ' - ' . userdate($guessedstartdate);
         } else {
             // Update it to something we guess.
 
@@ -151,6 +163,10 @@ function tool_analytics_calculate_course_dates($course, $options) {
 
     if ($options['guessend'] || $options['guessall']) {
 
+        if (!empty($lowerenddate) && !empty($guessedstartdate)) {
+            $course->startdate = $guessedstartdate;
+        }
+
         $originalenddate = $course->enddate;
 
         $format = course_get_format($course);
@@ -196,10 +212,8 @@ function tool_analytics_calculate_course_dates($course, $options) {
                     $updateit = true;
                 }
 
-                if ($options['update']) {
-                    if ($course->enddate > $course->startdate) {
-                        update_course($course);
-                    }
+                if ($options['update'] && $updateit) {
+                    update_course($course);
                 }
             }
         }
index 657fe42..6e31b70 100644 (file)
@@ -51,7 +51,7 @@ class block_calendar_month extends block_base {
         $courseid = $this->page->course->id;
         $categoryid = ($this->page->context->contextlevel === CONTEXT_COURSECAT) ? $this->page->category->id : null;
         $calendar = \calendar_information::create(time(), $courseid, $categoryid);
-        list($data, $template) = calendar_get_view($calendar, 'mini');
+        list($data, $template) = calendar_get_view($calendar, 'mini', isloggedin());
 
         $renderer = $this->page->get_renderer('core_calendar');
         $this->content->text .= $renderer->render_from_template($template, $data);
index 6ae9c7f..137ba26 100644 (file)
@@ -69,4 +69,59 @@ class block_calendar_upcoming extends block_base {
 
         return $this->content;
     }
+
+    /**
+     * Get the upcoming event block content.
+     *
+     * @param array $events list of events
+     * @param \moodle_url|string $linkhref link to event referer
+     * @param boolean $showcourselink whether links to courses should be shown
+     * @return string|null $content html block content
+     * @deprecated since 3.4
+     */
+    public static function get_upcoming_content($events, $linkhref = null, $showcourselink = false) {
+        debugging(
+                'get_upcoming_content() is deprecated. ' .
+                'Please see block_calendar_upcoming::get_content() for the correct API usage.',
+                DEBUG_DEVELOPER
+            );
+
+        $content = '';
+        $lines = count($events);
+
+        if (!$lines) {
+            return $content;
+        }
+
+        for ($i = 0; $i < $lines; ++$i) {
+            if (!isset($events[$i]->time)) {
+                continue;
+            }
+            $events[$i] = calendar_add_event_metadata($events[$i]);
+            $content .= '<div class="event"><span class="icon c0">' . $events[$i]->icon . '</span>';
+            if (!empty($events[$i]->referer)) {
+                // That's an activity event, so let's provide the hyperlink.
+                $content .= $events[$i]->referer;
+            } else {
+                if (!empty($linkhref)) {
+                    $href = calendar_get_link_href(new \moodle_url(CALENDAR_URL . $linkhref), 0, 0, 0,
+                        $events[$i]->timestart);
+                    $href->set_anchor('event_' . $events[$i]->id);
+                    $content .= \html_writer::link($href, $events[$i]->name);
+                } else {
+                    $content .= $events[$i]->name;
+                }
+            }
+            $events[$i]->time = str_replace('&raquo;', '<br />&raquo;', $events[$i]->time);
+            if ($showcourselink && !empty($events[$i]->courselink)) {
+                $content .= \html_writer::div($events[$i]->courselink, 'course');
+            }
+            $content .= '<div class="date">' . $events[$i]->time . '</div></div>';
+            if ($i < $lines - 1) {
+                $content .= '<hr />';
+            }
+        }
+
+        return $content;
+    }
 }
diff --git a/blocks/calendar_upcoming/upgrade.txt b/blocks/calendar_upcoming/upgrade.txt
new file mode 100644 (file)
index 0000000..b5c14a3
--- /dev/null
@@ -0,0 +1,5 @@
+=== 3.4 ===
+
+* block_calendar_upcoming::get_upcoming_content has been deprecated. Please
+  update your code to use the new APIs. You can see an example of how these
+  may be used in block_calendar_upcoming::get_content().
index 42fe7b9..aead6d1 100644 (file)
@@ -87,6 +87,9 @@ class calendar_upcoming_exporter extends exporter {
                 'optional' => true,
                 'default' => 0,
             ],
+            'isloggedin' => [
+                'type' => PARAM_BOOL,
+            ],
         ];
     }
 
@@ -106,6 +109,7 @@ class calendar_upcoming_exporter extends exporter {
             'course' => $this->calendar->course->id,
         ]);
         $this->url = $url;
+        $return['isloggedin'] = isloggedin();
         $return['events'] = array_map(function($event) use ($cache, $output, $url) {
             $context = $cache->get_context($event);
             $course = $cache->get_course($event);
index 8f276be..c2317bd 100644 (file)
 <div id="calendar-upcoming-block-{{uniqid}}" data-template="core_calendar/upcoming_mini">
     {{> core_calendar/upcoming_mini}}
 </div>
+{{#isloggedin}}
 {{#js}}
 require(['jquery', 'core_calendar/calendar_view'], function($, CalendarView) {
     CalendarView.init($("#calendar-upcoming-block-{{uniqid}}"), 'upcoming');
 });
 {{/js}}
+{{/isloggedin}}
index 528cc8d..b2973e5 100644 (file)
@@ -2,8 +2,7 @@ This files describes API changes in /calendar/* ,
 information provided here is intended especially for developers.
 
 === 3.4 ===
-* calendar_get_mini has been deprecated. Please update to use the new
-  exporters and renderers.
+* calendar_get_mini, and calendar_get_upcoming have been deprecated. Please update to use the new exporters and renderers.
 * added core_calendar_get_valid_event_timestart_range and core_calendar_event_timestart_updated callbacks for module events
   when the update_event_start_day function is used in the local api.
 
index 33e0398..9ef0019 100644 (file)
@@ -6243,8 +6243,11 @@ function calendar_wday_name($englishname) {
 function calendar_get_block_upcoming($events, $linkhref = null, $showcourselink = false) {
     global $CFG;
 
-    debugging(__FUNCTION__ . '() is deprecated, please use block_calendar_upcoming::get_upcoming_content() instead.',
-        DEBUG_DEVELOPER);
+    debugging(
+            __FUNCTION__ . '() has been deprecated. ' .
+            'Please see block_calendar_upcoming::get_content() for the correct API usage.',
+            DEBUG_DEVELOPER
+        );
 
     require_once($CFG->dirroot . '/blocks/moodleblock.class.php');
     require_once($CFG->dirroot . '/blocks/calendar_upcoming/block_calendar_upcoming.php');
@@ -6430,3 +6433,81 @@ function calendar_get_mini($courses, $groups, $users, $calmonth = false, $calyea
     list($data, $template) = calendar_get_view($calendar, 'mini');
     return $renderer->render_from_template($template, $data);
 }
+
+/**
+ * Gets the calendar upcoming event.
+ *
+ * @param array $courses array of courses
+ * @param array|int|bool $groups array of groups, group id or boolean for all/no group events
+ * @param array|int|bool $users array of users, user id or boolean for all/no user events
+ * @param int $daysinfuture number of days in the future we 'll look
+ * @param int $maxevents maximum number of events
+ * @param int $fromtime start time
+ * @return array $output array of upcoming events
+ * @deprecated since Moodle 3.4. MDL-59333
+ */
+function calendar_get_upcoming($courses, $groups, $users, $daysinfuture, $maxevents, $fromtime=0) {
+    debugging(
+            'calendar_get_upcoming() has been deprecated. ' .
+            'Please see block_calendar_upcoming::get_content() for the correct API usage.',
+            DEBUG_DEVELOPER
+        );
+
+    global $COURSE;
+
+    $display = new \stdClass;
+    $display->range = $daysinfuture; // How many days in the future we 'll look.
+    $display->maxevents = $maxevents;
+
+    $output = array();
+
+    $processed = 0;
+    $now = time(); // We 'll need this later.
+    $usermidnighttoday = usergetmidnight($now);
+
+    if ($fromtime) {
+        $display->tstart = $fromtime;
+    } else {
+        $display->tstart = $usermidnighttoday;
+    }
+
+    // This works correctly with respect to the user's DST, but it is accurate
+    // only because $fromtime is always the exact midnight of some day!
+    $display->tend = usergetmidnight($display->tstart + DAYSECS * $display->range + 3 * HOURSECS) - 1;
+
+    // Get the events matching our criteria.
+    $events = calendar_get_legacy_events($display->tstart, $display->tend, $users, $groups, $courses);
+
+    // This is either a genius idea or an idiot idea: in order to not complicate things, we use this rule: if, after
+    // possibly removing SITEID from $courses, there is only one course left, then clicking on a day in the month
+    // will also set the $SESSION->cal_courses_shown variable to that one course. Otherwise, we 'd need to add extra
+    // arguments to this function.
+    $hrefparams = array();
+    if (!empty($courses)) {
+        $courses = array_diff($courses, array(SITEID));
+        if (count($courses) == 1) {
+            $hrefparams['course'] = reset($courses);
+        }
+    }
+
+    if ($events !== false) {
+        foreach ($events as $event) {
+            if (!empty($event->modulename)) {
+                $instances = get_fast_modinfo($event->courseid)->get_instances_of($event->modulename);
+                if (empty($instances[$event->instance]->uservisible)) {
+                    continue;
+                }
+            }
+
+            if ($processed >= $display->maxevents) {
+                break;
+            }
+
+            $event->time = calendar_format_event_time($event, $now, $hrefparams);
+            $output[] = $event;
+            $processed++;
+        }
+    }
+
+    return $output;
+}
index 8174686..4971d5c 100644 (file)
@@ -77,7 +77,7 @@ class report extends \mod_scorm\report {
         foreach ($attempts as $attempt) {
             if ($trackdata = scorm_get_tracks($scoid, $attempt->userid, $attempt->attempt)) {
                 if (isset($trackdata->score_raw)) {
-                    $score = $trackdata->score_raw;
+                    $score = (int) $trackdata->score_raw;
                     if (empty($trackdata->score_min)) {
                         $minmark = 0;
                     } else {
index de74b4e..33da5ad 100644 (file)
@@ -475,6 +475,7 @@ class report extends \mod_scorm\report {
                         $row[] = scorm_grade_user_attempt($scorm, $scouser->userid, $scouser->attempt);
                     }
                     // Print out all scores of attempt.
+                    $emptyrow = $download ? '' : '&nbsp;';
                     foreach ($scoes as $sco) {
                         if ($sco->launch != '') {
                             if ($trackdata = scorm_get_tracks($sco->id, $scouser->userid, $scouser->attempt)) {
@@ -507,7 +508,7 @@ class report extends \mod_scorm\report {
                                         if (isset($trackdata->$element)) {
                                             $row[] = s($trackdata->$element);
                                         } else {
-                                            $row[] = '&nbsp;';
+                                            $row[] = $emptyrow;
                                         }
                                     }
                                     if ($displayoptions['resp']) {
@@ -515,7 +516,7 @@ class report extends \mod_scorm\report {
                                         if (isset($trackdata->$element)) {
                                             $row[] = s($trackdata->$element);
                                         } else {
-                                            $row[] = '&nbsp;';
+                                            $row[] = $emptyrow;
                                         }
                                     }
                                     if ($displayoptions['right']) {
@@ -533,7 +534,7 @@ class report extends \mod_scorm\report {
                                             }
                                             $row[] = $rightans;
                                         } else {
-                                            $row[] = '&nbsp;';
+                                            $row[] = $emptyrow;
                                         }
                                     }
                                     if ($displayoptions['result']) {
@@ -541,7 +542,7 @@ class report extends \mod_scorm\report {
                                         if (isset($trackdata->$element)) {
                                             $row[] = s($trackdata->$element);
                                         } else {
-                                            $row[] = '&nbsp;';
+                                            $row[] = $emptyrow;
                                         }
                                     }
                                 }
@@ -556,7 +557,7 @@ class report extends \mod_scorm\report {
                                 }
                                 // Complete the empty cells.
                                 for ($i = 0; $i < count($columns) - $nbmaincolumns; $i++) {
-                                    $row[] = '&nbsp;';
+                                    $row[] = $emptyrow;
                                 }
                             }
                         }
index 85af10c..5dcf4e1 100644 (file)
@@ -126,11 +126,13 @@ class workshop_edit_rubric_strategy_form extends workshop_edit_strategy_form {
             }
 
             // Make sure the levels grades are unique within the criterion.
+            $atleastonelevel = false;
             for ($j = 0; isset($data['levelid__idx_'.$i.'__idy_'.$j]); $j++) {
                 if (0 == strlen(trim($data['definition__idx_'.$i.'__idy_'.$j]))) {
                     // The level definition is empty and will not be saved.
                     continue;
                 }
+                $atleastonelevel = true;
 
                 $levelgrade = $data['grade__idx_'.$i.'__idy_'.$j];
 
@@ -143,6 +145,9 @@ class workshop_edit_rubric_strategy_form extends workshop_edit_strategy_form {
                     $dimgrades[$levelgrade] = $j;
                 }
             }
+            if (!$atleastonelevel) {
+                $errors['level__idx_'.$i.'__idy_0'] = get_string('mustdefinelevel', 'workshopform_rubric');
+            }
         }
 
         return $errors;
index 3785c4f..d62860f 100644 (file)
@@ -34,5 +34,6 @@ $string['layoutlist'] = 'List';
 $string['levelgroup'] = 'Level grade and definition';
 $string['levels'] = 'Levels';
 $string['mustbeunique'] = 'Level grades must be unique within a criterion';
+$string['mustdefinelevel'] = 'At least one level is required';
 $string['mustchooseone'] = 'You have to select one of these items';
 $string['pluginname'] = 'Rubric';
index 2bd123d..8a9ff6d 100644 (file)
@@ -1933,7 +1933,6 @@ dd:after {
 }
 
 .inplaceeditable {
-    display: block;
     &.inplaceeditingon {
         position: relative;
 
@@ -1975,6 +1974,10 @@ dd:after {
     &.inplaceeditable-toggle .quickediticon {
         display: none;
     }
+
+    &.inplaceeditable-autocomplete {
+        display: block;
+    }
 }
 
 h3.sectionname .inplaceeditable.inplaceeditingon .editinstructions {
index c0c6b16..52627ad 100644 (file)
@@ -2257,7 +2257,6 @@ dd:after {
 }
 
 .inplaceeditable {
-    display: block;
     &.inplaceeditingon {
         position: relative;
 
@@ -2300,6 +2299,10 @@ dd:after {
     &.inplaceeditable-toggle .quickediticon {
         display: none;
     }
+
+    &.inplaceeditable-autocomplete {
+        display: block;
+    }
 }
 
 h3.sectionname .inplaceeditable.inplaceeditingon .editinstructions {
index f08b7c6..940f2cc 100644 (file)
@@ -4674,9 +4674,6 @@ dd:after {
 .nav-tabs > .active > a[href]:focus {
   cursor: pointer;
 }
-.inplaceeditable {
-  display: block;
-}
 .inplaceeditable.inplaceeditingon {
   position: relative;
 }
@@ -4712,6 +4709,9 @@ dd:after {
 .inplaceeditable.inplaceeditable-toggle .quickediticon {
   display: none;
 }
+.inplaceeditable.inplaceeditable-autocomplete {
+  display: block;
+}
 h3.sectionname .inplaceeditable.inplaceeditingon .editinstructions {
   margin-top: -20px;
 }