diff --git a/calendar/amd/build/calendar.min.js b/calendar/amd/build/calendar.min.js index fab055da74b..f21a625b11c 100644 --- a/calendar/amd/build/calendar.min.js +++ b/calendar/amd/build/calendar.min.js @@ -1 +1 @@ -define(["jquery","core/ajax","core/str","core/templates","core/notification","core/custom_interaction_events","core/modal_events","core/modal_factory","core_calendar/modal_event_form","core_calendar/summary_modal","core_calendar/repository","core_calendar/events"],function(a,b,c,d,e,f,g,h,i,j,k,l){var m={ROOT:"[data-region='calendar']",EVENT_LINK:"[data-action='view-event']",NEW_EVENT_BUTTON:"[data-action='new-event-button']"},n=function(a){var b="type"+a;return c.get_string(b,"core_calendar").then(function(a){return a})},o=function(a){return c.get_string("subsource","core_calendar",a).then(function(b){return a.url?''+b+"":b})},p=function(b){k.getEventById(b).then(function(c){if(!c.event)throw new Error("Error encountered while trying to fetch calendar event with ID: "+b);var d=c.event,e=n(d.eventtype);if(d.displayeventsource){d.subscription=JSON.parse(d.subscription);var f={url:d.subscription.url,name:d.subscription.name},g=o(f);return a.when(e,g).then(function(a,b){return d.eventtype=a,d.source=b,d})}return e.then(function(a){return d.eventtype=a,d})}).then(function(a){var b={title:a.name,type:j.TYPE,body:d.render("core_calendar/event_summary_body",a)};return a.caneditevent||(b.footer=""),h.create(b)}).done(function(a){a.getRoot().on(g.hidden,function(){a.destroy()}),a.show()}).fail(e.exception)},q=function(a){var b=a.find(m.NEW_EVENT_BUTTON),c=b.attr("data-context-id");return h.create({type:i.TYPE,large:!0,templateContext:{contextid:c}},b)},r=function(b,c){var d=a("body");d.on(l.created,function(){window.location.reload()}),d.on(l.deleted,function(){window.location.reload()}),d.on(l.updated,function(){window.location.reload()}),c.then(function(a){d.on(l.editEvent,function(b,c){a.setEventId(c),a.show()})})},s=function(){var b=a(m.ROOT);a(m.EVENT_LINK).click(function(b){b.preventDefault();var c=a(this).attr("data-event-id");p(c)});var c=q(b);r(b,c)};return{init:function(){s()}}}); \ No newline at end of file +define(["jquery","core/ajax","core/str","core/templates","core/notification","core/custom_interaction_events","core/modal_events","core/modal_factory","core_calendar/modal_event_form","core_calendar/summary_modal","core_calendar/repository","core_calendar/events"],function(a,b,c,d,e,f,g,h,i,j,k,l){var m={ROOT:"[data-region='calendar']",EVENT_LINK:"[data-action='view-event']",NEW_EVENT_BUTTON:"[data-action='new-event-button']"},n=function(a){var b="type"+a;return c.get_string(b,"core_calendar").then(function(a){return a})},o=function(a){return c.get_string("subsource","core_calendar",a).then(function(b){return a.url?''+b+"":b})},p=function(b){k.getEventById(b).then(function(c){if(!c.event)throw new Error("Error encountered while trying to fetch calendar event with ID: "+b);var d=c.event,e=n(d.eventtype);if(d.displayeventsource){d.subscription=JSON.parse(d.subscription);var f={url:d.subscription.url,name:d.subscription.name},g=o(f);return a.when(e,g).then(function(a,b){return d.eventtype=a,d.source=b,d})}return e.then(function(a){return d.eventtype=a,d})}).then(function(a){var b={title:a.name,type:j.TYPE,body:d.render("core_calendar/event_summary_body",a),templateContext:{canedit:a.canedit,candelete:a.candelete}};return h.create(b)}).done(function(a){a.getRoot().on(g.hidden,function(){a.destroy()}),a.show()}).fail(e.exception)},q=function(a){var b=a.find(m.NEW_EVENT_BUTTON),c=b.attr("data-context-id");return h.create({type:i.TYPE,large:!0,templateContext:{contextid:c}},b)},r=function(b,c){var d=a("body");d.on(l.created,function(){window.location.reload()}),d.on(l.deleted,function(){window.location.reload()}),d.on(l.updated,function(){window.location.reload()}),d.on(l.editActionEvent,function(a,b){window.location.assign(b)}),c.then(function(a){d.on(l.editEvent,function(b,c){a.setEventId(c),a.show()})})},s=function(){var b=a(m.ROOT);a(m.EVENT_LINK).click(function(b){b.preventDefault();var c=a(this).attr("data-event-id");p(c)});var c=q(b);r(b,c)};return{init:function(){s()}}}); \ No newline at end of file diff --git a/calendar/amd/build/events.min.js b/calendar/amd/build/events.min.js index 938b80413b7..0c310d9f996 100644 --- a/calendar/amd/build/events.min.js +++ b/calendar/amd/build/events.min.js @@ -1 +1 @@ -define([],function(){return{created:"calendar-events:created",deleted:"calendar-events:deleted",updated:"calendar-events:updated",editEvent:"calendar-events:edit_event"}}); \ No newline at end of file +define([],function(){return{created:"calendar-events:created",deleted:"calendar-events:deleted",updated:"calendar-events:updated",editEvent:"calendar-events:edit_event",editActionEvent:"calendar-events:edit_action_event"}}); \ No newline at end of file diff --git a/calendar/amd/build/summary_modal.min.js b/calendar/amd/build/summary_modal.min.js index 9c0bb22ee4c..358bad067ad 100644 --- a/calendar/amd/build/summary_modal.min.js +++ b/calendar/amd/build/summary_modal.min.js @@ -1 +1 @@ -define(["jquery","core/str","core/notification","core/custom_interaction_events","core/modal","core/modal_registry","core/modal_factory","core/modal_events","core_calendar/repository","core_calendar/events"],function(a,b,c,d,e,f,g,h,i,j){var k=!1,l={ROOT:"[data-region='summary-modal-container']",EDIT_BUTTON:'[data-action="edit"]',DELETE_BUTTON:'[data-action="delete"]'},m=function(a){e.call(this,a),this.getEditButton().length||c.exception({message:"No edit button found"}),this.getDeleteButton().length||c.exception({message:"No delete button found"})};return m.TYPE="core_calendar-event_summary",m.prototype=Object.create(e.prototype),m.prototype.constructor=m,m.prototype.getEditButton=function(){return"undefined"==typeof this.editButton&&(this.editButton=this.getFooter().find(l.EDIT_BUTTON)),this.editButton},m.prototype.getDeleteButton=function(){return"undefined"==typeof this.deleteButton&&(this.deleteButton=this.getFooter().find(l.DELETE_BUTTON)),this.deleteButton},m.prototype.getEventId=function(){return this.getBody().find(l.ROOT).attr("data-event-id")},m.prototype.registerEventListeners=function(){e.prototype.registerEventListeners.call(this);var f=g.create({type:g.types.CONFIRM},this.getDeleteButton()).then(function(b){return b.getRoot().on(h.yes,function(){var b=this.getEventId();i.deleteEvent(b).then(function(){a("body").trigger(j.deleted,[b]),this.hide()}.bind(this))["catch"](c.exception)}.bind(this)),b}.bind(this));this.getRoot().on(h.bodyRendered,function(){var a=this.getBody().find(l.ROOT).attr("data-event-title");f.then(function(c){c.setBody(b.get_string("confirmeventdelete","core_calendar",a))})}.bind(this)),d.define(this.getEditButton(),[d.events.activate]),this.getEditButton().on(d.events.activate,function(b,c){a("body").trigger(j.editEvent,[this.getEventId()]),this.hide(),b.preventDefault(),b.stopPropagation(),c.originalEvent.preventDefault(),c.originalEvent.stopPropagation()}.bind(this))},k||(f.register(m.TYPE,m,"core_calendar/event_summary_modal"),k=!0),m}); \ No newline at end of file +define(["jquery","core/str","core/notification","core/custom_interaction_events","core/modal","core/modal_registry","core/modal_factory","core/modal_events","core_calendar/repository","core_calendar/events"],function(a,b,c,d,e,f,g,h,i,j){var k=!1,l={ROOT:"[data-region='summary-modal-container']",EDIT_BUTTON:'[data-action="edit"]',DELETE_BUTTON:'[data-action="delete"]'},m=function(a){e.call(this,a)};return m.TYPE="core_calendar-event_summary",m.prototype=Object.create(e.prototype),m.prototype.constructor=m,m.prototype.getEditButton=function(){return"undefined"==typeof this.editButton&&(this.editButton=this.getFooter().find(l.EDIT_BUTTON)),this.editButton},m.prototype.getDeleteButton=function(){return"undefined"==typeof this.deleteButton&&(this.deleteButton=this.getFooter().find(l.DELETE_BUTTON)),this.deleteButton},m.prototype.getEventId=function(){return this.getBody().find(l.ROOT).attr("data-event-id")},m.prototype.getEditUrl=function(){return this.getBody().find(l.ROOT).attr("data-edit-url")},m.prototype.isActionEvent=function(){return"true"==this.getBody().find(l.ROOT).attr("data-action-event")},m.prototype.registerEventListeners=function(){e.prototype.registerEventListeners.call(this);var f=g.create({type:g.types.CONFIRM},this.getDeleteButton()).then(function(b){return b.getRoot().on(h.yes,function(){var b=this.getEventId();i.deleteEvent(b).then(function(){a("body").trigger(j.deleted,[b]),this.hide()}.bind(this))["catch"](c.exception)}.bind(this)),b}.bind(this));this.getRoot().on(h.bodyRendered,function(){var a=this.getBody().find(l.ROOT).attr("data-event-title");f.then(function(c){c.setBody(b.get_string("confirmeventdelete","core_calendar",a))})}.bind(this)),d.define(this.getEditButton(),[d.events.activate]),this.getEditButton().on(d.events.activate,function(b,c){this.isActionEvent()?a("body").trigger(j.editActionEvent,[this.getEditUrl()]):a("body").trigger(j.editEvent,[this.getEventId()]),this.hide(),b.preventDefault(),b.stopPropagation(),c.originalEvent.preventDefault(),c.originalEvent.stopPropagation()}.bind(this))},k||(f.register(m.TYPE,m,"core_calendar/event_summary_modal"),k=!0),m}); \ No newline at end of file diff --git a/calendar/amd/src/calendar.js b/calendar/amd/src/calendar.js index 1843984823e..a08f1c3c0cc 100644 --- a/calendar/amd/src/calendar.js +++ b/calendar/amd/src/calendar.js @@ -130,11 +130,13 @@ define([ var modalParams = { title: eventData.name, type: SummaryModal.TYPE, - body: Templates.render('core_calendar/event_summary_body', eventData) + body: Templates.render('core_calendar/event_summary_body', eventData), + templateContext: { + canedit: eventData.canedit, + candelete: eventData.candelete + } }; - if (!eventData.caneditevent) { - modalParams.footer = ''; - } + // Create the modal. return ModalFactory.create(modalParams); @@ -196,6 +198,10 @@ define([ body.on(CalendarEvents.updated, function() { window.location.reload(); }); + body.on(CalendarEvents.editActionEvent, function(e, url) { + // Action events needs to be edit directly on the course module. + window.location.assign(url); + }); eventFormModalPromise.then(function(modal) { // When something within the calendar tells us the user wants diff --git a/calendar/amd/src/events.js b/calendar/amd/src/events.js index 80ec8cacb41..47aac12ec26 100644 --- a/calendar/amd/src/events.js +++ b/calendar/amd/src/events.js @@ -27,6 +27,7 @@ define([], function() { created: 'calendar-events:created', deleted: 'calendar-events:deleted', updated: 'calendar-events:updated', - editEvent: 'calendar-events:edit_event' + editEvent: 'calendar-events:edit_event', + editActionEvent: 'calendar-events:edit_action_event' }; }); diff --git a/calendar/amd/src/summary_modal.js b/calendar/amd/src/summary_modal.js index b758f45f3dd..4a668bea679 100644 --- a/calendar/amd/src/summary_modal.js +++ b/calendar/amd/src/summary_modal.js @@ -41,14 +41,6 @@ define(['jquery', 'core/str', 'core/notification', 'core/custom_interaction_even */ var ModalEventSummary = function(root) { Modal.call(this, root); - - if (!this.getEditButton().length) { - Notification.exception({message: 'No edit button found'}); - } - - if (!this.getDeleteButton().length) { - Notification.exception({message: 'No delete button found'}); - } }; ModalEventSummary.TYPE = 'core_calendar-event_summary'; @@ -97,6 +89,26 @@ define(['jquery', 'core/str', 'core/notification', 'core/custom_interaction_even return this.getBody().find(SELECTORS.ROOT).attr('data-event-id'); }; + /** + * Get the url for the event being shown in this modal. + * + * @method getEventUrl + * @return {String} + */ + ModalEventSummary.prototype.getEditUrl = function() { + return this.getBody().find(SELECTORS.ROOT).attr('data-edit-url'); + }; + + /** + * Is this an action event. + * + * @method getEventUrl + * @return {String} + */ + ModalEventSummary.prototype.isActionEvent = function() { + return (this.getBody().find(SELECTORS.ROOT).attr('data-action-event') == 'true'); + }; + /** * Set up all of the event handling for the modal. * @@ -140,9 +152,16 @@ define(['jquery', 'core/str', 'core/notification', 'core/custom_interaction_even ]); this.getEditButton().on(CustomEvents.events.activate, function(e, data) { - // When the edit button is clicked we fire an event for the calendar UI to handle. - // We don't care how the UI chooses to handle it. - $('body').trigger(CalendarEvents.editEvent, [this.getEventId()]); + + if (this.isActionEvent()) { + // Action events cannot be edited on the event form and must be redirected to the module UI. + $('body').trigger(CalendarEvents.editActionEvent, [this.getEditUrl()]); + } else { + // When the edit button is clicked we fire an event for the calendar UI to handle. + // We don't care how the UI chooses to handle it. + $('body').trigger(CalendarEvents.editEvent, [this.getEventId()]); + } + // There is nothing else for us to do so let's hide. this.hide(); diff --git a/calendar/classes/external/event_exporter.php b/calendar/classes/external/event_exporter.php index ec2d938dc4a..dd189b71da3 100644 --- a/calendar/classes/external/event_exporter.php +++ b/calendar/classes/external/event_exporter.php @@ -26,9 +26,12 @@ namespace core_calendar\external; defined('MOODLE_INTERNAL') || die(); +require_once($CFG->dirroot . "/calendar/lib.php"); + use \core\external\exporter; use \core_calendar\local\event\entities\event_interface; use \core_calendar\local\event\entities\action_event_interface; +use \core_calendar\local\event\container; use \core_course\external\course_summary_exporter; use \renderer_base; @@ -154,6 +157,10 @@ class event_exporter extends exporter { protected static function define_other_properties() { return [ 'url' => ['type' => PARAM_URL], + 'editurl' => [ + 'type' => PARAM_URL, + 'optional' => true + ], 'icon' => [ 'type' => event_icon_exporter::read_properties_definition(), ], @@ -164,7 +171,17 @@ class event_exporter extends exporter { 'course' => [ 'type' => course_summary_exporter::read_properties_definition(), 'optional' => true, - ] + ], + 'canedit' => ['type' => PARAM_BOOL], + 'displayeventsource' => ['type' => PARAM_BOOL], + 'subscription' => [ + 'type' => PARAM_RAW, + 'optional' => true, + 'default' => null, + 'null' => NULL_ALLOWED + ], + 'isactionevent' => ['type' => PARAM_BOOL], + 'candelete' => ['type' => PARAM_BOOL] ]; } @@ -177,11 +194,21 @@ class event_exporter extends exporter { protected function get_other_values(renderer_base $output) { $values = []; $event = $this->event; + $legacyevent = container::get_event_mapper()->from_event_to_legacy_event($event); + $context = $this->related['context']; + $values['isactionevent'] = false; if ($moduleproxy = $event->get_course_module()) { $modulename = $moduleproxy->get('modname'); $moduleid = $moduleproxy->get('id'); $url = new \moodle_url(sprintf('/mod/%s/view.php', $modulename), ['id' => $moduleid]); + + $values['isactionevent'] = true; + + // Build edit event url for action events. + $params = array('update' => $moduleid, 'return' => true, 'sesskey' => sesskey()); + $editurl = new \moodle_url('/course/mod.php', $params); + $values['editurl'] = $editurl->out(false); } else { // TODO MDL-58866 We do not have any way to find urls for events outside of course modules. global $CFG; @@ -208,6 +235,24 @@ class event_exporter extends exporter { $values['course'] = $coursesummaryexporter->export($output); } + $values['canedit'] = calendar_edit_event_allowed($legacyevent); + $values['candelete'] = (!$values['isactionevent'] && $values['canedit']); + + // Handle event subscription. + $values['subscription'] = null; + $values['displayeventsource'] = false; + if (!empty($legacyevent->subscriptionid)) { + $subscription = calendar_get_subscription($legacyevent->subscriptionid); + if (!empty($subscription) && $CFG->calendar_showicalsource) { + $values['displayeventsource'] = true; + $subscriptiondata = new \stdClass(); + if (!empty($subscription->url)) { + $subscriptiondata->url = $subscription->url; + } + $subscriptiondata->name = $subscription->name; + $values['subscription'] = json_encode($subscriptiondata); + } + } return $values; } diff --git a/calendar/externallib.php b/calendar/externallib.php index 037f33221d8..129bf60183f 100644 --- a/calendar/externallib.php +++ b/calendar/externallib.php @@ -712,37 +712,32 @@ class core_calendar_external extends external_api { * @return array Array of event details */ public static function get_calendar_event_by_id($eventid) { - global $CFG; + global $CFG, $PAGE, $USER; require_once($CFG->dirroot."/calendar/lib.php"); - // Parameter validation. $params = ['eventid' => $eventid]; - $params = self::validate_parameters(self::get_calendar_event_by_id_parameters(), $params); + self::validate_parameters(self::get_calendar_event_by_id_parameters(), $params); + $context = \context_user::instance($USER->id); + self::validate_context($context); $warnings = array(); - // We need to get events asked for eventids. - $event = calendar_get_events_by_id([$eventid]); - $eventobj = calendar_event::load($eventid); - list($event[$eventid]->description, $event[$eventid]->format) = $eventobj->format_external_text(); - $event[$eventid]->caneditevent = calendar_edit_event_allowed($eventobj); + $legacyevent = calendar_event::load($eventid); + $legacyevent->count_repeats(); - $event[$eventid]->subscription = null; - $event[$eventid]->displayeventsource = false; - if (!empty($event[$eventid]->subscriptionid)) { - $subscription = calendar_get_subscription($event[$eventid]->subscriptionid); - if (!empty($subscription) && $CFG->calendar_showicalsource) { - $event[$eventid]->displayeventsource = true; - $subscriptiondata = new stdClass(); - if (!empty($subscription->url)) { - $subscriptiondata->url = $subscription->url; - } - $subscriptiondata->name = $subscription->name; - $event[$eventid]->subscription = json_encode($subscriptiondata); - } - } + $eventmapper = event_container::get_event_mapper(); + $event = $eventmapper->from_legacy_event_to_event($legacyevent); - return array('event' => $event[$eventid], 'warnings' => $warnings); + $cache = new events_related_objects_cache([$event]); + $relatedobjects = [ + 'context' => $cache->get_context($event), + 'course' => $cache->get_course($event), + ]; + + $exporter = new event_exporter($event, $relatedobjects); + $renderer = $PAGE->get_renderer('core_calendar'); + + return array('event' => $exporter->export($renderer), 'warnings' => $warnings); } /** @@ -751,35 +746,10 @@ class core_calendar_external extends external_api { * @return external_description */ public static function get_calendar_event_by_id_returns() { + $eventstructure = event_exporter::get_read_structure(); return new external_single_structure(array( - 'event' => new external_single_structure( - array( - 'id' => new external_value(PARAM_INT, 'event id'), - 'name' => new external_value(PARAM_TEXT, 'event name'), - 'description' => new external_value(PARAM_RAW, 'Description', VALUE_OPTIONAL, null, NULL_ALLOWED), - 'format' => new external_format_value('description'), - 'courseid' => new external_value(PARAM_INT, 'course id'), - 'groupid' => new external_value(PARAM_INT, 'group id'), - 'userid' => new external_value(PARAM_INT, 'user id'), - 'repeatid' => new external_value(PARAM_INT, 'repeat id'), - 'modulename' => new external_value(PARAM_TEXT, 'module name', VALUE_OPTIONAL, null, NULL_ALLOWED), - 'instance' => new external_value(PARAM_INT, 'instance id'), - 'eventtype' => new external_value(PARAM_TEXT, 'Event type'), - 'timestart' => new external_value(PARAM_INT, 'timestart'), - 'timeduration' => new external_value(PARAM_INT, 'time duration'), - 'visible' => new external_value(PARAM_INT, 'visible'), - 'uuid' => new external_value(PARAM_TEXT, 'unique id of ical events', VALUE_OPTIONAL, null, NULL_NOT_ALLOWED), - 'sequence' => new external_value(PARAM_INT, 'sequence'), - 'timemodified' => new external_value(PARAM_INT, 'time modified'), - 'subscriptionid' => new external_value(PARAM_INT, 'Subscription id', VALUE_OPTIONAL, null, NULL_ALLOWED), - 'subscription' => new external_value(PARAM_RAW, 'Subscription object serialized', VALUE_OPTIONAL, - null, NULL_ALLOWED), - 'caneditevent' => new external_value(PARAM_BOOL, 'Whether the user can edit the event'), - 'displayeventsource' => new external_value(PARAM_BOOL, 'Whether the source should be displayed'), - ), - 'event' - ), + 'event' => $eventstructure, 'warnings' => new external_warnings() ) ); diff --git a/calendar/templates/event_summary_body.mustache b/calendar/templates/event_summary_body.mustache index d054f4f8f13..e5301bd87a0 100644 --- a/calendar/templates/event_summary_body.mustache +++ b/calendar/templates/event_summary_body.mustache @@ -26,7 +26,8 @@ "eventtype": "open" } }} -