Commit 05f184bb authored by Andrew Nicols's avatar Andrew Nicols
Browse files

MDL-59890 calendar: Add ability to add category events

parent 7b1e5e6f
......@@ -26,12 +26,14 @@ define([], function() {
eventFilterItem: "[data-action='filter-event-type']",
eventType: {
site: "[data-eventtype-site]",
category: "[data-eventtype-category]",
course: "[data-eventtype-course]",
group: "[data-eventtype-group]",
user: "[data-eventtype-user]",
},
popoverType: {
site: "[data-popover-eventtype-site]",
category: "[data-popover-eventtype-category]",
course: "[data-popover-eventtype-course]",
group: "[data-popover-eventtype-group]",
user: "[data-popover-eventtype-user]",
......
......@@ -55,7 +55,7 @@ class create extends \moodleform {
/**
* The form definition
*/
public function definition () {
public function definition() {
global $PAGE;
$mform = $this->_form;
......@@ -203,6 +203,9 @@ class create extends \moodleform {
if (isset($eventtypes['course'])) {
$options['course'] = get_string('course');
}
if (isset($eventtypes['category'])) {
$options['category'] = get_string('category');
}
if (isset($eventtypes['site'])) {
$options['site'] = get_string('site');
}
......@@ -223,6 +226,16 @@ class create extends \moodleform {
$mform->addElement('select', 'eventtype', get_string('eventkind', 'calendar'), $options);
}
if (isset($eventtypes['category'])) {
$categoryoptions = [];
foreach ($eventtypes['category'] as $id => $category) {
$categoryoptions[$id] = $category;
}
$mform->addElement('select', 'categoryid', get_string('category'), $categoryoptions);
$mform->hideIf('categoryid', 'eventtype', 'noteq', 'category');
}
if (isset($eventtypes['course'])) {
$courseoptions = [];
foreach ($eventtypes['course'] as $course) {
......
......@@ -89,6 +89,10 @@ define('CALENDAR_EVENT_GROUP', 4);
*/
define('CALENDAR_EVENT_USER', 8);
/**
* CALENDAR_EVENT_COURSECAT - Course category calendar event types
*/
define('CALENDAR_EVENT_COURSECAT', 16);
/**
* CALENDAR_IMPORT_FROM_FILE - import the calendar from a file
......@@ -360,8 +364,7 @@ class calendar_event {
if ($this->editorcontext === null) {
// Switch on the event type to decide upon the appropriate context to use for this event.
$this->editorcontext = $this->properties->context;
if ($this->properties->eventtype != 'user' && $this->properties->eventtype != 'course'
&& $this->properties->eventtype != 'site' && $this->properties->eventtype != 'group') {
if (!calendar_is_valid_eventtype($this->properties->eventtype)) {
return clean_text($this->properties->description, $this->properties->format);
}
}
......@@ -461,6 +464,11 @@ class calendar_event {
$this->properties->groupid = 0;
$this->properties->userid = $USER->id;
break;
case 'category':
$this->properties->groupid = 0;
$this->properties->category = 0;
$this->properties->userid = $USER->id;
break;
case 'group':
$this->properties->userid = $USER->id;
break;
......@@ -752,6 +760,17 @@ class calendar_event {
// We have a course and are within the course context so we had
// better use the courses max bytes value.
$this->editoroptions['maxbytes'] = $course->maxbytes;
} else if ($properties->eventtype === 'category') {
// First check the course is valid.
$category = $DB->get_record('course_categories', array('id' => $properties->categoryid));
if (!$category) {
print_error('invalidcourse');
}
// Course context.
$this->editorcontext = $this->properties->context;
// We have a course and are within the course context so we had
// better use the courses max bytes value.
$this->editoroptions['maxbytes'] = $course->maxbytes;
} else {
// If we get here we have a custom event type as used by some
// modules. In this case the event will have been added by
......@@ -896,8 +915,7 @@ class calendar_event {
// Switch on the event type to decide upon the appropriate context to use for this event.
$this->editorcontext = $this->properties->context;
if ($this->properties->eventtype != 'user' && $this->properties->eventtype != 'course'
&& $this->properties->eventtype != 'site' && $this->properties->eventtype != 'group') {
if (!calendar_is_valid_eventtype($this->properties->eventtype)) {
// We don't have a context here, do a normal format_text.
return external_format_text($this->properties->description, $this->properties->format, $this->editorcontext->id);
}
......@@ -2237,7 +2255,8 @@ function calendar_show_event_type($type, $user = null) {
*/
function calendar_set_event_type_display($type, $display = null, $user = null) {
$persist = get_user_preferences('calendar_persistflt', 0, $user);
$default = CALENDAR_EVENT_GLOBAL + CALENDAR_EVENT_COURSE + CALENDAR_EVENT_GROUP + CALENDAR_EVENT_USER;
$default = CALENDAR_EVENT_GLOBAL + CALENDAR_EVENT_COURSE + CALENDAR_EVENT_GROUP
+ CALENDAR_EVENT_USER + CALENDAR_EVENT_COURSECAT;
if ($persist === 0) {
global $SESSION;
if (!isset($SESSION->calendarshoweventtype)) {
......@@ -2273,14 +2292,16 @@ function calendar_set_event_type_display($type, $display = null, $user = null) {
* @param stdClass $allowed list of allowed edit for event type
* @param stdClass|int $course object of a course or course id
* @param array $groups array of groups for the given course
* @param stdClass|int $category object of a category
*/
function calendar_get_allowed_types(&$allowed, $course = null, $groups = null) {
function calendar_get_allowed_types(&$allowed, $course = null, $groups = null, $category = null) {
global $USER, $DB;
$allowed = new \stdClass();
$allowed->user = has_capability('moodle/calendar:manageownentries', \context_system::instance());
$allowed->groups = false;
$allowed->courses = false;
$allowed->categories = false;
$allowed->site = has_capability('moodle/calendar:manageentries', \context_course::instance(SITEID));
$getgroupsfunc = function($course, $context, $user) use ($groups) {
if ($course->groupmode != NOGROUPS || !$course->groupmodeforce) {
......@@ -2316,6 +2337,13 @@ function calendar_get_allowed_types(&$allowed, $course = null, $groups = null) {
}
}
}
if (!empty($category)) {
$catcontext = \context_coursecat::instance($category->id);
if (has_capability('moodle/category:manage', $catcontext)) {
$allowed->categories = [$category->id => 1];
}
}
}
/**
......@@ -2325,6 +2353,7 @@ function calendar_get_allowed_types(&$allowed, $course = null, $groups = null) {
* The returned array will optionally have 5 keys:
* 'user' : true if the logged in user can create user events
* 'site' : true if the logged in user can create site events
* 'category' : array of course categories that the user can create events for
* 'course' : array of courses that the user can create events for
* 'group': array of groups that the user can create events for
* 'groupcourses' : array of courses that the groups belong to (can
......@@ -2333,7 +2362,7 @@ function calendar_get_allowed_types(&$allowed, $course = null, $groups = null) {
* @return array The array of allowed types.
*/
function calendar_get_all_allowed_types() {
global $CFG, $USER;
global $CFG, $USER, $DB;
require_once($CFG->libdir . '/enrollib.php');
......@@ -2349,6 +2378,10 @@ function calendar_get_all_allowed_types() {
$types['site'] = true;
}
if (coursecat::has_manage_capability_on_any()) {
$types['category'] = coursecat::make_categories_list('moodle/category:manage');
}
// This function warms the context cache for the course so the calls
// to load the course context in calendar_get_allowed_types don't result
// in additional DB queries.
......@@ -2401,7 +2434,7 @@ function calendar_user_can_add_event($course) {
calendar_get_allowed_types($allowed, $course);
return (bool)($allowed->user || $allowed->groups || $allowed->courses || $allowed->site);
return (bool)($allowed->user || $allowed->groups || $allowed->courses || $allowed->category || $allowed->site);
}
/**
......@@ -2426,6 +2459,8 @@ function calendar_add_event_allowed($event) {
}
switch ($event->eventtype) {
case 'category':
return has_capability('moodle/category:manage', $event->context);
case 'course':
return has_capability('moodle/calendar:manageentries', $event->context);
case 'group':
......@@ -2485,6 +2520,9 @@ function calendar_get_eventtype_choices($courseid) {
if (!empty($allowed->courses)) {
$choices['course'] = get_string('courseevents', 'calendar');
}
if (!empty($allowed->categories)) {
$choices['category'] = get_string('categoryevents', 'calendar');
}
if (!empty($allowed->groups) and is_array($allowed->groups)) {
$choices['group'] = get_string('group');
}
......@@ -2505,6 +2543,8 @@ function calendar_add_subscription($sub) {
$sub->courseid = $SITE->id;
} else if ($sub->eventtype === 'group' || $sub->eventtype === 'course') {
$sub->courseid = $sub->course;
} else if ($sub->eventtype === 'category') {
$sub->categoryid = $sub->category;
} else {
// User events.
$sub->courseid = 0;
......@@ -3262,6 +3302,7 @@ function calendar_get_footer_options($calendar) {
function calendar_get_filter_types() {
$types = [
'site',
'category',
'course',
'group',
'user',
......@@ -3274,3 +3315,20 @@ function calendar_get_filter_types() {
];
}, $types);
}
/**
* Check whether the specified event type is valid.
*
* @param string $type
* @return bool
*/
function calendar_is_valid_eventtype($type) {
$validtypes = [
'user',
'group',
'course',
'category',
'site',
];
return in_array($type, $validtypes);
}
......@@ -44,6 +44,7 @@ $string['confirmeventseriesdelete'] = 'The "{$a->name}" event is part of a serie
$string['course'] = 'Course';
$string['courseevent'] = 'Course event';
$string['courseevents'] = 'Course events';
$string['categoryevents'] = 'Category events';
$string['courses'] = 'Courses';
$string['customexport'] = 'Custom range ({$a->timestart} - {$a->timeend})';
$string['daily'] = 'Daily';
......@@ -141,6 +142,7 @@ $string['groupevent'] = 'Group event';
$string['groupevents'] = 'Group events';
$string['eventtypeglobal'] = 'global';
$string['eventtypesite'] = 'global';
$string['eventtypecategory'] = 'category';
$string['eventtypecourse'] = 'course';
$string['eventtypemodule'] = 'module';
$string['eventtypegroup'] = 'group';
......@@ -227,6 +229,7 @@ $string['tue'] = 'Tue';
$string['tuesday'] = 'Tuesday';
$string['typeclose'] = 'Close event';
$string['typecourse'] = 'Course event';
$string['typecategory'] = 'Category event';
$string['typedue'] = 'Due event';
$string['typegradingdue'] = 'Grading due event';
$string['typegroup'] = 'Group event';
......
......@@ -291,6 +291,53 @@ class coursecat implements renderable, cacheable_object, IteratorAggregate {
return $categories;
}
/**
* Load all coursecat objects.
*
* @param array $options Options:
* @param bool $options.returnhidden Return categories even if they are hidden
* @return coursecat[]
*/
public static function get_all($options = null) {
global $DB;
if (null === $options) {
$options = [];
}
$coursecatrecordcache = cache::make('core', 'coursecatrecords');
$catcontextsql = \context_helper::get_preload_record_columns_sql('ctx');
$catsql = "SELECT cc.*, {$catcontextsql}
FROM {course_categories} cc
JOIN {context} ctx ON cc.id = ctx.instanceid";
$catsqlwhere = "WHERE ctx.contextlevel = :contextlevel";
$catsqlorder = "ORDER BY cc.depth ASC, cc.sortorder ASC";
$catrs = $DB->get_recordset_sql("{$catsql} {$catsqlwhere} {$catsqlorder}", [
'contextlevel' => CONTEXT_COURSECAT,
]);
$types['categories'] = [];
$categories = [];
$toset = [];
foreach ($catrs as $record) {
\context_helper::preload_from_record($record);
$category = new coursecat($record);
$toset[$category->id] = $category;
if (!empty($options['returnhidden']) || $category->is_uservisible()) {
$categories[$record->id] = new coursecat($record);
}
}
$catrs->close();
$coursecatrecordcache->set_many($toset);
return $categories;
}
/**
* Returns the first found category
*
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment