Skip to content

Commit

Permalink
MDL-60062 calendar: prevent drag and drop of override events
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanwyllie committed Nov 7, 2017
1 parent 478b1d1 commit 6688ae2
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 12 deletions.
18 changes: 17 additions & 1 deletion calendar/classes/external/calendar_event_exporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ protected static function define_other_properties() {
'type' => PARAM_TEXT,
'optional' => true
];
$values['draggable'] = [
'type' => PARAM_BOOL,
'default' => false
];

return $values;
}
Expand All @@ -90,6 +94,10 @@ protected function get_other_values(renderer_base $output) {
$values = parent::get_other_values($output);
$event = $this->event;

// By default all events that can be edited are
// draggable.
$values['draggable'] = $values['canedit'];

if ($moduleproxy = $event->get_course_module()) {
$modulename = $moduleproxy->get('modname');
$moduleid = $moduleproxy->get('id');
Expand Down Expand Up @@ -226,9 +234,17 @@ protected function get_module_timestamp_limits($event) {
'mod_' . $modname,
'core_calendar_get_valid_event_timestart_range',
[$mapper->from_event_to_legacy_event($event), $moduleinstance],
[null, null]
[false, false]
);

// The callback will return false for either of the
// min or max cutoffs to indicate that there are no
// valid timestart values. In which case the event is
// not draggable.
if ($min === false || $max === false) {
return ['draggable' => false];
}

if ($min) {
$values = array_merge($values, $this->get_module_timestamp_min_limit($starttime, $min));
}
Expand Down
8 changes: 7 additions & 1 deletion calendar/classes/local/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,15 @@ public static function update_event_start_day(
'mod_' . $event->get_course_module()->get('modname'),
'core_calendar_get_valid_event_timestart_range',
[$legacyevent, $moduleinstance],
[null, null]
[false, false]
);

// If the callback returns false for either value it means that
// there is no valid time start range.
if ($min === false || $max === false) {
throw new \moodle_exception('The start day of this event can not be modified');
}

if ($min && $legacyevent->timestart < $min[0]) {
throw new \moodle_exception($min[1]);
}
Expand Down
4 changes: 2 additions & 2 deletions calendar/templates/month_detailed.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
{{^underway}}
<li data-region="event-item"
data-eventtype-{{calendareventtype}}="1"
{{#canedit}}
{{#draggable}}
draggable="true"
data-drag-type="move"
{{#mindaytimestamp}}
Expand All @@ -102,7 +102,7 @@
{{#maxdayerror}}
data-max-day-error="{{.}}"
{{/maxdayerror}}
{{/canedit}}>
{{/draggable}}>

<a data-action="view-event" data-event-id="{{id}}" href="{{url}}" title="{{name}}">
<span class="badge badge-circle calendar_event_{{calendareventtype}}">
Expand Down
46 changes: 46 additions & 0 deletions calendar/tests/local_api_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -1239,4 +1239,50 @@ public function test_update_event_start_day_activity_event_before_min() {
$this->expectException('moodle_exception');
$newevent = \core_calendar\local\api::update_event_start_day($event, $newstartdate);
}

/**
* Updating the start day of an overridden event belonging to an activity
* should result in an exception. This is to prevent the drag and drop
* of override events.
*
* Note: This test uses the quiz activity because it requires
* module callbacks to be in place and override event support to test.
*/
public function test_update_event_start_day_activity_event_override() {
global $CFG, $DB;
require_once($CFG->dirroot . '/calendar/lib.php');
require_once($CFG->dirroot . '/mod/quiz/lib.php');

$this->resetAfterTest(true);
$this->setAdminUser();
$mapper = container::get_event_mapper();
$timeopen = new DateTimeImmutable('2017-01-1T15:00:00+08:00');
$newstartdate = new DateTimeImmutable('2016-02-2T10:00:00+08:00');
$generator = $this->getDataGenerator();
$user = $generator->create_user();
$course = $generator->create_course();
$quizgenerator = $generator->get_plugin_generator('mod_quiz');
$quiz = $quizgenerator->create_instance([
'course' => $course->id,
'timeopen' => $timeopen->getTimestamp(),
]);
$event = create_event([
'courseid' => $course->id,
'userid' => $user->id,
'modulename' => 'quiz',
'instance' => $quiz->id,
'eventtype' => QUIZ_EVENT_TYPE_OPEN,
'timestart' => $timeopen->getTimestamp()
]);
$event = $mapper->from_legacy_event_to_event($event);
$record = (object) [
'quiz' => $quiz->id,
'userid' => $user->id
];

$DB->insert_record('quiz_overrides', $record);

$this->expectException('moodle_exception');
$newevent = \core_calendar\local\api::update_event_start_day($event, $newstartdate);
}
}
4 changes: 4 additions & 0 deletions mod/assign/lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -1946,8 +1946,12 @@ function mod_assign_core_calendar_event_action_shows_item_count(calendar_event $
* [1506741172, 'The due date must be before the cutoff date']
* ]
*
* If the event does not have a valid timestart range then [false, false] will
* be returned.
*
* @param calendar_event $event The calendar event to get the time range for
* @param stdClass $instance The module instance to get the range from
* @return array
*/
function mod_assign_core_calendar_get_valid_event_timestart_range(\calendar_event $event, \stdClass $instance) {
global $CFG;
Expand Down
9 changes: 7 additions & 2 deletions mod/assign/locallib.php
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,11 @@ public function is_override_calendar_event(\calendar_event $event) {
* [1506741172, 'The due date must be before the cutoff date']
* ]
*
* If the event does not have a valid timestart range then [false, false] will
* be returned.
*
* @param calendar_event $event The calendar event to get the time range for
* @return array
*/
function get_valid_calendar_event_timestart_range(\calendar_event $event) {
$instance = $this->get_instance();
Expand All @@ -1018,8 +1022,9 @@ function get_valid_calendar_event_timestart_range(\calendar_event $event) {
// the only events that can be overridden, so we can save a DB
// query if we don't bother checking other events.
if ($this->is_override_calendar_event($event)) {
// This is an override event so we should ignore it.
return [null, null];
// This is an override event so there is no valid timestart
// range to set it to.
return [false, false];
}

if ($submissionsfromdate) {
Expand Down
4 changes: 2 additions & 2 deletions mod/assign/tests/lib_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -883,8 +883,8 @@ public function test_mod_assign_core_calendar_get_valid_event_timestart_range_ov
$DB->insert_record('assign_overrides', $record);

list($min, $max) = mod_assign_core_calendar_get_valid_event_timestart_range($event, $instance);
$this->assertNull($min);
$this->assertNull($max);
$this->assertFalse($min);
$this->assertFalse($max);
}

/**
Expand Down
7 changes: 5 additions & 2 deletions mod/quiz/lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -2264,6 +2264,9 @@ function mod_quiz_get_completion_active_rule_descriptions($cm) {
* If either value isn't set then null will be returned instead to
* indicate that there is no cutoff for that value.
*
* If the vent has no valid timestart range then [false, false] will
* be returned. This is the case for overriden events.
*
* A minimum and maximum cutoff return value will look like:
* [
* [1505704373, 'The date must be after this date'],
Expand All @@ -2279,9 +2282,9 @@ function mod_quiz_core_calendar_get_valid_event_timestart_range(\calendar_event
global $CFG, $DB;
require_once($CFG->dirroot . '/mod/quiz/locallib.php');

// No restrictions on override events.
// Overrides do not have a valid timestart range.
if (quiz_is_overriden_calendar_event($event)) {
return [null, null];
return [false, false];
}

$mindate = null;
Expand Down
4 changes: 2 additions & 2 deletions mod/quiz/tests/calendar_event_modified_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,8 @@ public function test_mod_quiz_core_calendar_get_valid_event_timestart_range_over

list ($min, $max) = mod_quiz_core_calendar_get_valid_event_timestart_range($event, $quiz);

$this->assertNull($min);
$this->assertNull($max);
$this->assertFalse($min);
$this->assertFalse($max);
}

/**
Expand Down

0 comments on commit 6688ae2

Please sign in to comment.