mirror of
https://github.com/moodle/moodle.git
synced 2025-04-14 04:52:36 +02:00
MDL-58866 core_calendar: allow component events
This commit is contained in:
parent
1afe68f382
commit
1a972b06f1
@ -56,7 +56,7 @@
|
||||
<small class="text-muted text-truncate mb-0">{{#quote}}{{{course.fullnamedisplay}}}{{/quote}}</small>
|
||||
{{#action.actionable}}
|
||||
<h6 class="mb-0 pt-2">
|
||||
<a href="{{{action.url}}}" aria-label="{{{action.name}}}" title="{{{action.name}}}" class="list-group-item-action">{{{action.name}}}</a>
|
||||
<a href="{{action.url}}" aria-label="{{action.name}}" title="{{action.name}}" class="list-group-item-action">{{{action.name}}}</a>
|
||||
{{#action.showitemcount}}
|
||||
<span class="badge badge-secondary">{{action.itemcount}}</span>
|
||||
{{/action.showitemcount}}
|
||||
|
2
calendar/amd/build/view_manager.min.js
vendored
2
calendar/amd/build/view_manager.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -403,7 +403,8 @@ const renderEventSummaryModal = (eventId) => {
|
||||
candelete: eventData.candelete,
|
||||
headerclasses: getEventTypeClassFromType(eventData.normalisedeventtype),
|
||||
isactionevent: eventData.isactionevent,
|
||||
url: eventData.url
|
||||
url: eventData.url,
|
||||
action: eventData.action
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -109,7 +109,6 @@ class calendar_event_exporter extends event_exporter_base {
|
||||
} else if ($event->get_type() == 'category') {
|
||||
$url = $event->get_category()->get_proxied_instance()->get_view_link();
|
||||
} else {
|
||||
// TODO MDL-58866 We do not have any way to find urls for events outside of course modules.
|
||||
$url = course_get_url($hascourse ? $course : SITEID);
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ class event_action_exporter extends exporter {
|
||||
public function __construct(action_interface $action, $related = []) {
|
||||
$data = new \stdClass();
|
||||
$data->name = $action->get_name();
|
||||
$data->url = $action->get_url()->out(true);
|
||||
$data->url = $action->get_url()->out(false);
|
||||
$data->itemcount = $action->get_item_count();
|
||||
$data->actionable = $action->is_actionable();
|
||||
|
||||
@ -90,17 +90,14 @@ class event_action_exporter extends exporter {
|
||||
protected function get_other_values(renderer_base $output) {
|
||||
$event = $this->related['event'];
|
||||
|
||||
if (!$event->get_course_module()) {
|
||||
// TODO MDL-58866 Only activity modules currently support this callback.
|
||||
if (!$event->get_component()) {
|
||||
return ['showitemcount' => false];
|
||||
}
|
||||
$modulename = $event->get_course_module()->get('modname');
|
||||
$component = 'mod_' . $modulename;
|
||||
$showitemcountcallback = 'core_calendar_event_action_shows_item_count';
|
||||
$mapper = container::get_event_mapper();
|
||||
$calevent = $mapper->from_event_to_legacy_event($event);
|
||||
$params = [$calevent, $this->data->itemcount];
|
||||
$showitemcount = component_callback($component, $showitemcountcallback, $params, false);
|
||||
$showitemcount = component_callback($event->get_component(), $showitemcountcallback, $params, false);
|
||||
|
||||
// Prepare other values data.
|
||||
$data = [
|
||||
@ -120,4 +117,13 @@ class event_action_exporter extends exporter {
|
||||
'event' => '\\core_calendar\\local\\event\\entities\\event_interface'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method returning parameters for formatting 'name' property
|
||||
*
|
||||
* @return bool[]
|
||||
*/
|
||||
protected function get_format_parameters_for_name() {
|
||||
return ['escape' => false];
|
||||
}
|
||||
}
|
||||
|
16
calendar/classes/external/event_exporter.php
vendored
16
calendar/classes/external/event_exporter.php
vendored
@ -51,10 +51,6 @@ class event_exporter extends event_exporter_base {
|
||||
$values = parent::define_other_properties();
|
||||
|
||||
$values['url'] = ['type' => PARAM_URL];
|
||||
$values['action'] = [
|
||||
'type' => event_action_exporter::read_properties_definition(),
|
||||
'optional' => true,
|
||||
];
|
||||
return $values;
|
||||
}
|
||||
|
||||
@ -86,7 +82,6 @@ class event_exporter extends event_exporter_base {
|
||||
} else if ($event->get_type() == 'course') {
|
||||
$url = \course_get_url($this->related['course'] ?: SITEID);
|
||||
} else {
|
||||
// TODO MDL-58866 We do not have any way to find urls for events outside of course modules.
|
||||
$url = \course_get_url($this->related['course'] ?: SITEID);
|
||||
}
|
||||
$values['url'] = $url->out(false);
|
||||
@ -95,17 +90,6 @@ class event_exporter extends event_exporter_base {
|
||||
$legacyevent = container::get_event_mapper()->from_event_to_legacy_event($event);
|
||||
$values['formattedtime'] = calendar_format_event_time($legacyevent, time(), null, false);
|
||||
|
||||
if ($event instanceof action_event_interface) {
|
||||
$actionrelated = [
|
||||
'context' => $context,
|
||||
'event' => $event
|
||||
];
|
||||
$actionexporter = new event_action_exporter($event->get_action(), $actionrelated);
|
||||
$values['action'] = $actionexporter->export($output);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
|
@ -89,6 +89,7 @@ class event_exporter_base extends exporter {
|
||||
$data->timesort = $event->get_times()->get_sort_time()->getTimestamp();
|
||||
$data->visible = $event->is_visible() ? 1 : 0;
|
||||
$data->timemodified = $event->get_times()->get_modified_time()->getTimestamp();
|
||||
$data->component = $event->get_component();
|
||||
|
||||
if ($repeats = $event->get_repeats()) {
|
||||
$data->repeatid = $repeats->get_id();
|
||||
@ -160,6 +161,12 @@ class event_exporter_base extends exporter {
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'component' => [
|
||||
'type' => PARAM_COMPONENT,
|
||||
'optional' => true,
|
||||
'default' => null,
|
||||
'null' => NULL_ALLOWED
|
||||
],
|
||||
'modulename' => [
|
||||
'type' => PARAM_TEXT,
|
||||
'optional' => true,
|
||||
@ -242,6 +249,10 @@ class event_exporter_base extends exporter {
|
||||
'normalisedeventtypetext' => [
|
||||
'type' => PARAM_TEXT
|
||||
],
|
||||
'action' => [
|
||||
'type' => event_action_exporter::read_properties_definition(),
|
||||
'optional' => true,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@ -291,7 +302,7 @@ class event_exporter_base extends exporter {
|
||||
$values['category'] = $categorysummaryexporter->export($output);
|
||||
}
|
||||
|
||||
if ($course) {
|
||||
if ($course && $course->id != SITEID) {
|
||||
$coursesummaryexporter = new course_summary_exporter($course, ['context' => $context]);
|
||||
$values['course'] = $coursesummaryexporter->export($output);
|
||||
}
|
||||
@ -319,6 +330,16 @@ class event_exporter_base extends exporter {
|
||||
['context' => \context_course::instance($event->get_course()->get('id'))]);
|
||||
}
|
||||
|
||||
if ($event instanceof action_event_interface) {
|
||||
// Export event action if applicable.
|
||||
$actionrelated = [
|
||||
'context' => $this->related['context'],
|
||||
'event' => $event
|
||||
];
|
||||
$actionexporter = new event_action_exporter($event->get_action(), $actionrelated);
|
||||
$values['action'] = $actionexporter->export($output);
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
|
@ -279,7 +279,7 @@ class container {
|
||||
// of the event class.
|
||||
$mapper = self::$eventmapper;
|
||||
$action = null;
|
||||
if ($event->get_course_module()) {
|
||||
if ($event->get_component()) {
|
||||
$requestinguserid = self::get_requesting_user();
|
||||
$legacyevent = $mapper->from_event_to_legacy_event($event);
|
||||
// We know for a fact that the the requesting user might be different from the logged in user,
|
||||
@ -288,10 +288,9 @@ class container {
|
||||
$legacyevent->userid = $requestinguserid;
|
||||
}
|
||||
|
||||
// TODO MDL-58866 Only activity modules currently support this callback.
|
||||
// Any other event will not be displayed on the dashboard.
|
||||
$action = component_callback(
|
||||
'mod_' . $event->get_course_module()->get('modname'),
|
||||
$event->get_component(),
|
||||
'core_calendar_provide_event_action',
|
||||
[
|
||||
$legacyevent,
|
||||
@ -322,7 +321,7 @@ class container {
|
||||
public static function apply_component_is_event_visible(event_interface $event) {
|
||||
$mapper = self::$eventmapper;
|
||||
$eventvisible = null;
|
||||
if ($event->get_course_module()) {
|
||||
if ($event->get_component()) {
|
||||
$requestinguserid = self::get_requesting_user();
|
||||
$legacyevent = $mapper->from_event_to_legacy_event($event);
|
||||
// We know for a fact that the the requesting user might be different from the logged in user,
|
||||
@ -331,9 +330,8 @@ class container {
|
||||
$legacyevent->userid = $requestinguserid;
|
||||
}
|
||||
|
||||
// TODO MDL-58866 Only activity modules currently support this callback.
|
||||
$eventvisible = component_callback(
|
||||
'mod_' . $event->get_course_module()->get('modname'),
|
||||
$event->get_component(),
|
||||
'core_calendar_is_event_visible',
|
||||
[
|
||||
$legacyevent,
|
||||
|
@ -125,4 +125,12 @@ class action_event implements action_event_interface {
|
||||
public function get_action() {
|
||||
return $this->action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event component
|
||||
* @return string
|
||||
*/
|
||||
public function get_component() {
|
||||
return $this->event->get_component();
|
||||
}
|
||||
}
|
||||
|
@ -102,6 +102,11 @@ class event implements event_interface {
|
||||
*/
|
||||
protected $visible;
|
||||
|
||||
/**
|
||||
* @var string $component
|
||||
*/
|
||||
protected $component;
|
||||
|
||||
/**
|
||||
* @var proxy_interface $subscription Subscription for this event.
|
||||
*/
|
||||
@ -124,6 +129,7 @@ class event implements event_interface {
|
||||
* @param bool $visible The event's visibility. True for visible, false for invisible.
|
||||
* @param proxy_interface $subscription The event's subscription.
|
||||
* @param string $location The event's location.
|
||||
* @param string $component The event's component.
|
||||
*/
|
||||
public function __construct(
|
||||
$id,
|
||||
@ -139,7 +145,8 @@ class event implements event_interface {
|
||||
times_interface $times,
|
||||
$visible,
|
||||
proxy_interface $subscription = null,
|
||||
$location = null
|
||||
$location = null,
|
||||
$component = null
|
||||
) {
|
||||
$this->id = $id;
|
||||
$this->name = $name;
|
||||
@ -155,6 +162,7 @@ class event implements event_interface {
|
||||
$this->times = $times;
|
||||
$this->visible = $visible;
|
||||
$this->subscription = $subscription;
|
||||
$this->component = $component;
|
||||
}
|
||||
|
||||
public function get_id() {
|
||||
@ -212,4 +220,12 @@ class event implements event_interface {
|
||||
public function is_visible() {
|
||||
return $this->visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolved event component (frankenstyle name of activity module or the component)
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_component() {
|
||||
return $this->get_course_module() ? 'mod_' . $this->get_course_module()->get('modname') : $this->component;
|
||||
}
|
||||
}
|
||||
|
@ -133,4 +133,10 @@ interface event_interface {
|
||||
* @return bool true if the event is visible, false otherwise
|
||||
*/
|
||||
public function is_visible();
|
||||
|
||||
/**
|
||||
* Resolved event component (frankenstyle name of activity module or the component)
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_component();
|
||||
}
|
||||
|
@ -133,6 +133,7 @@ abstract class event_abstract_factory implements event_factory_interface {
|
||||
$user = null;
|
||||
$module = null;
|
||||
$subscription = null;
|
||||
$component = null;
|
||||
|
||||
if ($dbrow->modulename && $dbrow->instance) {
|
||||
$module = new cm_info_proxy($dbrow->modulename, $dbrow->instance, $dbrow->courseid);
|
||||
@ -171,6 +172,10 @@ abstract class event_abstract_factory implements event_factory_interface {
|
||||
$repeatcollection = null;
|
||||
}
|
||||
|
||||
if (!empty($dbrow->component)) {
|
||||
$component = $dbrow->component;
|
||||
}
|
||||
|
||||
$event = new event(
|
||||
$dbrow->id,
|
||||
$dbrow->name,
|
||||
@ -190,7 +195,8 @@ abstract class event_abstract_factory implements event_factory_interface {
|
||||
),
|
||||
!empty($dbrow->visible),
|
||||
$subscription,
|
||||
$dbrow->location
|
||||
$dbrow->location,
|
||||
$component
|
||||
);
|
||||
|
||||
$isactionevent = !empty($dbrow->type) && $dbrow->type == CALENDAR_EVENT_TYPE_ACTION;
|
||||
|
@ -75,6 +75,7 @@ class event_mapper implements event_mapper_interface {
|
||||
'groupid' => $coalesce('groupid'),
|
||||
'userid' => $coalesce('userid'),
|
||||
'repeatid' => $coalesce('repeatid'),
|
||||
'component' => $coalesce('component'),
|
||||
'modulename' => $coalesce('modulename'),
|
||||
'instance' => $coalesce('instance'),
|
||||
'eventtype' => $coalesce('eventtype'),
|
||||
@ -98,6 +99,7 @@ class event_mapper implements event_mapper_interface {
|
||||
$properties->categoryid = empty($properties->categoryid) ? 0 : $properties->categoryid;
|
||||
$properties->groupid = empty($properties->groupid) ? 0 : $properties->groupid;
|
||||
$properties->userid = empty($properties->userid) ? 0 : $properties->userid;
|
||||
$properties->component = empty($properties->component) ? 0 : $properties->component;
|
||||
$properties->modulename = empty($properties->modulename) ? 0 : $properties->modulename;
|
||||
$properties->instance = empty($properties->instance) ? 0 : $properties->instance;
|
||||
$properties->repeatid = empty($properties->repeatid) ? 0 : $properties->repeatid;
|
||||
@ -127,6 +129,7 @@ class event_mapper implements event_mapper_interface {
|
||||
'groupid' => $event->get_group() ? $event->get_group()->get('id') : null,
|
||||
'userid' => $event->get_user() ? $event->get_user()->get('id') : null,
|
||||
'repeatid' => $event->get_repeats() ? $event->get_repeats()->get_id() : null,
|
||||
'component' => $event->get_component(),
|
||||
'modulename' => $event->get_course_module() ? $event->get_course_module()->get('modname') : null,
|
||||
'instance' => $event->get_course_module() ? $event->get_course_module()->get('instance') : null,
|
||||
'eventtype' => $event->get_type(),
|
||||
|
@ -797,20 +797,21 @@ class core_calendar_external extends external_api {
|
||||
self::validate_context($context);
|
||||
$warnings = array();
|
||||
|
||||
$legacyevent = calendar_event::load($eventid);
|
||||
// Must check we can see this event.
|
||||
if (!calendar_view_event_allowed($legacyevent)) {
|
||||
$eventvault = event_container::get_event_vault();
|
||||
if ($event = $eventvault->get_event_by_id($eventid)) {
|
||||
$mapper = event_container::get_event_mapper();
|
||||
if (!calendar_view_event_allowed($mapper->from_event_to_legacy_event($event))) {
|
||||
$event = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$event) {
|
||||
// We can't return a warning in this case because the event is not optional.
|
||||
// We don't know the context for the event and it's not worth loading it.
|
||||
$syscontext = context_system::instance();
|
||||
throw new \required_capability_exception($syscontext, 'moodle/course:view', 'nopermission', '');
|
||||
}
|
||||
|
||||
$legacyevent->count_repeats();
|
||||
|
||||
$eventmapper = event_container::get_event_mapper();
|
||||
$event = $eventmapper->from_legacy_event_to_event($legacyevent);
|
||||
|
||||
$cache = new events_related_objects_cache([$event]);
|
||||
$relatedobjects = [
|
||||
'context' => $cache->get_context($event),
|
||||
|
@ -172,6 +172,7 @@ define('CALENDAR_EVENT_TYPE_ACTION', 1);
|
||||
* @property int $userid The user the event is associated with (0 if none)
|
||||
* @property int $repeatid If this is a repeated event this will be set to the
|
||||
* id of the original
|
||||
* @property string $component If created by a plugin/component (other than module), the full frankenstyle name of a component
|
||||
* @property string $modulename If added by a module this will be the module name
|
||||
* @property int $instance If added by a module this will be the module instance
|
||||
* @property string $eventtype The event type
|
||||
@ -257,6 +258,10 @@ class calendar_event {
|
||||
$data->format = editors_get_preferred_format();
|
||||
}
|
||||
|
||||
if (empty($data->component)) {
|
||||
$data->component = null;
|
||||
}
|
||||
|
||||
$this->properties = $data;
|
||||
}
|
||||
|
||||
@ -337,6 +342,7 @@ class calendar_event {
|
||||
$context = \context_user::instance($this->properties->userid);
|
||||
} else if (isset($this->properties->userid) && $this->properties->userid > 0
|
||||
&& $this->properties->userid != $USER->id &&
|
||||
!empty($this->properties->modulename) &&
|
||||
isset($this->properties->instance) && $this->properties->instance > 0) {
|
||||
$cm = get_coursemodule_from_instance($this->properties->modulename, $this->properties->instance, 0,
|
||||
false, MUST_EXIST);
|
||||
@ -1523,10 +1529,13 @@ function calendar_get_group_cached($groupid) {
|
||||
/**
|
||||
* Add calendar event metadata
|
||||
*
|
||||
* @deprecated since 3.9
|
||||
*
|
||||
* @param stdClass $event event info
|
||||
* @return stdClass $event metadata
|
||||
*/
|
||||
function calendar_add_event_metadata($event) {
|
||||
debugging('This function is no longer used', DEBUG_DEVELOPER);
|
||||
global $CFG, $OUTPUT;
|
||||
|
||||
// Support multilang in event->name.
|
||||
@ -2276,6 +2285,10 @@ function calendar_edit_event_allowed($event, $manualedit = false) {
|
||||
return has_capability('moodle/course:manageactivities', $context);
|
||||
}
|
||||
|
||||
if ($manualedit && !empty($event->component)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// You cannot edit URL based calendar subscription events presently.
|
||||
if (!empty($event->subscriptionid)) {
|
||||
if (!empty($event->subscription->url)) {
|
||||
@ -2324,8 +2337,8 @@ function calendar_edit_event_allowed($event, $manualedit = false) {
|
||||
* @return bool Whether the user has permission to delete the event or not.
|
||||
*/
|
||||
function calendar_delete_event_allowed($event) {
|
||||
// Only allow delete if you have capabilities and it is not an module event.
|
||||
return (calendar_edit_event_allowed($event) && empty($event->modulename));
|
||||
// Only allow delete if you have capabilities and it is not an module or component event.
|
||||
return (calendar_edit_event_allowed($event) && empty($event->modulename) && empty($event->component));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,12 +135,15 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
/**
|
||||
* Displays an event
|
||||
*
|
||||
* @deprecated since 3.9
|
||||
*
|
||||
* @param calendar_event $event
|
||||
* @param bool $showactions
|
||||
* @return string
|
||||
*/
|
||||
public function event(calendar_event $event, $showactions=true) {
|
||||
global $CFG;
|
||||
debugging('This function is no longer used', DEBUG_DEVELOPER);
|
||||
|
||||
$event = calendar_add_event_metadata($event);
|
||||
$context = $event->context;
|
||||
|
@ -34,6 +34,7 @@
|
||||
{
|
||||
"formattedtime": "Wednesday, 17 April, 9:27 AM",
|
||||
"normalisedeventtype": "Group",
|
||||
"normalisedeventtypetext": "Group event",
|
||||
"description": "An random event description",
|
||||
"location": "Moodle HQ",
|
||||
"isactionevent": "true",
|
||||
@ -77,29 +78,19 @@
|
||||
<div class="location-content col-11">{{{.}}}</div>
|
||||
</div>
|
||||
{{/location}}
|
||||
{{#isactionevent}}
|
||||
<div class="row mt-1">
|
||||
<div class="col-1">{{#pix}} i/courseevent, core, {{#str}} course {{/str}} {{/pix}}</div>
|
||||
<div class="col-11"><a href="{{course.viewurl}}">{{{course.fullname}}}</a></div>
|
||||
</div>
|
||||
{{/isactionevent}}
|
||||
{{#iscategoryevent}}
|
||||
<div class="row mt-1">
|
||||
<div class="col-1">{{#pix}} i/categoryevent, core, {{#str}} category {{/str}} {{/pix}}</div>
|
||||
<div class="col-11">{{{category.nestedname}}}</div>
|
||||
</div>
|
||||
{{/iscategoryevent}}
|
||||
{{#iscourseevent}}
|
||||
{{#course.viewurl}}
|
||||
<div class="row mt-1">
|
||||
<div class="col-1">{{#pix}} i/courseevent, core, {{#str}} course {{/str}} {{/pix}}</div>
|
||||
<div class="col-11"><a href="{{url}}">{{{course.fullname}}}</a></div>
|
||||
<div class="col-11"><a href="{{course.viewurl}}">{{{course.fullname}}}</a></div>
|
||||
</div>
|
||||
{{/iscourseevent}}
|
||||
{{/course.viewurl}}
|
||||
{{#groupname}}
|
||||
<div class="row mt-1">
|
||||
<div class="col-1">{{#pix}} i/courseevent, core, {{#str}} course {{/str}} {{/pix}}</div>
|
||||
<div class="col-11"><a href="{{url}}">{{{course.fullname}}}</a></div>
|
||||
</div>
|
||||
<div class="row mt-1">
|
||||
<div class="col-1">{{#pix}} i/groupevent, core, {{#str}} group {{/str}} {{/pix}}</div>
|
||||
<div class="col-11">{{{groupname}}}</div>
|
||||
|
@ -80,10 +80,17 @@
|
||||
<div class="description card-body">
|
||||
{{> core_calendar/event_details }}
|
||||
</div>
|
||||
{{#isactionevent}}
|
||||
{{#action.actionable}}
|
||||
<div class="card-footer text-right bg-transparent">
|
||||
<a href="{{action.url}}" class="card-link">{{{action.name}}}</a>
|
||||
</div>
|
||||
{{/action.actionable}}
|
||||
{{^action.actionable}}
|
||||
{{#isactionevent}}
|
||||
<div class="card-footer text-right bg-transparent">
|
||||
<a href="{{url}}" class="card-link">{{#str}} gotoactivity, core_calendar {{/str}}</a>
|
||||
</div>
|
||||
{{/isactionevent}}
|
||||
{{/isactionevent}}
|
||||
{{/action.actionable}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"title": "Assignment due 1",
|
||||
"title": "Assignment due 1"
|
||||
}
|
||||
}}
|
||||
{{< core/modal }}
|
||||
@ -29,9 +29,15 @@
|
||||
{{#candelete}}
|
||||
<button type="button" class="btn btn-secondary" data-action="delete">{{#str}} delete {{/str}}</button>
|
||||
{{/candelete}}
|
||||
{{#isactionevent}}
|
||||
{{#action.actionable}}
|
||||
<a href="{{action.url}}">{{{action.name}}}</a>
|
||||
{{/action.actionable}}
|
||||
{{^action.actionable}}
|
||||
{{#isactionevent}}
|
||||
<a href="{{url}}">{{#str}} gotoactivity, core_calendar {{/str}}</a>
|
||||
{{/isactionevent}}
|
||||
{{/isactionevent}}
|
||||
{{/action.actionable}}
|
||||
|
||||
{{^isactionevent}}
|
||||
{{#canedit}}
|
||||
<button type="button" class="btn btn-primary" data-action="edit">{{#str}} edit {{/str}}</button>
|
||||
|
@ -156,6 +156,14 @@ class core_calendar_action_event_test_event implements event_interface {
|
||||
public function is_visible() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_component() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -255,6 +255,14 @@ class event_mapper_test_action_event implements action_event_interface {
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_component() {
|
||||
return $this->event->get_component();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -374,6 +382,14 @@ class event_mapper_test_event implements event_interface {
|
||||
public function is_visible() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_component() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,16 +59,18 @@ class core_calendar_event_testcase extends advanced_testcase {
|
||||
$constructorparams['times'],
|
||||
$constructorparams['visible'],
|
||||
$constructorparams['subscription'],
|
||||
$constructorparams['location']
|
||||
$constructorparams['location'],
|
||||
$constructorparams['component']
|
||||
);
|
||||
|
||||
foreach ($constructorparams as $name => $value) {
|
||||
if ($name !== 'visible') {
|
||||
if ($name !== 'visible' && $name !== 'component') {
|
||||
$this->assertEquals($event->{'get_' . $name}(), $value);
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertEquals($event->is_visible(), $constructorparams['visible']);
|
||||
$this->assertEquals('mod_' . $event->get_course_module()->get('modname'), $event->get_component());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,7 +78,7 @@ class core_calendar_event_testcase extends advanced_testcase {
|
||||
*/
|
||||
public function getters_testcases() {
|
||||
$lamecallable = function($id) {
|
||||
return (object)['id' => $id];
|
||||
return (object)['id' => $id, 'modname' => 'assign'];
|
||||
};
|
||||
|
||||
return [
|
||||
@ -101,6 +103,7 @@ class core_calendar_event_testcase extends advanced_testcase {
|
||||
'visible' => true,
|
||||
'subscription' => new std_proxy(1, $lamecallable),
|
||||
'location' => 'Test',
|
||||
'component' => null
|
||||
]
|
||||
],
|
||||
];
|
||||
|
@ -137,7 +137,8 @@ class action_event_test_factory implements event_factory_interface {
|
||||
),
|
||||
!empty($record->visible),
|
||||
$subscription,
|
||||
$record->location
|
||||
$record->location,
|
||||
!empty($record->component) ? $record->component : null
|
||||
);
|
||||
|
||||
$action = new action(
|
||||
|
@ -205,7 +205,8 @@ class core_calendar_repeat_event_collection_event_test_factory implements event_
|
||||
),
|
||||
!empty($dbrow->visible),
|
||||
new std_proxy($dbrow->subscriptionid, $identity),
|
||||
$dbrow->location
|
||||
$dbrow->location,
|
||||
$dbrow->component
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,11 @@
|
||||
This files describes API changes in /calendar/* ,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 3.9 ===
|
||||
* Plugins can now create their own calendar events, both standard and action ones. To do it they need to specify
|
||||
$event->component when creating an event. Component events can not be edited or deleted manually.
|
||||
See https://docs.moodle.org/dev/Calendar_API#Component_events
|
||||
|
||||
=== 3.8 ===
|
||||
* The following functions have been finally deprecated and can not be used anymore:
|
||||
* calendar_wday_name()
|
||||
|
@ -206,6 +206,7 @@ function uninstall_plugin($type, $name) {
|
||||
|
||||
// delete calendar events
|
||||
$DB->delete_records('event', array('modulename' => $pluginname));
|
||||
$DB->delete_records('event', ['component' => $component]);
|
||||
|
||||
// Delete scheduled tasks.
|
||||
$DB->delete_records('task_scheduled', array('component' => $component));
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="lib/db" VERSION="20200415" COMMENT="XMLDB file for core Moodle tables"
|
||||
<XMLDB PATH="lib/db" VERSION="20200504" COMMENT="XMLDB file for core Moodle tables"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
@ -433,6 +433,7 @@
|
||||
<FIELD NAME="groupid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="repeatid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="component" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false" COMMENT="Component that created this event, if specified, only component itself can edit and delete it"/>
|
||||
<FIELD NAME="modulename" TYPE="char" LENGTH="20" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="instance" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="type" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
@ -463,6 +464,7 @@
|
||||
<INDEX NAME="groupid-courseid-categoryid-visible-userid" UNIQUE="false" FIELDS="groupid, courseid, categoryid, visible, userid" COMMENT="used for calendar view"/>
|
||||
<INDEX NAME="eventtype" UNIQUE="false" FIELDS="eventtype"/>
|
||||
<INDEX NAME="modulename-instance" UNIQUE="false" FIELDS="modulename, instance"/>
|
||||
<INDEX NAME="component" UNIQUE="false" FIELDS="component, eventtype, instance"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="cache_filters" COMMENT="For keeping information about cached data">
|
||||
|
@ -2314,5 +2314,29 @@ function xmldb_main_upgrade($oldversion) {
|
||||
|
||||
upgrade_main_savepoint(true, 2020042800.01);
|
||||
}
|
||||
|
||||
if ($oldversion < 2020051900.01) {
|
||||
// Define field component to be added to event.
|
||||
$table = new xmldb_table('event');
|
||||
$field = new xmldb_field('component', XMLDB_TYPE_CHAR, '100', null, null, null, null, 'repeatid');
|
||||
|
||||
// Conditionally launch add field component.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Define index component (not unique) to be added to event.
|
||||
$table = new xmldb_table('event');
|
||||
$index = new xmldb_index('component', XMLDB_INDEX_NOTUNIQUE, ['component', 'eventtype', 'instance']);
|
||||
|
||||
// Conditionally launch add index component.
|
||||
if (!$dbman->index_exists($table, $index)) {
|
||||
$dbman->add_index($table, $index);
|
||||
}
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2020051900.01);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2020051900.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2020051900.01; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '3.9dev+ (Build: 20200519)'; // Human-friendly version name
|
||||
|
Loading…
x
Reference in New Issue
Block a user