Merge branch 'MDL-58550-master' of git://github.com/ankitagarwal/moodle
authorAndrew Nicols <andrew@nicols.co.uk>
Mon, 2 Oct 2017 03:57:34 +0000 (11:57 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Mon, 2 Oct 2017 03:57:34 +0000 (11:57 +0800)
187 files changed:
admin/cli/kill_all_sessions.php [new file with mode: 0644]
admin/cli/purge_caches.php
admin/index.php
admin/registration/confirmregistration.php
admin/registration/forms.php
admin/registration/index.php
admin/registration/lib.php
admin/registration/register.php
admin/registration/renderer.php
admin/registration/renewregistration.php
admin/renderer.php
admin/settings/analytics.php
admin/settings/server.php
admin/settings/top.php
admin/tool/analytics/settings.php
admin/tool/mobile/classes/api.php
admin/tool/mobile/tests/externallib_test.php
auth/email/classes/external.php
backup/moodle2/backup_stepslib.php
blocks/community/communitycourse.php
blocks/community/forms.php
blocks/community/locallib.php
blocks/community/renderer.php
blocks/community/styles.css
blocks/messages/block_messages.php [deleted file]
blocks/messages/db/access.php [deleted file]
blocks/messages/styles.css [deleted file]
blocks/messages/tests/behat/block_messages_course.feature [deleted file]
blocks/messages/tests/behat/block_messages_dashboard.feature [deleted file]
blocks/messages/tests/behat/block_messages_frontpage.feature [deleted file]
blocks/messages/version.php [deleted file]
blocks/upgrade.txt
calendar/amd/build/calendar.min.js
calendar/amd/build/calendar_mini.min.js
calendar/amd/build/calendar_threemonth.min.js [new file with mode: 0644]
calendar/amd/build/events.min.js
calendar/amd/build/modal_delete.min.js [new file with mode: 0644]
calendar/amd/build/repository.min.js
calendar/amd/build/selectors.min.js
calendar/amd/build/summary_modal.min.js
calendar/amd/build/view_manager.min.js
calendar/amd/src/calendar.js
calendar/amd/src/calendar_mini.js
calendar/amd/src/calendar_threemonth.js [new file with mode: 0644]
calendar/amd/src/events.js
calendar/amd/src/modal_delete.js [new file with mode: 0644]
calendar/amd/src/repository.js
calendar/amd/src/selectors.js
calendar/amd/src/summary_modal.js
calendar/amd/src/view_manager.js
calendar/classes/external/calendar_event_exporter.php
calendar/classes/external/date_exporter.php [new file with mode: 0644]
calendar/classes/external/day_exporter.php
calendar/classes/external/event_exporter.php
calendar/classes/external/event_exporter_base.php
calendar/classes/external/event_subscription_exporter.php [new file with mode: 0644]
calendar/classes/external/footer_options_exporter.php
calendar/classes/external/month_exporter.php
calendar/classes/external/week_day_exporter.php
calendar/classes/local/api.php
calendar/classes/type_base.php
calendar/externallib.php
calendar/lib.php
calendar/renderer.php
calendar/templates/add_event_button.mustache [new file with mode: 0644]
calendar/templates/calendar_mini.mustache
calendar/templates/calendar_threemonth.mustache [new file with mode: 0644]
calendar/templates/day_detailed.mustache [new file with mode: 0644]
calendar/templates/day_navigation.mustache [new file with mode: 0644]
calendar/templates/event_delete_modal.mustache [new file with mode: 0644]
calendar/templates/event_item.mustache [new file with mode: 0644]
calendar/templates/event_list.mustache [new file with mode: 0644]
calendar/templates/event_subscription.mustache [new file with mode: 0644]
calendar/templates/event_summary_body.mustache
calendar/templates/event_summary_modal.mustache
calendar/templates/footer_options.mustache
calendar/templates/header.mustache [moved from calendar/templates/month_header.mustache with 94% similarity]
calendar/templates/month_detailed.mustache
calendar/templates/month_mini.mustache
calendar/templates/month_navigation.mustache
calendar/templates/threemonth_month.mustache [new file with mode: 0644]
calendar/tests/behat/calendar_lookahead.feature
calendar/tests/rrule_manager_test.php
calendar/upgrade.txt
calendar/view.php
competency/classes/api.php
competency/tests/api_test.php
course/publish/backup.php
course/publish/forms.php
course/publish/hubselector.php
course/publish/index.php
course/publish/lib.php
course/publish/metadata.php
course/publish/renderer.php
enrol/meta/locallib.php
enrol/tests/enrollib_test.php
filter/mathjaxloader/db/upgrade.php
filter/mathjaxloader/version.php
install/lang/mi/langconfig.php [moved from blocks/messages/lang/en/block_messages.php with 60% similarity]
install/lang/oc_lnc/admin.php
install/lang/sv_fi/install.php
lang/en/admin.php
lang/en/analytics.php
lang/en/calendar.php
lang/en/deprecated.txt
lang/en/error.php
lang/en/hub.php
lang/en/role.php
lib/accesslib.php
lib/amd/build/chartjs-lazy.min.js
lib/amd/src/chartjs-lazy.js
lib/classes/hub/api.php [new file with mode: 0644]
lib/classes/hub/course_publication_form.php [new file with mode: 0644]
lib/classes/hub/publication.php [new file with mode: 0644]
lib/classes/hub/registration.php [new file with mode: 0644]
lib/classes/hub/site_registration_form.php [new file with mode: 0644]
lib/classes/hub/site_unregistration_form.php [new file with mode: 0644]
lib/classes/plugin_manager.php
lib/classes/task/registration_cron_task.php
lib/db/upgrade.php
lib/deprecatedlib.php
lib/enrollib.php
lib/filestorage/file_system.php
lib/filestorage/stored_file.php
lib/filestorage/tests/file_system_test.php
lib/flickrclient.php [new file with mode: 0644]
lib/flickrlib.php
lib/form/classes/filetypes_util.php
lib/form/tests/filetypes_util_test.php
lib/markdown/License.md
lib/markdown/Markdown.php
lib/markdown/MarkdownExtra.php
lib/markdown/MarkdownInterface.php
lib/markdown/Readme.md
lib/markdown/readme_moodle.txt
lib/mlbackend/python/classes/processor.php
lib/mlbackend/python/lang/en/mlbackend_python.php
lib/navigationlib.php
lib/oauthlib.php
lib/simplepie/LICENSE.txt [new file with mode: 0644]
lib/simplepie/autoloader.php
lib/simplepie/library/SimplePie.php
lib/simplepie/library/SimplePie/Category.php
lib/simplepie/library/SimplePie/Content/Type/Sniffer.php
lib/simplepie/library/SimplePie/File.php
lib/simplepie/library/SimplePie/Item.php
lib/simplepie/library/SimplePie/Locator.php
lib/simplepie/library/SimplePie/Misc.php
lib/simplepie/library/SimplePie/Parse/Date.php
lib/simplepie/library/SimplePie/Sanitize.php
lib/simplepie/readme_moodle.txt
lib/tests/accesslib_test.php
lib/tests/navigationlib_test.php
lib/thirdpartylibs.xml
login/signup_form.php
mod/assign/submission/onlinetext/locallib.php
mod/chat/classes/external.php
mod/chat/tests/externallib_test.php
mod/choice/lang/en/choice.php
mod/choice/lib.php
mod/choice/tests/lib_test.php
mod/choice/tests/restore_date_test.php
mod/data/export_form.php
mod/folder/edit.php
mod/lti/view.php
mod/quiz/report/overview/report.php
mod/quiz/report/responses/report.php
mod/workshop/classes/external.php
mod/workshop/db/services.php
mod/workshop/locallib.php
mod/workshop/submission.php
mod/workshop/tests/external_test.php
mod/workshop/version.php
plagiarism/upgrade.txt
portfolio/flickr/lib.php
question/behaviour/manualgraded/tests/walkthrough_test.php
question/behaviour/rendererbase.php
repository/flickr/db/upgrade.php [new file with mode: 0644]
repository/flickr/lib.php
repository/flickr/version.php
repository/googledocs/lib.php
repository/onedrive/lib.php
search/classes/document.php
theme/boost/scss/preset/default.scss
user/index.php
user/renderer.php
version.php

diff --git a/admin/cli/kill_all_sessions.php b/admin/cli/kill_all_sessions.php
new file mode 100644 (file)
index 0000000..9cf301d
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * CLI script to kill all user sessions without asking for confirmation.
+ *
+ * @package    core
+ * @subpackage cli
+ * @copyright  2017 Alexander Bias <alexander.bias@uni-ulm.de>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define('CLI_SCRIPT', true);
+
+require(__DIR__.'/../../config.php');
+require_once($CFG->libdir.'/clilib.php');
+
+list($options, $unrecognized) = cli_get_params(array('help' => false), array('h' => 'help'));
+
+if ($unrecognized) {
+    $unrecognized = implode("\n  ", $unrecognized);
+    cli_error(get_string('cliunknowoption', 'admin', $unrecognized), 2);
+}
+
+if ($options['help']) {
+    $help =
+"Kill all Moodle sessions
+
+Options:
+-h, --help            Print out this help
+
+Example:
+\$sudo -u www-data /usr/bin/php admin/cli/kill_all_sessions.php
+";
+
+    echo $help;
+    exit(0);
+}
+
+\core\session\manager::kill_all_sessions();
+
+exit(0);
index 7c9d344..64f29bd 100644 (file)
@@ -15,6 +15,8 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
+ * CLI script to purge caches without asking for confirmation.
+ *
  * @package    core
  * @subpackage cli
  * @copyright  2011 David Mudrak <david@moodle.com>
@@ -50,4 +52,4 @@ Example:
 
 purge_all_caches();
 
-exit(0);
\ No newline at end of file
+exit(0);
index ba80a96..88a7d4c 100644 (file)
@@ -857,7 +857,7 @@ if ($updateschecker->enabled()) {
 
 $buggyiconvnomb = (!function_exists('mb_convert_encoding') and @iconv('UTF-8', 'UTF-8//IGNORE', '100'.chr(130).'€') !== '100€');
 //check if the site is registered on Moodle.org
-$registered = $DB->count_records('registration_hubs', array('huburl' => HUB_MOODLEORGHUBURL, 'confirmed' => 1));
+$registered = \core\hub\registration::is_registered();
 // Check if there are any cache warnings.
 $cachewarnings = cache_helper::warnings();
 // Check if there are events 1 API handlers.
index 77b2fb2..7fe7689 100644 (file)
@@ -20,7 +20,7 @@
 //                                                                       //
 ///////////////////////////////////////////////////////////////////////////
 
-/*
+/**
  * @package    moodle
  * @subpackage registration
  * @author     Jerome Mouneyrac <jerome@mouneyrac.com>
@@ -36,7 +36,6 @@
 
 require('../../config.php');
 require_once($CFG->libdir . '/adminlib.php');
-require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
 
 $newtoken = optional_param('newtoken', '', PARAM_ALPHANUM);
 $url = optional_param('url', '', PARAM_URL);
@@ -44,7 +43,11 @@ $hubname = optional_param('hubname', '', PARAM_TEXT);
 $token = optional_param('token', '', PARAM_TEXT);
 $error = optional_param('error', '', PARAM_ALPHANUM);
 
-admin_externalpage_setup('registrationhubs');
+admin_externalpage_setup('registrationmoodleorg');
+
+if ($url !== HUB_MOODLEORGHUBURL) {
+    throw new moodle_exception('errorotherhubsnotsupported', 'hub');
+}
 
 if (!empty($error) and $error == 'urlalreadyexist') {
     throw new moodle_exception('urlalreadyregistered', 'hub',
@@ -52,38 +55,20 @@ if (!empty($error) and $error == 'urlalreadyexist') {
 }
 
 //check that we are waiting a confirmation from this hub, and check that the token is correct
-$registrationmanager = new registration_manager();
-$registeredhub = $registrationmanager->get_unconfirmedhub($url);
-if (!empty($registeredhub) and $registeredhub->token == $token) {
-
-    echo $OUTPUT->header();
-    echo $OUTPUT->heading(get_string('registrationconfirmed', 'hub'), 3, 'main');
+core\hub\registration::confirm_registration($token, $newtoken, $hubname);
 
-    $registeredhub->token = $newtoken;
-    $registeredhub->confirmed = 1;
-    $registeredhub->hubname = $hubname;
-    $registrationmanager->update_registeredhub($registeredhub);
+echo $OUTPUT->header();
+echo $OUTPUT->heading(get_string('registrationconfirmed', 'hub'), 3, 'main');
 
-    // Display notification message.
-    echo $OUTPUT->notification(get_string('registrationconfirmedon', 'hub'), 'notifysuccess');
+// Display notification message.
+echo $OUTPUT->notification(get_string('registrationconfirmedon', 'hub'), 'notifysuccess');
 
-    //display continue button
-    $registrationpage = new moodle_url('/admin/registration/index.php');
-    $continuebutton = $OUTPUT->render(new single_button($registrationpage, get_string('continue', 'hub')));
-    $continuebutton = html_writer::tag('div', $continuebutton, array('class' => 'mdl-align'));
-    echo $continuebutton;
+// Display continue button.
+$registrationpage = new moodle_url('/admin/registration/index.php');
+$continuebutton = $OUTPUT->render(new single_button($registrationpage, get_string('continue')));
+$continuebutton = html_writer::tag('div', $continuebutton, array('class' => 'mdl-align'));
+echo $continuebutton;
 
-    if (!extension_loaded('xmlrpc')) {
-        //display notice about xmlrpc
-        $xmlrpcnotification = $OUTPUT->doc_link('admin/environment/php_extension/xmlrpc', '');
-        $xmlrpcnotification .= get_string('xmlrpcdisabledregistration', 'hub');
-        echo $OUTPUT->notification($xmlrpcnotification);
-    }
-
-    echo $OUTPUT->footer();
-} else {
-    throw new moodle_exception('wrongtoken', 'hub',
-            $CFG->wwwroot . '/' . $CFG->admin . '/registration/index.php');
-}
+echo $OUTPUT->footer();
 
 
index 0d70879..6fe9553 100644 (file)
@@ -20,7 +20,7 @@
 //                                                                       //
 ///////////////////////////////////////////////////////////////////////////
 
-/*
+/**
  * @package    moodle
  * @subpackage registration
  * @author     Jerome Mouneyrac <jerome@mouneyrac.com>
  * The forms needed by registration pages.
  */
 
+defined('MOODLE_INTERNAL') || die();
 
-require_once($CFG->libdir . '/formslib.php');
-require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
-
-/**
- * This form display a unregistration form.
- */
-class site_unregistration_form extends moodleform {
-
-    public function definition() {
-        $mform = & $this->_form;
-        $mform->addElement('header', 'site', get_string('unregister', 'hub'));
-
-        $huburl = $this->_customdata['huburl'];
-        $hubname = $this->_customdata['hubname'];
-
-        $unregisterlabel = get_string('unregister', 'hub');
-        $mform->addElement('checkbox', 'unpublishalladvertisedcourses', '',
-                ' ' . get_string('unpublishalladvertisedcourses', 'hub'));
-        $mform->setType('unpublishalladvertisedcourses', PARAM_INT);
-        $mform->addElement('checkbox', 'unpublishalluploadedcourses', '',
-                ' ' . get_string('unpublishalluploadedcourses', 'hub'));
-        $mform->setType('unpublishalluploadedcourses', PARAM_INT);
-
-        $mform->addElement('hidden', 'confirm', 1);
-        $mform->setType('confirm', PARAM_INT);
-        $mform->addElement('hidden', 'unregistration', 1);
-        $mform->setType('unregistration', PARAM_INT);
-        $mform->addElement('hidden', 'huburl', $huburl);
-        $mform->setType('huburl', PARAM_URL);
-        $mform->addElement('hidden', 'hubname', $hubname);
-        $mform->setType('hubname', PARAM_TEXT);
-
-        $this->add_action_buttons(true, $unregisterlabel);
-    }
-
-}
-
-/**
- * This form display a clean registration data form.
- */
-class site_clean_registration_data_form extends moodleform {
-
-    public function definition() {
-        $mform = & $this->_form;
-        $mform->addElement('header', 'site', get_string('unregister', 'hub'));
-
-        $huburl = $this->_customdata['huburl'];
-        $hubname = $this->_customdata['hubname'];
-
-
-        $unregisterlabel = get_string('forceunregister', 'hub');
-        $mform->addElement('static', '', get_string('warning', 'hub'), get_string('forceunregisterconfirmation', 'hub', $hubname));
-
-        $mform->addElement('hidden', 'confirm', 1);
-        $mform->setType('confirm', PARAM_INT);
-        $mform->addElement('hidden', 'unregistration', 1);
-        $mform->setType('unregistration', PARAM_INT);
-        $mform->addElement('hidden', 'cleanregdata', 1);
-        $mform->setType('cleanregdata', PARAM_INT);
-        $mform->addElement('hidden', 'huburl', $huburl);
-        $mform->setType('huburl', PARAM_URL);
-        $mform->addElement('hidden', 'hubname', $hubname);
-        $mform->setType('hubname', PARAM_TEXT);
-
-        $this->add_action_buttons(true, $unregisterlabel);
-    }
-
-}
-
-/**
- * This form display a hub selector.
- * The hub list is retrieved from Moodle.org hub directory.
- * Also displayed, a text field to enter private hub url + its password
- */
-class hub_selector_form extends moodleform {
-
-    public function definition() {
-        global $CFG, $OUTPUT;
-        $mform = & $this->_form;
-        $mform->addElement('header', 'site', get_string('selecthub', 'hub'));
-
-        //retrieve the hub list on the hub directory by web service
-        $function = 'hubdirectory_get_hubs';
-        $params = array();
-        $serverurl = HUB_HUBDIRECTORYURL . "/local/hubdirectory/webservice/webservices.php";
-        require_once($CFG->dirroot . "/webservice/xmlrpc/lib.php");
-        $xmlrpcclient = new webservice_xmlrpc_client($serverurl, 'publichubdirectory');
-        try {
-            $hubs = $xmlrpcclient->call($function, $params);
-        } catch (Exception $e) {
-            $error = $OUTPUT->notification(get_string('errorhublisting', 'hub', $e->getMessage()));
-            $mform->addElement('static', 'errorhub', '', $error);
-            $hubs = array();
-        }
-
-        //remove moodle.org from the hub list
-        foreach ($hubs as $key => $hub) {
-            if ($hub['url'] == HUB_MOODLEORGHUBURL || $hub['url'] == HUB_OLDMOODLEORGHUBURL) {
-                unset($hubs[$key]);
-            }
-        }
-
-        //Public hub list
-        $options = array();
-        foreach ($hubs as $hub) {
-            //to not display a name longer than 100 character (too big)
-            if (core_text::strlen($hub['name']) > 100) {
-                $hubname = core_text::substr($hub['name'], 0, 100);
-                $hubname = $hubname . "...";
-            } else {
-                $hubname = $hub['name'];
-            }
-            $options[$hub['url']] = $hubname;
-            $mform->addElement('hidden', clean_param($hub['url'], PARAM_ALPHANUMEXT), $hubname);
-            $mform->setType(clean_param($hub['url'], PARAM_ALPHANUMEXT), PARAM_ALPHANUMEXT);
-        }
-        if (!empty($hubs)) {
-            $mform->addElement('select', 'publichub', get_string('publichub', 'hub'),
-                    $options, array("size" => 15));
-            $mform->setType('publichub', PARAM_URL);
-        }
-
-        $mform->addElement('static', 'or', '', get_string('orenterprivatehub', 'hub'));
-
-        //Private hub
-        $mform->addElement('text', 'unlistedurl', get_string('privatehuburl', 'hub'),
-                array('class' => 'registration_textfield'));
-        $mform->setType('unlistedurl', PARAM_URL);
-        $mform->addElement('text', 'password', get_string('password'),
-                array('class' => 'registration_textfield'));
-        $mform->setType('password', PARAM_RAW);
-
-        $this->add_action_buttons(false, get_string('selecthub', 'hub'));
-    }
-
-    /**
-     * Check the unlisted URL is a URL
-     */
-    function validation($data, $files) {
-        global $CFG;
-        $errors = parent::validation($data, $files);
-
-        $unlistedurl = $this->_form->_submitValues['unlistedurl'];
-
-        if (empty($unlistedurl)) {
-            $errors['unlistedurl'] = get_string('badurlformat', 'hub');
-        }
-
-        return $errors;
-    }
-
-}
-
-/**
- * The site registration form. Information will be sent to a given hub.
- */
-class site_registration_form extends moodleform {
-
-    public function definition() {
-        global $CFG, $DB;
-
-        $strrequired = get_string('required');
-        $mform = & $this->_form;
-        $huburl = $this->_customdata['huburl'];
-        $hubname = $this->_customdata['hubname'];
-        $password = $this->_customdata['password'];
-        $admin = get_admin();
-        $site = get_site();
-
-        //retrieve config for this hub and set default if they don't exist
-        $cleanhuburl = clean_param($huburl, PARAM_ALPHANUMEXT);
-        $sitename = get_config('hub', 'site_name_' . $cleanhuburl);
-        if ($sitename === false) {
-            $sitename = format_string($site->fullname, true, array('context' => context_course::instance(SITEID)));
-        }
-        $sitedescription = get_config('hub', 'site_description_' . $cleanhuburl);
-        if ($sitedescription === false) {
-            $sitedescription = $site->summary;
-        }
-        $contactname = get_config('hub', 'site_contactname_' . $cleanhuburl);
-        if ($contactname === false) {
-            $contactname = fullname($admin, true);
-        }
-        $contactemail = get_config('hub', 'site_contactemail_' . $cleanhuburl);
-        if ($contactemail === false) {
-            $contactemail = $admin->email;
-        }
-        $contactphone = get_config('hub', 'site_contactphone_' . $cleanhuburl);
-        if ($contactphone === false) {
-            $contactphone = $admin->phone1;
-        }
-        $imageurl = get_config('hub', 'site_imageurl_' . $cleanhuburl);
-        $privacy = get_config('hub', 'site_privacy_' . $cleanhuburl);
-        $address = get_config('hub', 'site_address_' . $cleanhuburl);
-        if ($address === false) {
-            $address = '';
-        }
-        $region = get_config('hub', 'site_region_' . $cleanhuburl);
-        $country = get_config('hub', 'site_country_' . $cleanhuburl);
-        if (empty($country)) {
-            $country = $admin->country ?: $CFG->country;
-        }
-        $language = get_config('hub', 'site_language_' . $cleanhuburl);
-        if ($language === false) {
-            $language = explode('_', current_language())[0];
-        }
-        $geolocation = get_config('hub', 'site_geolocation_' . $cleanhuburl);
-        if ($geolocation === false) {
-            $geolocation = '';
-        }
-        $contactable = get_config('hub', 'site_contactable_' . $cleanhuburl);
-        $emailalert = get_config('hub', 'site_emailalert_' . $cleanhuburl);
-        $emailalert = ($emailalert === false || $emailalert) ? 1 : 0;
-        $coursesnumber = get_config('hub', 'site_coursesnumber_' . $cleanhuburl);
-        $usersnumber = get_config('hub', 'site_usersnumber_' . $cleanhuburl);
-        $roleassignmentsnumber = get_config('hub', 'site_roleassignmentsnumber_' . $cleanhuburl);
-        $postsnumber = get_config('hub', 'site_postsnumber_' . $cleanhuburl);
-        $questionsnumber = get_config('hub', 'site_questionsnumber_' . $cleanhuburl);
-        $resourcesnumber = get_config('hub', 'site_resourcesnumber_' . $cleanhuburl);
-        $badgesnumber = get_config('hub', 'site_badges_' . $cleanhuburl);
-        $issuedbadgesnumber = get_config('hub', 'site_issuedbadges_' . $cleanhuburl);
-        $mediancoursesize = get_config('hub', 'site_mediancoursesize_' . $cleanhuburl);
-        $participantnumberaveragecfg = get_config('hub', 'site_participantnumberaverage_' . $cleanhuburl);
-        $modulenumberaveragecfg = get_config('hub', 'site_modulenumberaverage_' . $cleanhuburl);
-        // Mobile related information.
-        $mobileservicesenabled = get_config('hub', 'site_mobileservicesenabled_' . $cleanhuburl);
-        $mobilenotificationsenabled = get_config('hub', 'site_mobilenotificationsenabled_' . $cleanhuburl);
-        $registereduserdevices = get_config('hub', 'site_registereduserdevices_' . $cleanhuburl);
-        $registeredactiveuserdevices = get_config('hub', 'site_registeredactiveuserdevices_' . $cleanhuburl);
-
-        //hidden parameters
-        $mform->addElement('hidden', 'huburl', $huburl);
-        $mform->setType('huburl', PARAM_URL);
-        $mform->addElement('hidden', 'hubname', $hubname);
-        $mform->setType('hubname', PARAM_TEXT);
-        $mform->addElement('hidden', 'password', $password);
-        $mform->setType('password', PARAM_RAW);
-
-        //the input parameters
-        $mform->addElement('header', 'moodle', get_string('registrationinfo', 'hub'));
-
-        $mform->addElement('text', 'name', get_string('sitename', 'hub'),
-                array('class' => 'registration_textfield'));
-        $mform->addRule('name', $strrequired, 'required', null, 'client');
-        $mform->setType('name', PARAM_TEXT);
-        $mform->setDefault('name', $sitename);
-        $mform->addHelpButton('name', 'sitename', 'hub');
-
-        $options = array();
-        $registrationmanager = new registration_manager();
-        $options[HUB_SITENOTPUBLISHED] = $registrationmanager->get_site_privacy_string(HUB_SITENOTPUBLISHED);
-        $options[HUB_SITENAMEPUBLISHED] = $registrationmanager->get_site_privacy_string(HUB_SITENAMEPUBLISHED);
-        $options[HUB_SITELINKPUBLISHED] = $registrationmanager->get_site_privacy_string(HUB_SITELINKPUBLISHED);
-        $mform->addElement('select', 'privacy', get_string('siteprivacy', 'hub'), $options);
-        $mform->setDefault('privacy', $privacy);
-        $mform->setType('privacy', PARAM_ALPHA);
-        $mform->addHelpButton('privacy', 'privacy', 'hub');
-        unset($options);
-
-        $mform->addElement('textarea', 'description', get_string('sitedesc', 'hub'),
-                array('rows' => 8, 'cols' => 41));
-        $mform->addRule('description', $strrequired, 'required', null, 'client');
-        $mform->setDefault('description', $sitedescription);
-        $mform->setType('description', PARAM_TEXT);
-        $mform->addHelpButton('description', 'sitedesc', 'hub');
-
-        $languages = get_string_manager()->get_list_of_languages();
-        core_collator::asort($languages);
-        $mform->addElement('select', 'language', get_string('sitelang', 'hub'),
-                $languages);
-        $mform->setType('language', PARAM_ALPHANUMEXT);
-        $mform->addHelpButton('language', 'sitelang', 'hub');
-        $mform->setDefault('language', $language);
-
-        $mform->addElement('textarea', 'address', get_string('postaladdress', 'hub'),
-                array('rows' => 4, 'cols' => 41));
-        $mform->setType('address', PARAM_TEXT);
-        $mform->setDefault('address', $address);
-        $mform->addHelpButton('address', 'postaladdress', 'hub');
-
-        //TODO: use the region array I generated
-//        $mform->addElement('select', 'region', get_string('selectaregion'), array('-' => '-'));
-//        $mform->setDefault('region', $region);
-        $mform->addElement('hidden', 'regioncode', '-');
-        $mform->setType('regioncode', PARAM_ALPHANUMEXT);
-
-        $countries = ['' => ''] + get_string_manager()->get_list_of_countries();
-        $mform->addElement('select', 'countrycode', get_string('sitecountry', 'hub'), $countries);
-        $mform->setDefault('countrycode', $country);
-        $mform->setType('countrycode', PARAM_ALPHANUMEXT);
-        $mform->addHelpButton('countrycode', 'sitecountry', 'hub');
-        $mform->addRule('countrycode', $strrequired, 'required', null, 'client');
-
-        $mform->addElement('text', 'geolocation', get_string('sitegeolocation', 'hub'),
-                array('class' => 'registration_textfield'));
-        $mform->setDefault('geolocation', $geolocation);
-        $mform->setType('geolocation', PARAM_RAW);
-        $mform->addHelpButton('geolocation', 'sitegeolocation', 'hub');
-
-        $mform->addElement('text', 'contactname', get_string('siteadmin', 'hub'),
-                array('class' => 'registration_textfield'));
-        $mform->addRule('contactname', $strrequired, 'required', null, 'client');
-        $mform->setType('contactname', PARAM_TEXT);
-        $mform->setDefault('contactname', $contactname);
-        $mform->addHelpButton('contactname', 'siteadmin', 'hub');
-
-        $mform->addElement('text', 'contactphone', get_string('sitephone', 'hub'),
-                array('class' => 'registration_textfield'));
-        $mform->setType('contactphone', PARAM_TEXT);
-        $mform->setDefault('contactphone', $contactphone);
-        $mform->addHelpButton('contactphone', 'sitephone', 'hub');
-        $mform->setForceLtr('contactphone');
-
-        $mform->addElement('text', 'contactemail', get_string('siteemail', 'hub'),
-                array('class' => 'registration_textfield'));
-        $mform->addRule('contactemail', $strrequired, 'required', null, 'client');
-        $mform->setType('contactemail', PARAM_EMAIL);
-        $mform->setDefault('contactemail', $contactemail);
-        $mform->addHelpButton('contactemail', 'siteemail', 'hub');
-
-        $options = array();
-        $options[0] = get_string("registrationcontactno");
-        $options[1] = get_string("registrationcontactyes");
-        $mform->addElement('select', 'contactable', get_string('siteregistrationcontact', 'hub'), $options);
-        $mform->setDefault('contactable', $contactable);
-        $mform->setType('contactable', PARAM_INT);
-        $mform->addHelpButton('contactable', 'siteregistrationcontact', 'hub');
-        unset($options);
-
-        $options = array();
-        $options[0] = get_string("registrationno");
-        $options[1] = get_string("registrationyes");
-        $mform->addElement('select', 'emailalert', get_string('siteregistrationemail', 'hub'), $options);
-        $mform->setDefault('emailalert', $emailalert);
-        $mform->setType('emailalert', PARAM_INT);
-        $mform->addHelpButton('emailalert', 'siteregistrationemail', 'hub');
-        unset($options);
-
-        //TODO site logo
-        $mform->addElement('hidden', 'imageurl', ''); //TODO: temporary
-        $mform->setType('imageurl', PARAM_URL);
-
-        $mform->addElement('static', 'urlstring', get_string('siteurl', 'hub'), $CFG->wwwroot);
-        $mform->addHelpButton('urlstring', 'siteurl', 'hub');
-
-        $mform->addElement('static', 'versionstring', get_string('siteversion', 'hub'), $CFG->version);
-        $mform->addElement('hidden', 'moodleversion', $CFG->version);
-        $mform->setType('moodleversion', PARAM_INT);
-        $mform->addHelpButton('versionstring', 'siteversion', 'hub');
-
-        $mform->addElement('static', 'releasestring', get_string('siterelease', 'hub'), $CFG->release);
-        $mform->addElement('hidden', 'moodlerelease', $CFG->release);
-        $mform->setType('moodlerelease', PARAM_TEXT);
-        $mform->addHelpButton('releasestring', 'siterelease', 'hub');
-
-        /// Display statistic that are going to be retrieve by the hub
-        $coursecount = $DB->count_records('course') - 1;
-        $usercount = $DB->count_records('user', array('deleted' => 0));
-        $roleassigncount = $DB->count_records('role_assignments');
-        $postcount = $DB->count_records('forum_posts');
-        $questioncount = $DB->count_records('question');
-        $resourcecount = $DB->count_records('resource');
-        require_once($CFG->dirroot . "/course/lib.php");
-        $participantnumberaverage = number_format(average_number_of_participants(), 2);
-        $modulenumberaverage = number_format(average_number_of_courses_modules(), 2);
-        require_once($CFG->libdir . '/badgeslib.php');
-        $badges = $DB->count_records_select('badge', 'status <> ' . BADGE_STATUS_ARCHIVED);
-        $issuedbadges = $DB->count_records('badge_issued');
-        // Mobile related information.
-        $ismobileenabled = false;
-        $aremobilenotificationsenabled = false;
-        $registereduserdevicescount = 0;
-        $registeredactiveuserdevicescount = 0;
-        if (!empty($CFG->enablewebservices) && !empty($CFG->enablemobilewebservice)) {
-            $ismobileenabled = true;
-            $registereduserdevicescount = $DB->count_records('user_devices');
-            $airnotifierextpath = $CFG->dirroot . '/message/output/airnotifier/externallib.php';
-            if (file_exists($airnotifierextpath)) { // Maybe some one uninstalled the plugin.
-                require_once($airnotifierextpath);
-                $aremobilenotificationsenabled = (bool) message_airnotifier_external::is_system_configured();
-                $registeredactiveuserdevicescount = $DB->count_records('message_airnotifier_devices', array('enable' => 1));
-            }
-        }
-
-        if (HUB_MOODLEORGHUBURL != $huburl) {
-            $mform->addElement('checkbox', 'courses', get_string('sendfollowinginfo', 'hub'),
-                    " " . get_string('coursesnumber', 'hub', $coursecount));
-            $mform->setDefault('courses', $coursesnumber != -1);
-            $mform->setType('courses', PARAM_INT);
-            $mform->addHelpButton('courses', 'sendfollowinginfo', 'hub');
-
-            $mform->addElement('checkbox', 'users', '',
-                    " " . get_string('usersnumber', 'hub', $usercount));
-            $mform->setDefault('users', $usersnumber != -1);
-            $mform->setType('users', PARAM_INT);
-
-            $mform->addElement('checkbox', 'roleassignments', '',
-                    " " . get_string('roleassignmentsnumber', 'hub', $roleassigncount));
-            $mform->setDefault('roleassignments', $roleassignmentsnumber != -1);
-            $mform->setType('roleassignments', PARAM_INT);
-
-            $mform->addElement('checkbox', 'posts', '',
-                    " " . get_string('postsnumber', 'hub', $postcount));
-            $mform->setDefault('posts', $postsnumber != -1);
-            $mform->setType('posts', PARAM_INT);
-
-            $mform->addElement('checkbox', 'questions', '',
-                    " " . get_string('questionsnumber', 'hub', $questioncount));
-            $mform->setDefault('questions', $questionsnumber != -1);
-            $mform->setType('questions', PARAM_INT);
-
-            $mform->addElement('checkbox', 'resources', '',
-                    " " . get_string('resourcesnumber', 'hub', $resourcecount));
-            $mform->setDefault('resources', $resourcesnumber != -1);
-            $mform->setType('resources', PARAM_INT);
-
-            $mform->addElement('checkbox', 'badges', '',
-                    " " . get_string('badgesnumber', 'hub', $badges));
-            $mform->setDefault('badges', $badgesnumber != -1);
-            $mform->setType('badges', PARAM_INT);
-
-            $mform->addElement('checkbox', 'issuedbadges', '',
-                    " " . get_string('issuedbadgesnumber', 'hub', $issuedbadges));
-            $mform->setDefault('issuedbadges', $issuedbadgesnumber != -1);
-            $mform->setType('issuedbadges', PARAM_INT);
-
-            $mform->addElement('checkbox', 'participantnumberaverage', '',
-                    " " . get_string('participantnumberaverage', 'hub', $participantnumberaverage));
-            $mform->setDefault('participantnumberaverage', $participantnumberaveragecfg != -1);
-            $mform->setType('participantnumberaverage', PARAM_FLOAT);
-
-            $mform->addElement('checkbox', 'modulenumberaverage', '',
-                    " " . get_string('modulenumberaverage', 'hub', $modulenumberaverage));
-            $mform->setDefault('modulenumberaverage', $modulenumberaveragecfg != -1);
-            $mform->setType('modulenumberaverage', PARAM_FLOAT);
-
-            $mobileservicestatus = $ismobileenabled ? 'yes' : 'no';
-            $mform->addElement('checkbox', 'mobileservicesenabled', '',
-                    " " . get_string('mobileservicesenabled', 'hub', $mobileservicestatus));
-            $mform->setDefault('mobileservicesenabled', $mobileservicesenabled != -1);
-            $mform->setType('mobileservicesenabled', PARAM_INT);
-
-            $mobilenotificationsstatus = $aremobilenotificationsenabled ? 'yes' : 'no';
-            $mform->addElement('checkbox', 'mobilenotificationsenabled', '',
-                    " " . get_string('mobilenotificationsenabled', 'hub', $mobilenotificationsstatus));
-            $mform->setDefault('mobilenotificationsenabled', $mobilenotificationsenabled != -1);
-            $mform->setType('mobilenotificationsenabled', PARAM_INT);
-
-            $mform->addElement('checkbox', 'registereduserdevices', '',
-                    " " . get_string('registereduserdevices', 'hub', $registereduserdevicescount));
-            $mform->setDefault('registereduserdevices', $registereduserdevices != -1);
-            $mform->setType('registereduserdevices', PARAM_INT);
-
-            $mform->addElement('checkbox', 'registeredactiveuserdevices', '',
-                    " " . get_string('registeredactiveuserdevices', 'hub', $registeredactiveuserdevicescount));
-            $mform->setDefault('registeredactiveuserdevices', $registeredactiveuserdevices != -1);
-            $mform->setType('registeredactiveuserdevices', PARAM_INT);
-        } else {
-            $mform->addElement('static', 'courseslabel', get_string('sendfollowinginfo', 'hub'),
-                    " " . get_string('coursesnumber', 'hub', $coursecount));
-            $mform->addElement('hidden', 'courses', 1);
-            $mform->setType('courses', PARAM_INT);
-            $mform->addHelpButton('courseslabel', 'sendfollowinginfo', 'hub');
-
-            $mform->addElement('static', 'userslabel', '',
-                    " " . get_string('usersnumber', 'hub', $usercount));
-            $mform->addElement('hidden', 'users', 1);
-            $mform->setType('users', PARAM_INT);
-
-            $mform->addElement('static', 'roleassignmentslabel', '',
-                    " " . get_string('roleassignmentsnumber', 'hub', $roleassigncount));
-            $mform->addElement('hidden', 'roleassignments', 1);
-            $mform->setType('roleassignments', PARAM_INT);
-
-            $mform->addElement('static', 'postslabel', '',
-                    " " . get_string('postsnumber', 'hub', $postcount));
-            $mform->addElement('hidden', 'posts', 1);
-            $mform->setType('posts', PARAM_INT);
-
-            $mform->addElement('static', 'questionslabel', '',
-                    " " . get_string('questionsnumber', 'hub', $questioncount));
-            $mform->addElement('hidden', 'questions', 1);
-            $mform->setType('questions', PARAM_INT);
-
-            $mform->addElement('static', 'resourceslabel', '',
-                    " " . get_string('resourcesnumber', 'hub', $resourcecount));
-            $mform->addElement('hidden', 'resources', 1);
-            $mform->setType('resources', PARAM_INT);
-
-            $mform->addElement('static', 'badgeslabel', '',
-                    " " . get_string('badgesnumber', 'hub', $badges));
-            $mform->addElement('hidden', 'badges', 1);
-            $mform->setType('badges', PARAM_INT);
-
-            $mform->addElement('static', 'issuedbadgeslabel', '',
-                    " " . get_string('issuedbadgesnumber', 'hub', $issuedbadges));
-            $mform->addElement('hidden', 'issuedbadges', true);
-            $mform->setType('issuedbadges', PARAM_INT);
-
-            $mform->addElement('static', 'participantnumberaveragelabel', '',
-                    " " . get_string('participantnumberaverage', 'hub', $participantnumberaverage));
-            $mform->addElement('hidden', 'participantnumberaverage', 1);
-            $mform->setType('participantnumberaverage', PARAM_FLOAT);
-
-            $mform->addElement('static', 'modulenumberaveragelabel', '',
-                    " " . get_string('modulenumberaverage', 'hub', $modulenumberaverage));
-            $mform->addElement('hidden', 'modulenumberaverage', 1);
-            $mform->setType('modulenumberaverage', PARAM_FLOAT);
-
-            $mobileservicestatus = $ismobileenabled ? 'yes' : 'no';
-            $mform->addElement('static', 'mobileservicesenabledlabel', '',
-                    " " . get_string('mobileservicesenabled', 'hub', $mobileservicestatus));
-            $mform->addElement('hidden', 'mobileservicesenabled', 1);
-            $mform->setType('mobileservicesenabled', PARAM_INT);
-
-            $mobilenotificationsstatus = $aremobilenotificationsenabled ? 'yes' : 'no';
-            $mform->addElement('static', 'mobilenotificationsenabledlabel', '',
-                    " " . get_string('mobilenotificationsenabled', 'hub', $mobilenotificationsstatus));
-            $mform->addElement('hidden', 'mobilenotificationsenabled', 1);
-            $mform->setType('mobilenotificationsenabled', PARAM_INT);
-
-            $mform->addElement('static', 'registereduserdeviceslabel', '',
-                    " " . get_string('registereduserdevices', 'hub', $registereduserdevicescount));
-            $mform->addElement('hidden', 'registereduserdevices', 1);
-            $mform->setType('registereduserdevices', PARAM_INT);
-
-            $mform->addElement('static', 'registeredactiveuserdeviceslabel', '',
-                    " " . get_string('registeredactiveuserdevices', 'hub', $registeredactiveuserdevicescount));
-            $mform->addElement('hidden', 'registeredactiveuserdevices', 1);
-            $mform->setType('registeredactiveuserdevices', PARAM_INT);
-        }
-
-        //check if it's a first registration or update
-        $hubregistered = $registrationmanager->get_registeredhub($huburl);
-
-        if (!empty($hubregistered)) {
-            $buttonlabel = get_string('updatesite', 'hub',
-                            !empty($hubname) ? $hubname : $huburl);
-            $mform->addElement('hidden', 'update', true);
-            $mform->setType('update', PARAM_BOOL);
-        } else {
-            $buttonlabel = get_string('registersite', 'hub',
-                            !empty($hubname) ? $hubname : $huburl);
-        }
-
-        $this->add_action_buttons(false, $buttonlabel);
-    }
-
-}
-
+debugging('Support for alternative hubs has been removed from Moodle in 3.4. For communication with moodle.net ' .
+    'see lib/classes/hub/ .', DEBUG_DEVELOPER);
index b9aeb18..0adb27b 100644 (file)
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-/*
+/**
  * @package    moodle
  * @subpackage registration
  * @author     Jerome Mouneyrac <jerome@mouneyrac.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
  * @copyright  (C) 1999 onwards Martin Dougiamas  http://dougiamas.com
  *
- * On this page the administrator selects which hub he wants to register (except for moodle.net)
- * Admins can register with moodle.net via the site admin menu "Registration" link.
- * On this page the administrator can also unregister from any hubs including moodle.net.
+ * This page displays the site registration form for Moodle.net.
+ * It handles redirection to the hub to continue the registration workflow process.
+ * It also handles update operation by web service.
  */
 
-require('../../config.php');
-
+require_once('../../config.php');
 require_once($CFG->libdir . '/adminlib.php');
-require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
-require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/forms.php');
-require_once($CFG->dirroot . '/course/publish/lib.php');
-require_once($CFG->dirroot . "/webservice/xmlrpc/lib.php");
-
-admin_externalpage_setup('registrationhubs');
 
-$renderer = $PAGE->get_renderer('core', 'register');
+admin_externalpage_setup('registrationmoodleorg');
 
 $unregistration = optional_param('unregistration', 0, PARAM_INT);
-$cleanregdata = optional_param('cleanregdata', 0, PARAM_BOOL);
-$confirm = optional_param('confirm', 0, PARAM_INT);
-$huburl = optional_param('huburl', '', PARAM_URL);
-$cancel = optional_param('cancel', null, PARAM_ALPHA);
-
-$registrationmanager = new registration_manager();
-$publicationmanager = new course_publish_manager();
-$errormessage = '';
-if (empty($cancel) and $unregistration and $confirm and confirm_sesskey()) {
-
-    $hub = $registrationmanager->get_registeredhub($huburl);
-
-    //unpublish course and unregister the site by web service
-    if (!$cleanregdata) {
-
-        //check if we need to unpublish courses
-        //enrollable courses
-        $unpublishalladvertisedcourses = optional_param('unpublishalladvertisedcourses', 0, PARAM_INT);
-        $hubcourseids = array();
-        if ($unpublishalladvertisedcourses) {
-            $enrollablecourses = $publicationmanager->get_publications($huburl, null, 1);
-            if (!empty($enrollablecourses)) {
-                foreach ($enrollablecourses as $enrollablecourse) {
-                    $hubcourseids[] = $enrollablecourse->hubcourseid;
-                }
-            }
-        }
-        //downloadable courses
-        $unpublishalluploadedcourses = optional_param('unpublishalluploadedcourses', 0, PARAM_INT);
-        if ($unpublishalluploadedcourses) {
-            $downloadablecourses = $publicationmanager->get_publications($huburl, null, 0);
-            if (!empty($downloadablecourses)) {
-                foreach ($downloadablecourses as $downloadablecourse) {
-                    $hubcourseids[] = $downloadablecourse->hubcourseid;
-                }
-            }
-        }
 
-        //unpublish the courses by web service
-        if (!empty($hubcourseids)) {
-            $function = 'hub_unregister_courses';
-            $params = array('courseids' => $hubcourseids);
-            $serverurl = $huburl . "/local/hub/webservice/webservices.php";
-            $xmlrpcclient = new webservice_xmlrpc_client($serverurl, $hub->token);
-            try {
-                $result = $xmlrpcclient->call($function, $params);
-                //delete the published courses
-                if (!empty($enrollablecourses)) {
-                    $publicationmanager->delete_hub_publications($huburl, 1);
-                }
-                if (!empty($downloadablecourses)) {
-                    $publicationmanager->delete_hub_publications($huburl, 0);
-                }
-            } catch (Exception $e) {
-                $errormessage = $e->getMessage();
-                $errormessage .= html_writer::empty_tag('br') .
-                        get_string('errorunpublishcourses', 'hub');
-                $confirm = false;
-                $cleanregdata = 1;
-            }
-        }
-    }
+if ($unregistration && \core\hub\registration::is_registered()) {
+    $siteunregistrationform = new \core\hub\site_unregistration_form();
 
-    //course unpublish went ok, unregister the site now
-    if ($confirm) {
-        $function = 'hub_unregister_site';
-        $params = array();
-        $serverurl = $huburl . "/local/hub/webservice/webservices.php";
-        $xmlrpcclient = new webservice_xmlrpc_client($serverurl, $hub->token);
-        try {
-            $result = $xmlrpcclient->call($function, $params);
-        } catch (Exception $e) {
-            if (!$cleanregdata) {
-                $errormessage = $e->getMessage();
-                $confirm = false;
-                $cleanregdata = 1;
-            }
+    if ($siteunregistrationform->is_cancelled()) {
+        redirect(new moodle_url('/admin/registration/index.php'));
+    } else if ($data = $siteunregistrationform->get_data()) {
+        if (\core\hub\registration::unregister($data->unpublishalladvertisedcourses,
+            $data->unpublishalluploadedcourses)) {
+            redirect(new moodle_url('/admin/registration/index.php'));
         }
     }
 
-    //check that we are still processing the unregistration,
-    //it could have been unset if an exception were previsouly catched
-    if ($confirm) {
-        $registrationmanager->delete_registeredhub($huburl);
-    }
+    echo $OUTPUT->header();
+    echo $OUTPUT->heading(get_string('unregisterfrom', 'hub', 'Moodle.net'), 3, 'main');
+    $siteunregistrationform->display();
+    echo $OUTPUT->footer();
+    exit;
 }
 
-if (empty($cancel) and $unregistration and !$confirm) {
-
-    echo $OUTPUT->header();
+$siteregistrationform = new \core\hub\site_registration_form();
+if ($fromform = $siteregistrationform->get_data()) {
 
-    //do not check sesskey if confirm = false because this script is linked into email message
-    if (!empty($errormessage)) {
-        echo $OUTPUT->notification(get_string('unregistrationerror', 'hub', $errormessage));
-    }
+    // Save the settings.
+    \core\hub\registration::save_site_info($fromform);
 
-    $hub = $registrationmanager->get_registeredhub($huburl);
-    echo $OUTPUT->heading(get_string('unregisterfrom', 'hub', $hub->hubname), 3, 'main');
-    if ($cleanregdata) {
-        $siteunregistrationform = new site_clean_registration_data_form('',
-                        array('huburl' => $huburl, 'hubname' => $hub->hubname));
+    if (\core\hub\registration::is_registered()) {
+        \core\hub\registration::update_manual();
+        redirect(new moodle_url('/admin/registration/index.php'));
     } else {
-        $siteunregistrationform = new site_unregistration_form('',
-                        array('huburl' => $huburl, 'hubname' => $hub->hubname));
+        \core\hub\registration::register();
+        // This method will redirect away.
     }
 
-    $siteunregistrationform->display();
-} else {
-    $registeredonmoodleorg = false;
-    $moodleorghub = $registrationmanager->get_registeredhub(HUB_MOODLEORGHUBURL);
-    if (!empty($moodleorghub)) {
-        $registeredonmoodleorg = true;
-    }
-
-    // load the hub selector form
-    $hubselectorform = new hub_selector_form();
-    $fromform = $hubselectorform->get_data();
-    $selectedhuburl = optional_param('publichub', false, PARAM_URL);
-    $unlistedhuburl = optional_param('unlistedurl', false, PARAM_TEXT);
-    $password = optional_param('password', '', PARAM_RAW);
-    $registeringhuburl = null;
-    if (!empty($unlistedhuburl)) {
-        if (clean_param($unlistedhuburl, PARAM_URL) !== '') {
-            $registeringhuburl = $unlistedhuburl;
-        }
-    } else if (!empty($selectedhuburl)) {
-        $registeringhuburl = $selectedhuburl;
-    }
+}
 
-    // a hub has been selected, redirect to the hub registration page
-    if (empty($cancel) and !empty($registeringhuburl) and confirm_sesskey()) {
-        $hubname = optional_param(clean_param($registeringhuburl, PARAM_ALPHANUMEXT), '', PARAM_TEXT);
-        $params = array('sesskey' => sesskey(), 'huburl' => $registeringhuburl,
-            'password' => $password, 'hubname' => $hubname);
-        redirect(new moodle_url($CFG->wwwroot . "/" . $CFG->admin . "/registration/register.php",
-                        $params));
-    }
+// OUTPUT SECTION.
 
-    echo $OUTPUT->header();
+echo $OUTPUT->header();
 
-    //check if the site is registered on Moodle.org and display a message about registering on MOOCH
-    $adminrenderer = $PAGE->get_renderer('core', 'admin');
-    echo $adminrenderer->warn_if_not_registered();
+// Current status of registration on Moodle.net.
 
-    //do not check sesskey if confirm = false because this script is linked into email message
-    if (!empty($errormessage)) {
-        echo $OUTPUT->notification(get_string('unregistrationerror', 'hub', $errormessage));
+$notificationtype = \core\output\notification::NOTIFY_ERROR;
+if (\core\hub\registration::is_registered()) {
+    $lastupdated = \core\hub\registration::get_last_updated();
+    if ($lastupdated == 0) {
+        $registrationmessage = get_string('pleaserefreshregistrationunknown', 'admin');
+    } else {
+        $lastupdated = userdate($lastupdated, get_string('strftimedate', 'langconfig'));
+        $registrationmessage = get_string('pleaserefreshregistration', 'admin', $lastupdated);
+        $notificationtype = \core\output\notification::NOTIFY_INFO;
     }
+    echo $OUTPUT->notification($registrationmessage, $notificationtype);
+} else {
+    $registrationmessage = get_string('registrationwarning', 'admin');
+    echo $OUTPUT->notification($registrationmessage, $notificationtype);
+}
 
-    echo $OUTPUT->heading(get_string('registerwith', 'hub'));
+// Heading.
+if (\core\hub\registration::is_registered()) {
+    echo $OUTPUT->heading(get_string('updatesite', 'hub', 'Moodle.net'));
+} else {
+    echo $OUTPUT->heading(get_string('registerwithmoodleorg', 'admin'));
+}
 
-    $hubselectorform->display();
+$renderer = $PAGE->get_renderer('core', 'register');
+echo $renderer->moodleorg_registration_message();
 
-    if (extension_loaded('xmlrpc')) {
-        $hubs = $registrationmanager->get_registered_on_hubs();
-        if (!empty($hubs)) {
-            echo $OUTPUT->heading(get_string('registeredon', 'hub'), 3, 'main');
-            echo $renderer->registeredonhublisting($hubs);
-        }
-    } else { //display notice about xmlrpc
-        $xmlrpcnotification = $OUTPUT->doc_link('admin/environment/php_extension/xmlrpc', '');
-        $xmlrpcnotification .= get_string('xmlrpcdisabledregistration', 'hub');
-        echo $OUTPUT->notification($xmlrpcnotification);
-    }
+$siteregistrationform->display();
+
+if (\core\hub\registration::is_registered()) {
+    // Unregister link.
+    $unregisterhuburl = new moodle_url("/admin/registration/index.php", ['unregistration' => 1]);
+    echo html_writer::div(html_writer::link($unregisterhuburl, get_string('unregister', 'hub')), 'unregister');
 }
 echo $OUTPUT->footer();
index 8d1f8db..72330f6 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-
-
-
-//// SITE PRIVACY /////
-
-/**
- * Site privacy: private
- */
-define('HUB_SITENOTPUBLISHED', 'notdisplayed');
-
-/**
- * Site privacy: public
- */
-define('HUB_SITENAMEPUBLISHED', 'named');
-
-/**
- * Site privacy: public and global
- */
-define('HUB_SITELINKPUBLISHED', 'linked');
-
-/**
- *
- * Site registration library
- *
- * @package   course
- * @copyright 2010 Moodle Pty Ltd (http://moodle.com)
- * @author    Jerome Mouneyrac
- * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class registration_manager {
-
-    /**
-     * Automatically update the registration on all hubs
-     */
-    public function cron() {
-        global $CFG;
-        if (extension_loaded('xmlrpc')) {
-            $function = 'hub_update_site_info';
-            require_once($CFG->dirroot . "/webservice/xmlrpc/lib.php");
-
-            // Update all hubs where the site is registered.
-            $hubs = $this->get_registered_on_hubs();
-            if (empty($hubs)) {
-                mtrace(get_string('registrationwarning', 'admin'));
-            }
-            foreach ($hubs as $hub) {
-                // Update the registration.
-                $siteinfo = $this->get_site_info($hub->huburl);
-                $params = array('siteinfo' => $siteinfo);
-                $serverurl = $hub->huburl . "/local/hub/webservice/webservices.php";
-                $xmlrpcclient = new webservice_xmlrpc_client($serverurl, $hub->token);
-                try {
-                    $result = $xmlrpcclient->call($function, $params);
-                    $this->update_registeredhub($hub); // To update timemodified.
-                    mtrace(get_string('siteupdatedcron', 'hub', $hub->hubname));
-                } catch (Exception $e) {
-                    $errorparam = new stdClass();
-                    $errorparam->errormessage = $e->getMessage();
-                    $errorparam->hubname = $hub->hubname;
-                    mtrace(get_string('errorcron', 'hub', $errorparam));
-                }
-            }
-        } else {
-            mtrace(get_string('errorcronnoxmlrpc', 'hub'));
-        }
-    }
-
-    /**
-     * Return the site secret for a given hub
-     * site identifier is assigned to Mooch
-     * each hub has a unique and personal site secret.
-     * @param string $huburl
-     * @return string site secret
-     */
-    public function get_site_secret_for_hub($huburl) {
-        global $DB;
-
-        $existingregistration = $DB->get_record('registration_hubs',
-                    array('huburl' => $huburl));
-
-        if (!empty($existingregistration)) {
-            return $existingregistration->secret;
-        }
-
-        if ($huburl == HUB_MOODLEORGHUBURL) {
-            $siteidentifier =  get_site_identifier();
-        } else {
-            $siteidentifier = random_string(32) . $_SERVER['HTTP_HOST'];
-        }
-
-        return $siteidentifier;
-
-    }
-
-    /**
-     * When the site register on a hub, he must call this function
-     * @param object $hub where the site is registered on
-     * @return integer id of the record
-     */
-    public function add_registeredhub($hub) {
-        global $DB;
-        $hub->timemodified = time();
-        $id = $DB->insert_record('registration_hubs', $hub);
-        return $id;
-    }
-
-    /**
-     * When a site unregister from a hub, he must call this function
-     * @param string $huburl the huburl to delete
-     */
-    public function delete_registeredhub($huburl) {
-        global $DB;
-        $DB->delete_records('registration_hubs', array('huburl' => $huburl));
-    }
-
-    /**
-     * Get a hub on which the site is registered for a given url or token
-     * Mostly use to check if the site is registered on a specific hub
-     * @param string $huburl
-     * @param string $token
-     * @return object the  hub
-     */
-    public function get_registeredhub($huburl = null, $token = null) {
-        global $DB;
-
-        $params = array();
-        if (!empty($huburl)) {
-            $params['huburl'] = $huburl;
-        }
-        if (!empty($token)) {
-            $params['token'] = $token;
-        }
-        $params['confirmed'] = 1;
-        $token = $DB->get_record('registration_hubs', $params);
-        return $token;
-    }
-
-    /**
-     * Get the hub which has not confirmed that the site is registered on,
-     * but for which a request has been sent
-     * @param string $huburl
-     * @return object the  hub
-     */
-    public function get_unconfirmedhub($huburl) {
-        global $DB;
-
-        $params = array();
-        $params['huburl'] = $huburl;
-        $params['confirmed'] = 0;
-        $token = $DB->get_record('registration_hubs', $params);
-        return $token;
-    }
-
-    /**
-     * Update a registered hub (mostly use to update the confirmation status)
-     * @param object $hub the hub
-     */
-    public function update_registeredhub($hub) {
-        global $DB;
-        $hub->timemodified = time();
-        $DB->update_record('registration_hubs', $hub);
-    }
-
-    /**
-     * Return all hubs where the site is registered
-     */
-    public function get_registered_on_hubs() {
-        global $DB;
-        $hubs = $DB->get_records('registration_hubs', array('confirmed' => 1));
-        return $hubs;
-    }
-
-    /**
-     * Return site information for a specific hub
-     * @param string $huburl
-     * @return array site info
-     */
-    public function get_site_info($huburl) {
-        global $CFG, $DB;
-
-        $siteinfo = array();
-        $cleanhuburl = clean_param($huburl, PARAM_ALPHANUMEXT);
-        $siteinfo['name'] = get_config('hub', 'site_name_' . $cleanhuburl);
-        $siteinfo['description'] = get_config('hub', 'site_description_' . $cleanhuburl);
-        $siteinfo['contactname'] = get_config('hub', 'site_contactname_' . $cleanhuburl);
-        $siteinfo['contactemail'] = get_config('hub', 'site_contactemail_' . $cleanhuburl);
-        $siteinfo['contactphone'] = get_config('hub', 'site_contactphone_' . $cleanhuburl);
-        $siteinfo['imageurl'] = get_config('hub', 'site_imageurl_' . $cleanhuburl);
-        $siteinfo['privacy'] = get_config('hub', 'site_privacy_' . $cleanhuburl);
-        $siteinfo['street'] = get_config('hub', 'site_address_' . $cleanhuburl);
-        $siteinfo['regioncode'] = get_config('hub', 'site_region_' . $cleanhuburl);
-        $siteinfo['countrycode'] = get_config('hub', 'site_country_' . $cleanhuburl);
-        $siteinfo['geolocation'] = get_config('hub', 'site_geolocation_' . $cleanhuburl);
-        $siteinfo['contactable'] = get_config('hub', 'site_contactable_' . $cleanhuburl);
-        $siteinfo['emailalert'] = get_config('hub', 'site_emailalert_' . $cleanhuburl);
-        if (get_config('hub', 'site_coursesnumber_' . $cleanhuburl) == -1) {
-            $coursecount = -1;
-        } else {
-            $coursecount = $DB->count_records('course') - 1;
-        }
-        $siteinfo['courses'] = $coursecount;
-        if (get_config('hub', 'site_usersnumber_' . $cleanhuburl) == -1) {
-            $usercount = -1;
-        } else {
-            $usercount = $DB->count_records('user', array('deleted' => 0));
-        }
-        $siteinfo['users'] = $usercount;
-
-        if (get_config('hub', 'site_roleassignmentsnumber_' . $cleanhuburl) == -1) {
-            $roleassigncount = -1;
-        } else {
-            $roleassigncount = $DB->count_records('role_assignments');
-        }
-        $siteinfo['enrolments'] = $roleassigncount;
-        if (get_config('hub', 'site_postsnumber_' . $cleanhuburl) == -1) {
-            $postcount = -1;
-        } else {
-            $postcount = $DB->count_records('forum_posts');
-        }
-        $siteinfo['posts'] = $postcount;
-        if (get_config('hub', 'site_questionsnumber_' . $cleanhuburl) == -1) {
-            $questioncount = -1;
-        } else {
-            $questioncount = $DB->count_records('question');
-        }
-        $siteinfo['questions'] = $questioncount;
-        if (get_config('hub', 'site_resourcesnumber_' . $cleanhuburl) == -1) {
-            $resourcecount = -1;
-        } else {
-            $resourcecount = $DB->count_records('resource');
-        }
-        $siteinfo['resources'] = $resourcecount;
-        // Badge statistics.
-        require_once($CFG->libdir . '/badgeslib.php');
-        if (get_config('hub', 'site_badges_' . $cleanhuburl) == -1) {
-            $badges = -1;
-        } else {
-            $badges = $DB->count_records_select('badge', 'status <> ' . BADGE_STATUS_ARCHIVED);
-        }
-        $siteinfo['badges'] = $badges;
-        if (get_config('hub', 'site_issuedbadges_' . $cleanhuburl) == -1) {
-            $issuedbadges = -1;
-        } else {
-            $issuedbadges = $DB->count_records('badge_issued');
-        }
-        $siteinfo['issuedbadges'] = $issuedbadges;
-        //TODO
-        require_once($CFG->dirroot . "/course/lib.php");
-        if (get_config('hub', 'site_participantnumberaverage_' . $cleanhuburl) == -1) {
-            $participantnumberaverage = -1;
-        } else {
-            $participantnumberaverage = average_number_of_participants();
-        }
-        $siteinfo['participantnumberaverage'] = $participantnumberaverage;
-        if (get_config('hub', 'site_modulenumberaverage_' . $cleanhuburl) == -1) {
-            $modulenumberaverage = -1;
-        } else {
-            $modulenumberaverage = average_number_of_courses_modules();
-        }
-        $siteinfo['modulenumberaverage'] = $modulenumberaverage;
-        $siteinfo['language'] = get_config('hub', 'site_language_' . $cleanhuburl);
-        $siteinfo['moodleversion'] = $CFG->version;
-        $siteinfo['moodlerelease'] = $CFG->release;
-        $siteinfo['url'] = $CFG->wwwroot;
-        // Mobile related information.
-        $siteinfo['mobileservicesenabled'] = 0;
-        $siteinfo['mobilenotificationsenabled'] = 0;
-        $siteinfo['registereduserdevices'] = 0;
-        $siteinfo['registeredactiveuserdevices'] = 0;
-        if (!empty($CFG->enablewebservices) && !empty($CFG->enablemobilewebservice)) {
-            $siteinfo['mobileservicesenabled'] = 1;
-            $siteinfo['registereduserdevices'] = $DB->count_records('user_devices');
-            $airnotifierextpath = $CFG->dirroot . '/message/output/airnotifier/externallib.php';
-            if (file_exists($airnotifierextpath)) { // Maybe some one uninstalled the plugin.
-                require_once($airnotifierextpath);
-                $siteinfo['mobilenotificationsenabled'] = message_airnotifier_external::is_system_configured();
-                $siteinfo['registeredactiveuserdevices'] = $DB->count_records('message_airnotifier_devices', array('enable' => 1));
-            }
-        }
-
-        return $siteinfo;
-    }
-
-    /**
-     * Retrieve the site privacy string matching the define value
-     * @param string $privacy must match the define into moodlelib.php
-     * @return string
-     */
-    public function get_site_privacy_string($privacy) {
-        switch ($privacy) {
-            case HUB_SITENOTPUBLISHED:
-                $privacystring = get_string('siteprivacynotpublished', 'hub');
-                break;
-            case HUB_SITENAMEPUBLISHED:
-                $privacystring = get_string('siteprivacypublished', 'hub');
-                break;
-            case HUB_SITELINKPUBLISHED:
-                $privacystring = get_string('siteprivacylinked', 'hub');
-                break;
-        }
-        if (empty($privacystring)) {
-            throw new moodle_exception('unknownprivacy');
-        }
-        return $privacystring;
-    }
-
-}
-?>
+defined('MOODLE_INTERNAL') || die();
index 2b7cf96..ee2d534 100644 (file)
@@ -20,7 +20,7 @@
 //                                                                       //
 ///////////////////////////////////////////////////////////////////////////
 
-/*
+/**
  * @package    moodle
  * @subpackage registration
  * @author     Jerome Mouneyrac <jerome@mouneyrac.com>
 
 
 require_once('../../config.php');
-require_once($CFG->libdir . '/adminlib.php');
-require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/forms.php');
-require_once($CFG->dirroot . '/webservice/lib.php');
-require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
 
-require_sesskey();
-
-$huburl = required_param('huburl', PARAM_URL);
-$huburl = rtrim($huburl, "/");
-
-if ($huburl == HUB_MOODLEORGHUBURL) { // register to Moodle.org
-    admin_externalpage_setup('registrationmoodleorg');
-} else { //register to a hub
-    admin_externalpage_setup('registrationhub');
-}
-
-$password = optional_param('password', '', PARAM_TEXT);
-$hubname = optional_param('hubname', '', PARAM_TEXT);
-
-$registrationmanager = new registration_manager();
-
-$registeredhub = $registrationmanager->get_registeredhub($huburl);
-
-$siteregistrationform = new site_registration_form('',
-                array('alreadyregistered' => !empty($registeredhub->token),
-                    'huburl' => $huburl, 'hubname' => $hubname,
-                    'password' => $password));
-$fromform = $siteregistrationform->get_data();
-
-if (!empty($fromform) and confirm_sesskey()) {
-
-    // Set to -1 all optional data marked as "don't send" by the admin.
-    // The function get_site_info() will not calculate the optional data if config is set to -1.
-    $inputnames = array('courses', 'users', 'roleassignments', 'posts', 'questions', 'resources',
-        'badges', 'issuedbadges', 'modulenumberaverage', 'participantnumberaverage',
-        'mobileservicesenabled', 'mobilenotificationsenabled', 'registereduserdevices', 'registeredactiveuserdevices');
-    foreach ($inputnames as $inputname) {
-        if (empty($fromform->{$inputname})) {
-            $fromform->{$inputname} = -1;
-        }
-    }
-
-    // Save the settings.
-    $cleanhuburl = clean_param($huburl, PARAM_ALPHANUMEXT);
-    set_config('site_name_' . $cleanhuburl, $fromform->name, 'hub');
-    set_config('site_description_' . $cleanhuburl, $fromform->description, 'hub');
-    set_config('site_contactname_' . $cleanhuburl, $fromform->contactname, 'hub');
-    set_config('site_contactemail_' . $cleanhuburl, $fromform->contactemail, 'hub');
-    set_config('site_contactphone_' . $cleanhuburl, $fromform->contactphone, 'hub');
-    set_config('site_imageurl_' . $cleanhuburl, $fromform->imageurl, 'hub');
-    set_config('site_privacy_' . $cleanhuburl, $fromform->privacy, 'hub');
-    set_config('site_address_' . $cleanhuburl, $fromform->address, 'hub');
-    set_config('site_region_' . $cleanhuburl, $fromform->regioncode, 'hub');
-    set_config('site_country_' . $cleanhuburl, $fromform->countrycode, 'hub');
-    set_config('site_language_' . $cleanhuburl, $fromform->language, 'hub');
-    set_config('site_geolocation_' . $cleanhuburl, $fromform->geolocation, 'hub');
-    set_config('site_contactable_' . $cleanhuburl, $fromform->contactable, 'hub');
-    set_config('site_emailalert_' . $cleanhuburl, $fromform->emailalert, 'hub');
-    set_config('site_coursesnumber_' . $cleanhuburl, $fromform->courses, 'hub');
-    set_config('site_usersnumber_' . $cleanhuburl, $fromform->users, 'hub');
-    set_config('site_roleassignmentsnumber_' . $cleanhuburl, $fromform->roleassignments, 'hub');
-    set_config('site_postsnumber_' . $cleanhuburl, $fromform->posts, 'hub');
-    set_config('site_questionsnumber_' . $cleanhuburl, $fromform->questions, 'hub');
-    set_config('site_resourcesnumber_' . $cleanhuburl, $fromform->resources, 'hub');
-    set_config('site_badges_' . $cleanhuburl, $fromform->badges, 'hub');
-    set_config('site_issuedbadges_' . $cleanhuburl, $fromform->issuedbadges, 'hub');
-    set_config('site_modulenumberaverage_' . $cleanhuburl, $fromform->modulenumberaverage, 'hub');
-    set_config('site_participantnumberaverage_' . $cleanhuburl, $fromform->participantnumberaverage, 'hub');
-    set_config('site_mobileservicesenabled_' . $cleanhuburl, $fromform->mobileservicesenabled, 'hub');
-    set_config('site_mobilenotificationsenabled_' . $cleanhuburl, $fromform->mobilenotificationsenabled, 'hub');
-    set_config('site_registereduserdevices_' . $cleanhuburl, $fromform->registereduserdevices, 'hub');
-    set_config('site_registeredactiveuserdevices_' . $cleanhuburl, $fromform->registeredactiveuserdevices, 'hub');
-}
-
-/////// UPDATE ACTION ////////
-
-// update the hub registration
-$update = optional_param('update', 0, PARAM_INT);
-if ($update and confirm_sesskey()) {
-
-    //update the registration
-    $function = 'hub_update_site_info';
-    $siteinfo = $registrationmanager->get_site_info($huburl);
-    $params = array('siteinfo' => $siteinfo);
-    $serverurl = $huburl . "/local/hub/webservice/webservices.php";
-    require_once($CFG->dirroot . "/webservice/xmlrpc/lib.php");
-    $xmlrpcclient = new webservice_xmlrpc_client($serverurl, $registeredhub->token);
-    try {
-        $result = $xmlrpcclient->call($function, $params);
-        $registrationmanager->update_registeredhub($registeredhub); // To update timemodified.
-    } catch (Exception $e) {
-        $error = $OUTPUT->notification(get_string('errorregistration', 'hub', $e->getMessage()));
-    }
-}
-
-/////// FORM REGISTRATION ACTION //////
-
-if (!empty($fromform) and empty($update) and confirm_sesskey()) {
-
-    if (!empty($fromform) and confirm_sesskey()) { // if the register button has been clicked
-
-        // Retrieve the optional info (specially course number, user number, module number average...).
-        $siteinfo = $registrationmanager->get_site_info($huburl);
-        $fromform->courses = $siteinfo['courses'];
-        $fromform->users = $siteinfo['users'];
-        $fromform->enrolments = $siteinfo['enrolments'];
-        $fromform->posts = $siteinfo['posts'];
-        $fromform->questions = $siteinfo['questions'];
-        $fromform->resources = $siteinfo['resources'];
-        $fromform->badges = $siteinfo['badges'];
-        $fromform->issuedbadges = $siteinfo['issuedbadges'];
-        $fromform->modulenumberaverage = $siteinfo['modulenumberaverage'];
-        $fromform->participantnumberaverage = $siteinfo['participantnumberaverage'];
-        $fromform->street = $siteinfo['street'];
-        $fromform->mobileservicesenabled = $siteinfo['mobileservicesenabled'];
-        $fromform->mobilenotificationsenabled = $siteinfo['mobilenotificationsenabled'];
-        $fromform->registereduserdevices = $siteinfo['registereduserdevices'];
-        $fromform->registeredactiveuserdevices = $siteinfo['registeredactiveuserdevices'];
-
-        $params = (array) $fromform; //we are using the form input as the redirection parameters (token, url and name)
-
-        $unconfirmedhub = $registrationmanager->get_unconfirmedhub($huburl);
-        if (empty($unconfirmedhub)) {
-            //we save the token into the communication table in order to have a reference
-            $unconfirmedhub = new stdClass();
-            $unconfirmedhub->token = $registrationmanager->get_site_secret_for_hub($huburl);
-            $unconfirmedhub->secret = $unconfirmedhub->token;
-            $unconfirmedhub->huburl = $huburl;
-            $unconfirmedhub->hubname = $hubname;
-            $unconfirmedhub->confirmed = 0;
-            $unconfirmedhub->id = $registrationmanager->add_registeredhub($unconfirmedhub);
-        }
-
-        $params['token'] = $unconfirmedhub->token;
-        $params['url'] = $CFG->wwwroot;
-        redirect(new moodle_url($huburl . '/local/hub/siteregistration.php', $params));
-    }
-}
-
-/////// OUTPUT SECTION /////////////
-
-echo $OUTPUT->header();
-//Display update notification result
-if (!empty($registeredhub->confirmed)) {
-    if (!empty($result)) {
-        echo $OUTPUT->notification(get_string('siteregistrationupdated', 'hub'), 'notifysuccess');
-    }
-}
-
-if (!empty($error)) {
-    echo $error;
-}
-
-// Some Moodle.org registration explanation.
-if ($huburl == HUB_MOODLEORGHUBURL) {
-    $notificationtype = \core\output\notification::NOTIFY_ERROR;
-    if (!empty($registeredhub->token)) {
-        if ($registeredhub->timemodified == 0) {
-            $registrationmessage = get_string('pleaserefreshregistrationunknown', 'admin');
-        } else {
-            $lastupdated = userdate($registeredhub->timemodified, get_string('strftimedate', 'langconfig'));
-            $registrationmessage = get_string('pleaserefreshregistration', 'admin', $lastupdated);
-            $notificationtype = \core\output\notification::NOTIFY_INFO;
-        }
-    } else {
-        $registrationmessage = get_string('registrationwarning', 'admin');
-    }
-    echo $OUTPUT->notification($registrationmessage, $notificationtype);
-
-    echo $OUTPUT->heading(get_string('registerwithmoodleorg', 'admin'));
-    $renderer = $PAGE->get_renderer('core', 'register');
-    echo $renderer->moodleorg_registration_message();
-}
-
-$siteregistrationform->display();
-echo $OUTPUT->footer();
+redirect(new moodle_url('/admin/registration/index.php'));
\ No newline at end of file
index 09d2735..196d680 100644 (file)
@@ -46,50 +46,4 @@ class core_register_renderer extends plugin_renderer_base {
         $moodleorgregmsg .= html_writer::alist($items);
         return $moodleorgregmsg;
     }
-
-    /**
-     * Display a box message confirming a site registration (add or update)
-     * @param string $confirmationmessage
-     * @return string
-     */
-    public function registration_confirmation($confirmationmessage) {
-        $linktositelist = html_writer::tag('a', get_string('sitelist', 'hub'),
-                        array('href' => new moodle_url('/local/hub/index.php')));
-        $message = $confirmationmessage . html_writer::empty_tag('br') . $linktositelist;
-        return $this->output->box($message);
-    }
-
-    /**
-     * Display the listing of registered on hub
-     */
-    public function registeredonhublisting($hubs) {
-        global $CFG;
-        $table = new html_table();
-        $table->head = array(get_string('hub', 'hub'), get_string('operation', 'hub'));
-        $table->size = array('80%', '20%');
-
-        foreach ($hubs as $hub) {
-            if ($hub->huburl == HUB_MOODLEORGHUBURL) {
-                $hub->hubname = get_string('registeredmoodleorg', 'hub', $hub->hubname);
-            }
-            $hublink = html_writer::tag('a', $hub->hubname, array('href' => $hub->huburl));
-            $hublinkcell = html_writer::tag('div', $hublink, array('class' => 'registeredhubrow'));
-
-            $unregisterhuburl = new moodle_url("/" . $CFG->admin . "/registration/index.php",
-                            array('sesskey' => sesskey(), 'huburl' => $hub->huburl,
-                                'unregistration' => 1));
-            $unregisterbutton = new single_button($unregisterhuburl,
-                            get_string('unregister', 'hub'));
-            $unregisterbutton->class = 'centeredbutton';
-            $unregisterbuttonhtml = $this->output->render($unregisterbutton);
-
-            //add button cells
-            $cells = array($hublinkcell, $unregisterbuttonhtml);
-            $row = new html_table_row($cells);
-            $table->data[] = $row;
-        }
-
-        return html_writer::table($table);
-    }
-
 }
index dd15463..7926e0f 100644 (file)
@@ -20,7 +20,7 @@
 //                                                                       //
 ///////////////////////////////////////////////////////////////////////////
 
-/*
+/**
  * @package    moodle
  * @subpackage registration
  * @author     Jerome Mouneyrac <jerome@mouneyrac.com>
 
 require('../../config.php');
 require_once($CFG->libdir . '/adminlib.php');
-require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
 
 $url = optional_param('url', '', PARAM_URL);
-$hubname = optional_param('hubname', '', PARAM_TEXT);
 $token = optional_param('token', '', PARAM_TEXT);
 
-admin_externalpage_setup('registrationhubs');
+admin_externalpage_setup('registrationmoodleorg');
 
-//check that we are waiting a confirmation from this hub, and check that the token is correct
-$registrationmanager = new registration_manager();
-$registeredhub = $registrationmanager->get_unconfirmedhub($url);
-if (!empty($registeredhub) and $registeredhub->token == $token) {
-
-    echo $OUTPUT->header();
-    echo $OUTPUT->heading(get_string('renewregistration', 'hub'), 3, 'main');
-    $hublink = html_writer::tag('a', $hubname, array('href' => $url));
+if ($url !== HUB_MOODLEORGHUBURL) {
+    throw new moodle_exception('errorotherhubsnotsupported', 'hub');
+}
 
-    $registrationmanager->delete_registeredhub($url);
+// Check that we are waiting a confirmation from this hub, and check that the token is correct.
+\core\hub\registration::reset_site_identifier($token);
 
-    //Mooch case, need to recreate the siteidentifier
-    if ($url == HUB_MOODLEORGHUBURL) {
-        $CFG->siteidentifier = null;
-        get_site_identifier();
-    }
+echo $OUTPUT->header();
+echo $OUTPUT->heading(get_string('renewregistration', 'hub'), 3, 'main');
+$hublink = html_writer::tag('a', 'Moodle.net', array('href' => HUB_MOODLEORGHUBURL));
 
-    $deletedregmsg = get_string('previousregistrationdeleted', 'hub', $hublink);
+$deletedregmsg = get_string('previousregistrationdeleted', 'hub', $hublink);
 
-    $button = new single_button(new moodle_url('/admin/registration/index.php'),
-                    get_string('restartregistration', 'hub'));
-    $button->class = 'restartregbutton';
+$button = new single_button(new moodle_url('/admin/registration/index.php'),
+                get_string('restartregistration', 'hub'));
+$button->class = 'restartregbutton';
 
-    echo html_writer::tag('div', $deletedregmsg . $OUTPUT->render($button),
-            array('class' => 'mdl-align'));
+echo html_writer::tag('div', $deletedregmsg . $OUTPUT->render($button),
+        array('class' => 'mdl-align'));
 
-    echo $OUTPUT->footer();
-} else {
-    throw new moodle_exception('wrongtoken', 'hub',
-            $CFG->wwwroot . '/' . $CFG->admin . '/registration/index.php');
-}
+echo $OUTPUT->footer();
 
 
index 561b24a..7dd4808 100644 (file)
@@ -805,8 +805,7 @@ class core_admin_renderer extends plugin_renderer_base {
         if (!$registered) {
 
             if (has_capability('moodle/site:config', context_system::instance())) {
-                $registerbutton = $this->single_button(new moodle_url('/admin/registration/register.php',
-                    array('huburl' =>  HUB_MOODLEORGHUBURL, 'hubname' => 'Moodle.net')),
+                $registerbutton = $this->single_button(new moodle_url('/admin/registration/index.php'),
                     get_string('register', 'admin'));
                 $str = 'registrationwarning';
             } else {
@@ -828,10 +827,7 @@ class core_admin_renderer extends plugin_renderer_base {
      * @return string
      */
     public function warn_if_not_registered() {
-        global $CFG;
-        require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
-        $registrationmanager = new registration_manager();
-        return $this->registration_warning($registrationmanager->get_registeredhub(HUB_MOODLEORGHUBURL) ? true : false);
+        return $this->registration_warning(\core\hub\registration::is_registered());
     }
 
     /**
index 3d28719..e8247c8 100644 (file)
@@ -26,7 +26,7 @@ defined('MOODLE_INTERNAL') || die();
 
 if ($hassiteconfig) {
     $settings = new admin_settingpage('analyticssettings', new lang_string('analyticssettings', 'analytics'));
-    $ADMIN->add('appearance', $settings);
+    $ADMIN->add('analytics', $settings);
 
     if ($ADMIN->fulltree) {
         // Select the site prediction's processor.
index 32af104..c0d57c3 100644 (file)
@@ -12,6 +12,8 @@ $temp->add(new admin_setting_configexecutable('pathtodu', new lang_string('patht
 $temp->add(new admin_setting_configexecutable('aspellpath', new lang_string('aspellpath', 'admin'), new lang_string('edhelpaspellpath'), ''));
 $temp->add(new admin_setting_configexecutable('pathtodot', new lang_string('pathtodot', 'admin'), new lang_string('pathtodot_help', 'admin'), ''));
 $temp->add(new admin_setting_configexecutable('pathtogs', new lang_string('pathtogs', 'admin'), new lang_string('pathtogs_help', 'admin'), '/usr/bin/gs'));
+$temp->add(new admin_setting_configexecutable('pathtopython', new lang_string('pathtopython', 'admin'),
+    new lang_string('pathtopythondesc', 'admin'), ''));
 $ADMIN->add('server', $temp);
 
 
@@ -209,9 +211,6 @@ $temp->add(new admin_setting_configtext('curltimeoutkbitrate', new lang_string('
 $ADMIN->add('server', $temp);
 
 
-$ADMIN->add('server', new admin_externalpage('adminregistration', new lang_string('hubs', 'admin'),
-    "$CFG->wwwroot/$CFG->admin/registration/index.php"));
-
 // E-mail settings.
 $ADMIN->add('server', new admin_category('email', new lang_string('categoryemail', 'admin')));
 
index c78c909..17621cb 100644 (file)
@@ -11,14 +11,7 @@ $hassiteconfig = has_capability('moodle/site:config', $systemcontext);
 $ADMIN->add('root', new admin_externalpage('adminnotifications', new lang_string('notifications'), "$CFG->wwwroot/$CFG->admin/index.php"));
 
 $ADMIN->add('root', new admin_externalpage('registrationmoodleorg', new lang_string('registration', 'admin'),
-        "$CFG->wwwroot/$CFG->admin/registration/register.php?huburl=" . HUB_MOODLEORGHUBURL . "&hubname=Moodle.net&sesskey=" . sesskey()));
-$ADMIN->add('root', new admin_externalpage('registrationhub', new lang_string('registerwith', 'hub'),
-        "$CFG->wwwroot/$CFG->admin/registration/register.php", 'moodle/site:config', true));
-$ADMIN->add('root', new admin_externalpage('registrationhubs', new lang_string('hubs', 'admin'),
-        "$CFG->wwwroot/$CFG->admin/registration/index.php", 'moodle/site:config', true));
-$ADMIN->add('root', new admin_externalpage('siteregistrationconfirmed',
-        new lang_string('registrationconfirmed', 'hub'),
-        $CFG->wwwroot."/".$CFG->admin."/registration/confirmregistration.php", 'moodle/site:config', true));
+        new moodle_url("/admin/registration/index.php")));
  // hidden upgrade script
 $ADMIN->add('root', new admin_externalpage('upgradesettings', new lang_string('upgradesettings', 'admin'), "$CFG->wwwroot/$CFG->admin/upgradesettings.php", 'moodle/site:config', true));
 
@@ -30,6 +23,7 @@ if ($hassiteconfig) {
 $ADMIN->add('root', new admin_category('users', new lang_string('users','admin')));
 $ADMIN->add('root', new admin_category('courses', new lang_string('courses','admin')));
 $ADMIN->add('root', new admin_category('grades', new lang_string('grades')));
+$ADMIN->add('root', new admin_category('analytics', new lang_string('analytics', 'analytics')));
 $ADMIN->add('root', new admin_category('competencies', new lang_string('competencies', 'core_competency')));
 $ADMIN->add('root', new admin_category('badges', new lang_string('badges'), empty($CFG->enablebadges)));
 $ADMIN->add('root', new admin_category('location', new lang_string('location','admin')));
index 76a1bde..aad459a 100644 (file)
@@ -24,5 +24,5 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$ADMIN->add('reports', new admin_externalpage('analyticmodels', get_string('analyticmodels', 'tool_analytics'),
+$ADMIN->add('analytics', new admin_externalpage('analyticmodels', get_string('analyticmodels', 'tool_analytics'),
     "$CFG->wwwroot/$CFG->admin/tool/analytics/index.php", 'moodle/analytics:managemodels'));
index 2fc0bfe..7d1674a 100644 (file)
@@ -152,10 +152,11 @@ class api {
         $url = new moodle_url("/$CFG->admin/tool/mobile/launch.php");
         $settings['launchurl'] = $url->out(false);
 
-        if ($logourl = $OUTPUT->get_logo_url()) {
+        // Check that we are receiving a moodle_url object, themes can override get_logo_url and may return incorrect values.
+        if (($logourl = $OUTPUT->get_logo_url()) && $logourl instanceof moodle_url) {
             $settings['logourl'] = $logourl->out(false);
         }
-        if ($compactlogourl = $OUTPUT->get_compact_logo_url()) {
+        if (($compactlogourl = $OUTPUT->get_compact_logo_url()) && $compactlogourl instanceof moodle_url) {
             $settings['compactlogourl'] = $compactlogourl->out(false);
         }
 
@@ -210,12 +211,17 @@ class api {
         }
 
         if (empty($section) or $section == 'sitepolicies') {
+            $settings->sitepolicy = $CFG->sitepolicy;
             $settings->disableuserimages = $CFG->disableuserimages;
         }
 
         if (empty($section) or $section == 'gradessettings') {
             require_once($CFG->dirroot . '/user/lib.php');
-            $settings->mygradesurl = user_mygrades_url()->out(false);
+            $settings->mygradesurl = user_mygrades_url();
+            // The previous function may return moodle_url instances or plain string URLs.
+            if ($settings->mygradesurl instanceof moodle_url) {
+                $settings->mygradesurl = $settings->mygradesurl->out(false);
+            }
         }
 
         if (empty($section) or $section == 'mobileapp') {
index 126ea1c..328011a 100644 (file)
@@ -123,6 +123,10 @@ class tool_mobile_external_testcase extends externallib_advanced_testcase {
         require_once($CFG->dirroot . '/course/format/lib.php');
 
         $this->resetAfterTest(true);
+
+        $mysitepolicy = 'http://mysite.is/policy/';
+        set_config('sitepolicy', $mysitepolicy);
+
         $result = external::get_config();
         $result = external_api::clean_returnvalue(external::get_config_returns(), $result);
 
@@ -143,6 +147,7 @@ class tool_mobile_external_testcase extends externallib_advanced_testcase {
             array('name' => 'numsections', 'value' => course_get_format($SITE)->get_last_section_number()),
             array('name' => 'newsitems', 'value' => $SITE->newsitems),
             array('name' => 'commentsperpage', 'value' => $CFG->commentsperpage),
+            array('name' => 'sitepolicy', 'value' => $mysitepolicy),
             array('name' => 'disableuserimages', 'value' => $CFG->disableuserimages),
             array('name' => 'mygradesurl', 'value' => user_mygrades_url()->out(false)),
             array('name' => 'tool_mobile_forcelogout', 'value' => 0),
index d951a2f..a36ceb3 100644 (file)
@@ -137,7 +137,7 @@ class auth_email_external extends external_api {
                      new external_value(PARAM_NOTAGS, 'The order of the name fields')
                 ),
                 'passwordpolicy' => new external_value(PARAM_RAW, 'Password policy', VALUE_OPTIONAL),
-                'sitepolicy' => new external_value(PARAM_URL, 'Site policy url', VALUE_OPTIONAL),
+                'sitepolicy' => new external_value(PARAM_RAW, 'Site policy', VALUE_OPTIONAL),
                 'defaultcity' => new external_value(PARAM_NOTAGS, 'Default city', VALUE_OPTIONAL),
                 'country' => new external_value(PARAM_ALPHA, 'Default country', VALUE_OPTIONAL),
                 'profilefields' => new external_multiple_structure(
index 122408f..af22ff5 100644 (file)
@@ -529,7 +529,7 @@ class backup_enrolments_structure_step extends backup_structure_step {
         $enrol->annotate_ids('role', 'roleid');
 
         // Add enrol plugin structure.
-        $this->add_plugin_structure('enrol', $enrol, false);
+        $this->add_plugin_structure('enrol', $enrol, true);
 
         return $enrolments;
     }
index d27cb07..bc13ad2 100644 (file)
@@ -31,7 +31,6 @@
 require('../../config.php');
 require_once($CFG->dirroot . '/blocks/community/locallib.php');
 require_once($CFG->dirroot . '/blocks/community/forms.php');
-require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
 
 require_login();
 $courseid = required_param('courseid', PARAM_INT); //if no courseid is given
@@ -48,21 +47,8 @@ $PAGE->navbar->add(get_string('searchcourse', 'block_community'));
 $search = optional_param('search', null, PARAM_TEXT);
 
 //if no capability to search course, display an error message
-$usercansearch = has_capability('moodle/community:add', $context);
+require_capability('moodle/community:add', $context);
 $usercandownload = has_capability('moodle/community:download', $context);
-if (empty($usercansearch)) {
-    $notificationerror = get_string('cannotsearchcommunity', 'hub');
-} else if (!extension_loaded('xmlrpc')) {
-    $notificationerror = $OUTPUT->doc_link('admin/environment/php_extension/xmlrpc', '');
-    $notificationerror .= get_string('xmlrpcdisabledcommunity', 'hub');
-}
-if (!empty($notificationerror)) {
-    echo $OUTPUT->header();
-    echo $OUTPUT->heading(get_string('searchcommunitycourse', 'block_community'), 3, 'main');
-    echo $OUTPUT->notification($notificationerror);
-    echo $OUTPUT->footer();
-    die();
-}
 
 $communitymanager = new block_community_manager();
 $renderer = $PAGE->get_renderer('block_community');
@@ -93,17 +79,11 @@ if ($usercandownload and $cancelrestore and confirm_sesskey()) {
 }
 
 /// Download
-$huburl = optional_param('huburl', false, PARAM_URL);
 $download = optional_param('download', -1, PARAM_INT);
 $downloadcourseid = optional_param('downloadcourseid', '', PARAM_INT);
 $coursefullname = optional_param('coursefullname', '', PARAM_ALPHANUMEXT);
 $backupsize = optional_param('backupsize', 0, PARAM_INT);
 if ($usercandownload and $download != -1 and !empty($downloadcourseid) and confirm_sesskey()) {
-    $course = new stdClass();
-    $course->fullname = $coursefullname;
-    $course->id = $downloadcourseid;
-    $course->huburl = $huburl;
-
     //OUTPUT: display restore choice page
     echo $OUTPUT->header();
     echo $OUTPUT->heading(get_string('downloadingcourse', 'block_community'), 3, 'main');
@@ -115,12 +95,12 @@ if ($usercandownload and $download != -1 and !empty($downloadcourseid) and confi
         ob_flush();
     }
     flush();
-    $filenames = $communitymanager->block_community_download_course_backup($course);
+    list($privatefilename, $tmpfilename) = \core\hub\publication::download_course_backup($downloadcourseid, $coursefullname);
     echo html_writer::tag('div', get_string('downloaded', 'block_community'),
             array('class' => 'textinfo'));
     echo $OUTPUT->notification(get_string('downloadconfirmed', 'block_community',
-                    '/downloaded_backup/' . $filenames['privatefile']), 'notifysuccess');
-    echo $renderer->restore_confirmation_box($filenames['tmpfile'], $context);
+                    $privatefilename), 'notifysuccess');
+    echo $renderer->restore_confirmation_box($tmpfilename, $context);
     echo $OUTPUT->footer();
     die();
 }
@@ -145,7 +125,6 @@ $fromformdata['language'] = optional_param('language', current_language(), PARAM
 $fromformdata['educationallevel'] = optional_param('educationallevel', 'all', PARAM_ALPHANUMEXT);
 $fromformdata['downloadable'] = optional_param('downloadable', $usercandownload, PARAM_ALPHANUM);
 $fromformdata['orderby'] = optional_param('orderby', 'newest', PARAM_ALPHA);
-$fromformdata['huburl'] = optional_param('huburl', HUB_MOODLEORGHUBURL, PARAM_URL);
 $fromformdata['search'] = $search;
 $fromformdata['courseid'] = $courseid;
 $hubselectorform = new community_hub_search_form('', $fromformdata);
@@ -181,35 +160,14 @@ if (optional_param('executesearch', 0, PARAM_INT) and confirm_sesskey()) {
     //the range of course requested
     $options->givememore = optional_param('givememore', 0, PARAM_INT);
 
-    //check if the selected hub is from the registered list (in this case we use the private token)
-    $token = 'publichub';
-    $registrationmanager = new registration_manager();
-    $registeredhubs = $registrationmanager->get_registered_on_hubs();
-    foreach ($registeredhubs as $registeredhub) {
-        if ($huburl == $registeredhub->huburl) {
-            $token = $registeredhub->token;
-        }
-    }
-
-    $function = 'hub_get_courses';
-    $params = array('search' => $search, 'downloadable' => $downloadable,
-        'enrollable' => intval(!$downloadable), 'options' => $options);
-    $serverurl = $huburl . "/local/hub/webservice/webservices.php";
-    require_once($CFG->dirroot . "/webservice/xmlrpc/lib.php");
-    $xmlrpcclient = new webservice_xmlrpc_client($serverurl, $token);
-    try {
-        $result = $xmlrpcclient->call($function, array_values($params));
-        $courses = $result['courses'];
-        $coursetotal = $result['coursetotal'];
-    } catch (Exception $e) {
-        $errormessage = $OUTPUT->notification(
-                        get_string('errorcourselisting', 'block_community', $e->getMessage()));
-    }
+    list($courses, $coursetotal) = \core\hub\publication::search($search, $downloadable, $options);
 }
 
 // OUTPUT
 echo $OUTPUT->header();
 echo $OUTPUT->heading(get_string('searchcommunitycourse', 'block_community'), 3, 'main');
+echo $renderer->moodlenet_info();
+
 $hubselectorform->display();
 if (!empty($errormessage)) {
     echo $errormessage;
@@ -232,9 +190,9 @@ $PAGE->requires->yui_module('moodle-block_community-comments', 'M.blocks_communi
         array(array('commentids' => $commentedcourseids, 'closeButtonTitle' => get_string('close', 'editor'))));
 $PAGE->requires->yui_module('moodle-block_community-imagegallery', 'M.blocks_community.init_imagegallery',
         array(array('imageids' => $courseids, 'imagenumbers' => $courseimagenumbers,
-                'huburl' => $huburl, 'closeButtonTitle' => get_string('close', 'editor'))));
+                'huburl' => HUB_MOODLEORGHUBURL, 'closeButtonTitle' => get_string('close', 'editor'))));
 
-echo highlight($search, $renderer->course_list($courses, $huburl, $courseid));
+echo highlight($search, $renderer->course_list($courses, null, $courseid));
 
 //display givememore/Next link if more course can be displayed
 if (!empty($courses)) {
index a61b273..8142b5c 100644 (file)
  */
 
 require_once($CFG->libdir . '/formslib.php');
-require_once($CFG->dirroot . '/course/publish/lib.php');
-require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
 
 class community_hub_search_form extends moodleform {
 
     public function definition() {
-        global $CFG, $USER, $OUTPUT;
-        $strrequired = get_string('required');
+        global $CFG;
         $mform = & $this->_form;
 
         //set default value
@@ -81,11 +78,6 @@ class community_hub_search_form extends moodleform {
         } else {
             $orderby = 'newest';
         }
-        if (isset($this->_customdata['huburl'])) {
-            $huburl = $this->_customdata['huburl'];
-        } else {
-            $huburl = HUB_MOODLEORGHUBURL;
-        }
 
         $mform->addElement('header', 'site', get_string('search', 'block_community'));
 
@@ -95,222 +87,87 @@ class community_hub_search_form extends moodleform {
         $mform->addElement('hidden', 'executesearch', 1);
         $mform->setType('executesearch', PARAM_INT);
 
-        //retrieve the hub list on the hub directory by web service
-        $function = 'hubdirectory_get_hubs';
-        $params = array();
-        $serverurl = HUB_HUBDIRECTORYURL . "/local/hubdirectory/webservice/webservices.php";
-        require_once($CFG->dirroot . "/webservice/xmlrpc/lib.php");
-        $xmlrpcclient = new webservice_xmlrpc_client($serverurl, 'publichubdirectory');
-        try {
-            $hubs = $xmlrpcclient->call($function, $params);
-        } catch (Exception $e) {
-            $hubs = array();
-            $error = $OUTPUT->notification(get_string('errorhublisting', 'block_community', $e->getMessage()));
-            $mform->addElement('static', 'errorhub', '', $error);
-        }
-
-        // Hubdirectory returns old URL for the moodle.net hub, substitute it.
-        foreach ($hubs as $key => $hub) {
-            if ($hub['url'] === HUB_OLDMOODLEORGHUBURL) {
-                $hubs[$key]['url'] = HUB_MOODLEORGHUBURL;
-            }
-        }
-
-        //display list of registered on hub
-        $registrationmanager = new registration_manager();
-        $registeredhubs = $registrationmanager->get_registered_on_hubs();
-        //retrieve some additional hubs that we will add to
-        //the hub list got from the hub directory
-        $additionalhubs = array();
-        foreach ($registeredhubs as $registeredhub) {
-            $inthepubliclist = false;
-            foreach ($hubs as $hub) {
-                if ($hub['url'] == $registeredhub->huburl) {
-                    $inthepubliclist = true;
-                    $hub['registeredon'] = true;
-                }
-            }
-            if (!$inthepubliclist) {
-                $additionalhub = array();
-                $additionalhub['name'] = $registeredhub->hubname;
-                $additionalhub['url'] = $registeredhub->huburl;
-                $additionalhubs[] = $additionalhub;
-            }
-        }
-        if (!empty($additionalhubs)) {
-            $hubs = array_merge($hubs, $additionalhubs);
-        }
-
-        if (!empty($hubs)) {
-            $htmlhubs = array();
-            foreach ($hubs as $hub) {
-                // Name can come from hub directory - need some cleaning.
-                $hubname = clean_text($hub['name'], PARAM_TEXT);
-                $smalllogohtml = '';
-                if (array_key_exists('id', $hub)) {
-
-                    // Retrieve hub logo + generate small logo.
-                    $params = array('hubid' => $hub['id'], 'filetype' => HUB_HUBSCREENSHOT_FILE_TYPE);
-                    $imgurl = new moodle_url(HUB_HUBDIRECTORYURL . "/local/hubdirectory/webservice/download.php", $params);
-                    $imgsize = getimagesize($imgurl->out(false));
-                    if ($imgsize[0] > 1) {
-                        $ascreenshothtml = html_writer::empty_tag('img', array('src' => $imgurl, 'alt' => $hubname));
-                        $smalllogohtml = html_writer::empty_tag('img', array('src' => $imgurl, 'alt' => $hubname
-                                        , 'height' => 30, 'width' => 40));
-                    } else {
-                        $ascreenshothtml = '';
-                    }
-                    $hubimage = html_writer::tag('div', $ascreenshothtml, array('class' => 'hubimage'));
-
-                    // Statistics + trusted info.
-                    $hubstats = '';
-                    if (isset($hub['enrollablecourses'])) { //check needed to avoid warnings for Moodle version < 2011081700
-                        $additionaldesc = get_string('enrollablecourses', 'block_community') . ': ' . $hub['enrollablecourses'] . ' - ' .
-                                get_string('downloadablecourses', 'block_community') . ': ' . $hub['downloadablecourses'];
-                        $hubstats .= html_writer::tag('div', $additionaldesc);
-                    }
-                    if ($hub['trusted']) {
-                        $hubtrusted =  get_string('hubtrusted', 'block_community');
-                        $hubstats .= $OUTPUT->doc_link('trusted_hubs') . html_writer::tag('div', $hubtrusted);
-                    }
-                    $hubstats = html_writer::tag('div', $hubstats, array('class' => 'hubstats'));
-
-                    // hub name link + hub description.
-                    $hubnamelink = html_writer::link($hub['url'], html_writer::tag('h2',$hubname),
-                                    array('class' => 'hubtitlelink'));
-                    // The description can come from the hub directory - need to clean.
-                    $hubdescription = clean_param($hub['description'], PARAM_TEXT);
-                    $hubdescriptiontext = html_writer::tag('div', format_text($hubdescription, FORMAT_PLAIN),
-                                    array('class' => 'hubdescription'));
-
-                    $hubtext = html_writer::tag('div', $hubdescriptiontext . $hubstats, array('class' => 'hubtext'));
-
-                    $hubimgandtext = html_writer::tag('div', $hubimage . $hubtext, array('class' => 'hubimgandtext'));
-
-                    $hubfulldesc = html_writer::tag('div', $hubnamelink . $hubimgandtext, array('class' => 'hubmainhmtl'));
-                } else {
-                    $hubfulldesc = html_writer::link($hub['url'], $hubname);
-                }
-
-                // Add hub to the hub items.
-                $hubinfo = new stdClass();
-                $hubinfo->mainhtml = $hubfulldesc;
-                $hubinfo->rowhtml = html_writer::tag('div', $smalllogohtml , array('class' => 'hubsmalllogo')) . $hubname;
-                $hubitems[$hub['url']] = $hubinfo;
-            }
-
-            // Hub listing form element.
-            $mform->addElement('listing','huburl', '', '', array('items' => $hubitems,
-                'showall' => get_string('showall', 'block_community'),
-                'hideall' => get_string('hideall', 'block_community')));
-            $mform->setDefault('huburl', $huburl);
+        // Display enrol/download select box if the USER has the download capability on the course.
+        if (has_capability('moodle/community:download',
+                        context_course::instance($this->_customdata['courseid']))) {
+            $options = array(0 => get_string('enrollable', 'block_community'),
+                1 => get_string('downloadable', 'block_community'));
+            $mform->addElement('select', 'downloadable', get_string('enroldownload', 'block_community'),
+                    $options);
+            $mform->addHelpButton('downloadable', 'enroldownload', 'block_community');
 
-            //display enrol/download select box if the USER has the download capability on the course
-            if (has_capability('moodle/community:download',
-                            context_course::instance($this->_customdata['courseid']))) {
-                $options = array(0 => get_string('enrollable', 'block_community'),
-                    1 => get_string('downloadable', 'block_community'));
-                $mform->addElement('select', 'downloadable', get_string('enroldownload', 'block_community'),
-                        $options);
-                $mform->addHelpButton('downloadable', 'enroldownload', 'block_community');
-
-                $mform->setDefault('downloadable', $downloadable);
-            } else {
-                $mform->addElement('hidden', 'downloadable', 0);
-            }
-            $mform->setType('downloadable', PARAM_INT);
-
-            $options = array();
-            $options['all'] = get_string('any');
-            $options[HUB_AUDIENCE_EDUCATORS] = get_string('audienceeducators', 'hub');
-            $options[HUB_AUDIENCE_STUDENTS] = get_string('audiencestudents', 'hub');
-            $options[HUB_AUDIENCE_ADMINS] = get_string('audienceadmins', 'hub');
-            $mform->addElement('select', 'audience', get_string('audience', 'block_community'), $options);
-            $mform->setDefault('audience', $audience);
-            unset($options);
-            $mform->addHelpButton('audience', 'audience', 'block_community');
-
-            $options = array();
-            $options['all'] = get_string('any');
-            $options[HUB_EDULEVEL_PRIMARY] = get_string('edulevelprimary', 'hub');
-            $options[HUB_EDULEVEL_SECONDARY] = get_string('edulevelsecondary', 'hub');
-            $options[HUB_EDULEVEL_TERTIARY] = get_string('eduleveltertiary', 'hub');
-            $options[HUB_EDULEVEL_GOVERNMENT] = get_string('edulevelgovernment', 'hub');
-            $options[HUB_EDULEVEL_ASSOCIATION] = get_string('edulevelassociation', 'hub');
-            $options[HUB_EDULEVEL_CORPORATE] = get_string('edulevelcorporate', 'hub');
-            $options[HUB_EDULEVEL_OTHER] = get_string('edulevelother', 'hub');
-            $mform->addElement('select', 'educationallevel',
-                    get_string('educationallevel', 'block_community'), $options);
-            $mform->setDefault('educationallevel', $educationallevel);
-            unset($options);
-            $mform->addHelpButton('educationallevel', 'educationallevel', 'block_community');
-
-            $publicationmanager = new course_publish_manager();
-            $options = $publicationmanager->get_sorted_subjects();
-            $mform->addElement('searchableselector', 'subject', get_string('subject', 'block_community'),
-                    $options, array('id' => 'communitysubject'));
-            $mform->setDefault('subject', $subject);
-            unset($options);
-            $mform->addHelpButton('subject', 'subject', 'block_community');
-
-            require_once($CFG->libdir . "/licenselib.php");
-            $licensemanager = new license_manager();
-            $licences = $licensemanager->get_licenses();
-            $options = array();
-            $options['all'] = get_string('any');
-            foreach ($licences as $license) {
-                $options[$license->shortname] = get_string($license->shortname, 'license');
-            }
-            $mform->addElement('select', 'licence', get_string('licence', 'block_community'), $options);
-            unset($options);
-            $mform->addHelpButton('licence', 'licence', 'block_community');
-            $mform->setDefault('licence', $licence);
-
-            $languages = get_string_manager()->get_list_of_languages();
-            core_collator::asort($languages);
-            $languages = array_merge(array('all' => get_string('any')), $languages);
-            $mform->addElement('select', 'language', get_string('language'), $languages);
-
-            $mform->setDefault('language', $language);
-            $mform->addHelpButton('language', 'language', 'block_community');
-
-            $mform->addElement('select', 'orderby', get_string('orderby', 'block_community'),
-                array('newest' => get_string('orderbynewest', 'block_community'),
-                    'eldest' => get_string('orderbyeldest', 'block_community'),
-                    'fullname' => get_string('orderbyname', 'block_community'),
-                    'publisher' => get_string('orderbypublisher', 'block_community'),
-                    'ratingaverage' => get_string('orderbyratingaverage', 'block_community')));
-
-            $mform->setDefault('orderby', $orderby);
-            $mform->addHelpButton('orderby', 'orderby', 'block_community');
-            $mform->setType('orderby', PARAM_ALPHA);
-
-            $mform->setAdvanced('audience');
-            $mform->setAdvanced('educationallevel');
-            $mform->setAdvanced('subject');
-            $mform->setAdvanced('licence');
-            $mform->setAdvanced('language');
-            $mform->setAdvanced('orderby');
-
-            $mform->addElement('text', 'search', get_string('keywords', 'block_community'),
-                array('size' => 30));
-            $mform->addHelpButton('search', 'keywords', 'block_community');
-            $mform->setType('search', PARAM_NOTAGS);
-
-            $mform->addElement('submit', 'submitbutton', get_string('search', 'block_community'));
+            $mform->setDefault('downloadable', $downloadable);
+        } else {
+            $mform->addElement('hidden', 'downloadable', 0);
         }
-    }
-
-    function validation($data, $files) {
-        global $CFG;
-
-        $errors = array();
-
-        if (empty($this->_form->_submitValues['huburl'])) {
-            $errors['huburl'] = get_string('nohubselected', 'hub');
+        $mform->setType('downloadable', PARAM_INT);
+
+        $options = \core\hub\publication::audience_options(true);
+        $mform->addElement('select', 'audience', get_string('audience', 'block_community'), $options);
+        $mform->setDefault('audience', $audience);
+        unset($options);
+        $mform->addHelpButton('audience', 'audience', 'block_community');
+
+        $options = \core\hub\publication::educational_level_options(true);
+        $mform->addElement('select', 'educationallevel',
+                get_string('educationallevel', 'block_community'), $options);
+        $mform->setDefault('educationallevel', $educationallevel);
+        unset($options);
+        $mform->addHelpButton('educationallevel', 'educationallevel', 'block_community');
+
+        $options = \core\hub\publication::get_sorted_subjects();
+        $mform->addElement('searchableselector', 'subject', get_string('subject', 'block_community'),
+                $options, array('id' => 'communitysubject'));
+        $mform->setDefault('subject', $subject);
+        unset($options);
+        $mform->addHelpButton('subject', 'subject', 'block_community');
+
+        require_once($CFG->libdir . "/licenselib.php");
+        $licensemanager = new license_manager();
+        $licences = $licensemanager->get_licenses();
+        $options = array();
+        $options['all'] = get_string('any');
+        foreach ($licences as $license) {
+            $options[$license->shortname] = get_string($license->shortname, 'license');
         }
+        $mform->addElement('select', 'licence', get_string('licence', 'block_community'), $options);
+        unset($options);
+        $mform->addHelpButton('licence', 'licence', 'block_community');
+        $mform->setDefault('licence', $licence);
+
+        $languages = get_string_manager()->get_list_of_languages();
+        core_collator::asort($languages);
+        $languages = array_merge(array('all' => get_string('any')), $languages);
+        $mform->addElement('select', 'language', get_string('language'), $languages);
+
+        $mform->setDefault('language', $language);
+        $mform->addHelpButton('language', 'language', 'block_community');
+
+        $mform->addElement('select', 'orderby', get_string('orderby', 'block_community'),
+            array('newest' => get_string('orderbynewest', 'block_community'),
+                'eldest' => get_string('orderbyeldest', 'block_community'),
+                'fullname' => get_string('orderbyname', 'block_community'),
+                'publisher' => get_string('orderbypublisher', 'block_community'),
+                'ratingaverage' => get_string('orderbyratingaverage', 'block_community')));
+
+        $mform->setDefault('orderby', $orderby);
+        $mform->addHelpButton('orderby', 'orderby', 'block_community');
+        $mform->setType('orderby', PARAM_ALPHA);
+
+        $mform->setAdvanced('audience');
+        $mform->setAdvanced('educationallevel');
+        $mform->setAdvanced('subject');
+        $mform->setAdvanced('licence');
+        $mform->setAdvanced('language');
+        $mform->setAdvanced('orderby');
+
+        $mform->addElement('text', 'search', get_string('keywords', 'block_community'),
+            array('size' => 30));
+        $mform->addHelpButton('search', 'keywords', 'block_community');
+        $mform->setType('search', PARAM_NOTAGS);
+
+        $mform->addElement('submit', 'submitbutton', get_string('search', 'block_community'));
 
-        return $errors;
     }
 
 }
index 330d3da..d975078 100644 (file)
@@ -73,66 +73,6 @@ class block_community_manager {
                 array('courseurl' => $courseurl, 'userid' => $userid));
     }
 
-    /**
-     * Download the community course backup and save it in file API
-     * @param integer $courseid
-     * @param string $huburl
-     * @return array 'privatefile' the file name saved in private area
-     *               'tmpfile' the file name saved in the moodledata temp dir (for restore)
-     */
-    public function block_community_download_course_backup($course) {
-        global $CFG, $USER;
-        require_once($CFG->libdir . "/filelib.php");
-        require_once($CFG->dirroot. "/course/publish/lib.php");
-
-        $params['courseid'] = $course->id;
-        $params['filetype'] = HUB_BACKUP_FILE_TYPE;
-
-        make_temp_directory('backup');
-
-        $filename = md5(time() . '-' . $course->id . '-'. $USER->id . '-'. random_string(20));
-
-        $url  = new moodle_url($course->huburl.'/local/hub/webservice/download.php', $params);
-        $path = $CFG->tempdir.'/backup/'.$filename.".mbz";
-        $fp = fopen($path, 'w');
-        $curlurl = $course->huburl.'/local/hub/webservice/download.php?filetype='
-                .HUB_BACKUP_FILE_TYPE.'&courseid='.$course->id;
-
-        //send an identification token if the site is registered on the hub
-        require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
-        $registrationmanager = new registration_manager();
-        $registeredhub = $registrationmanager->get_registeredhub($course->huburl);
-        if (!empty($registeredhub)) {
-            $token = $registeredhub->token;
-            $curlurl .= '&token='.$token;
-        }
-
-        $ch = curl_init($curlurl);
-        curl_setopt($ch, CURLOPT_FILE, $fp);
-        $data = curl_exec($ch);
-        curl_close($ch);
-        fclose($fp);
-
-        $fs = get_file_storage();
-        $record = new stdClass();
-        $record->contextid = context_user::instance($USER->id)->id;
-        $record->component = 'user';
-        $record->filearea = 'private';
-        $record->itemid = 0;
-        $record->filename = urlencode($course->fullname)."_".time().".mbz";
-        $record->filepath = '/downloaded_backup/';
-        if (!$fs->file_exists($record->contextid, $record->component,
-                $record->filearea, 0, $record->filepath, $record->filename)) {
-            $fs->create_file_from_pathname($record,
-                    $CFG->tempdir.'/backup/'.$filename.".mbz");
-        }
-
-        $filenames = array();
-        $filenames['privatefile'] = $record->filename;
-        $filenames['tmpfile'] = $filename;
-        return $filenames;
-    }
-
     /**
      * Delete a community course
      * @param integer $communityid
index f29d301..f415204 100644 (file)
@@ -85,14 +85,43 @@ class block_community_renderer extends plugin_renderer_base {
         return html_writer::tag('div', $nextlink, array( 'class' => 'nextlink'));
     }
 
+    /**
+     * Displays information about moodle.net above course search form
+     *
+     * @return string
+     */
+    public function moodlenet_info() {
+        if (!$info = \core\hub\registration::get_moodlenet_info()) {
+            return '';
+        }
+
+        $image = html_writer::div(html_writer::img($info['imgurl'], $info['name']), 'hubimage');
+
+        $namelink = html_writer::link($info['url'], html_writer::tag('h2', $info['name']), array('class' => 'hubtitlelink'));
+        $description = clean_param($info['description'], PARAM_TEXT);
+        $descriptiontext = html_writer::div(format_text($description, FORMAT_PLAIN), 'hubdescription');
+
+        $additionaldesc = get_string('enrollablecourses', 'block_community') . ': ' . $info['enrollablecourses'] . ' - ' .
+            get_string('downloadablecourses', 'block_community') . ': ' . $info['downloadablecourses'];
+        $stats = html_writer::div(html_writer::tag('div', $additionaldesc), 'hubstats');
+
+        $text = html_writer::div($descriptiontext . $stats, 'hubtext');
+
+        $imgandtext = html_writer::div($image . $text, 'hubimgandtext');
+
+        $fulldesc = html_writer::div($namelink . $imgandtext, 'hubmainhmtl clearfix');
+
+        return html_writer::div($fulldesc, 'formlisting');
+    }
+
     /**
      * Display a list of courses
      * @param array $courses
-     * @param boolean $withwriteaccess
+     * @param mixed $unused parameter is not used
      * @param int $contextcourseid context course id
      * @return string
      */
-    public function course_list($courses, $huburl, $contextcourseid) {
+    public function course_list($courses, $unused, $contextcourseid) {
         global $CFG;
 
         $renderedhtml = '';
@@ -128,12 +157,9 @@ class block_community_renderer extends plugin_renderer_base {
 
                 // create screenshots html
                 $screenshothtml = '';
-                if (!empty($course->screenshots)) {
-                    $baseurl = new moodle_url($huburl . '/local/hub/webservice/download.php',
-                                    array('courseid' => $course->id,
-                                        'filetype' => HUB_SCREENSHOT_FILE_TYPE));
+                if (!empty($course->screenshotbaseurl)) {
                     $screenshothtml = html_writer::empty_tag('img',
-                        array('src' => $baseurl, 'alt' => $course->fullname));
+                        array('src' => $course->screenshotbaseurl, 'alt' => $course->fullname));
                 }
                 $coursescreenshot = html_writer::tag('div', $screenshothtml,
                                 array('class' => 'coursescreenshot',
@@ -269,7 +295,7 @@ class block_community_renderer extends plugin_renderer_base {
                 if (!$course->enrollable) {
                     $params = array('sesskey' => sesskey(), 'download' => 1, 'confirmed' => 1,
                         'remotemoodleurl' => $CFG->wwwroot, 'courseid' => $contextcourseid,
-                        'downloadcourseid' => $course->id, 'huburl' => $huburl,
+                        'downloadcourseid' => $course->id,
                         'coursefullname' => $course->fullname, 'backupsize' => $course->backupsize);
                     $downloadurl = new moodle_url("/blocks/community/communitycourse.php", $params);
                     $downloadbuttonhtml = html_writer::tag('a', get_string('install', 'block_community'),
@@ -339,10 +365,8 @@ class block_community_renderer extends plugin_renderer_base {
 
                 //link rate and comment
                 $rateandcomment = html_writer::tag('div',
-                                html_writer::tag('a', get_string('rateandcomment', 'block_community'),
-                                        array('href' => new moodle_url($huburl,
-                                                    array('courseid' => $course->id, 'mustbelogged' => true)),
-                                            'onclick' => 'this.target="_blank"')),
+                                html_writer::link($course->commenturl, get_string('rateandcomment', 'block_community'),
+                                            ['onclick' => 'this.target="_blank"']),
                                 array('class' => 'hubrateandcomment'));
 
                 //the main DIV tags
index c6704e6..f9ecac8 100644 (file)
     padding-left: 165px;
 }
 
-#page-blocks-community-communitycourse .hubimgandtext {
-    display: table;
-}
-
 #page-blocks-community-communitycourse .hubimage {
     float: left;
     display: block;
diff --git a/blocks/messages/block_messages.php b/blocks/messages/block_messages.php
deleted file mode 100644 (file)
index 79d74b8..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Mentees block.
- *
- * @package    block_messages
- * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-class block_messages extends block_base {
-    function init() {
-        $this->title = get_string('pluginname', 'block_messages');
-    }
-
-    function get_content() {
-        global $USER, $CFG, $DB, $OUTPUT;
-
-        if (!$CFG->messaging) {
-            $this->content = new stdClass;
-            $this->content->text = '';
-            $this->content->footer = '';
-            if ($this->page->user_is_editing()) {
-                $this->content->text = get_string('disabled', 'message');
-            }
-            return $this->content;
-        }
-
-        if ($this->content !== NULL) {
-            return $this->content;
-        }
-
-        $this->content = new stdClass;
-        $this->content->text = '';
-        $this->content->footer = '';
-
-        if (empty($this->instance) or !isloggedin() or isguestuser() or empty($CFG->messaging)) {
-            return $this->content;
-        }
-
-        $link = '/message/index.php';
-        $action = null; //this was using popup_action() but popping up a fullsize window seems wrong
-        $this->content->footer = $OUTPUT->action_link($link, get_string('messages', 'message'), $action);
-
-        $ufields = user_picture::fields('u', array('lastaccess'));
-        $users = $DB->get_records_sql("SELECT $ufields, COUNT(m.useridfrom) AS count
-                                         FROM {user} u, {message} m
-                                        WHERE m.useridto = ? AND u.id = m.useridfrom AND m.notification = 0
-                                     GROUP BY $ufields", array($USER->id));
-
-
-        //Now, we have in users, the list of users to show
-        //Because they are online
-        if (!empty($users)) {
-            $this->content->text .= '<ul class="list">';
-            foreach ($users as $user) {
-                $timeago = format_time(time() - $user->lastaccess);
-                $this->content->text .= '<li class="listentry"><div class="user"><a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.SITEID.'" title="'.$timeago.'">';
-                $this->content->text .= $OUTPUT->user_picture($user, array('courseid'=>SITEID)); //TODO: user might not have capability to view frontpage profile :-(
-                $this->content->text .= fullname($user).'</a></div>';
-
-                $link = '/message/index.php?usergroup=unread&id='.$user->id;
-                $anchortagcontents = $OUTPUT->pix_icon('t/message', fullname($user)) . '&nbsp;' . $user->count;
-
-                $action = null; // popup is gone now
-                $anchortag = $OUTPUT->action_link($link, $anchortagcontents, $action);
-
-                $this->content->text .= '<div class="message">'.$anchortag.'</div></li>';
-            }
-            $this->content->text .= '</ul>';
-        } else {
-            $this->content->text .= '<div class="info">';
-            $this->content->text .= get_string('nomessages', 'message');
-            $this->content->text .= '</div>';
-        }
-
-        return $this->content;
-    }
-}
-
-
diff --git a/blocks/messages/db/access.php b/blocks/messages/db/access.php
deleted file mode 100644 (file)
index 4ea589d..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Messages block caps.
- *
- * @package    block_messages
- * @copyright  Mark Nelson <markn@moodle.com>
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-$capabilities = array(
-
-    'block/messages:myaddinstance' => array(
-        'captype' => 'write',
-        'contextlevel' => CONTEXT_SYSTEM,
-        'archetypes' => array(
-            'user' => CAP_ALLOW
-        ),
-
-        'clonepermissionsfrom' => 'moodle/my:manageblocks'
-    ),
-
-    'block/messages:addinstance' => array(
-        'riskbitmask' => RISK_SPAM | RISK_XSS,
-
-        'captype' => 'write',
-        'contextlevel' => CONTEXT_BLOCK,
-        'archetypes' => array(
-            'editingteacher' => CAP_ALLOW,
-            'manager' => CAP_ALLOW
-        ),
-
-        'clonepermissionsfrom' => 'moodle/site:manageblocks'
-    ),
-);
diff --git a/blocks/messages/styles.css b/blocks/messages/styles.css
deleted file mode 100644 (file)
index 176f756..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-.block_messages .content {
-    text-align: left;
-    padding-top: 5px;
-}
-
-.block_messages .content .list li.listentry {
-    clear: both;
-}
-
-.block_messages .content .list li.listentry .user {
-    float: left;
-    position: relative;
-}
-
-.block_messages .content .list li.listentry .message {
-    float: right;
-}
-
-.block_messages .content .info {
-    text-align: center;
-}
-
-.block_messages .content .footer {
-    clear: both;
-}
diff --git a/blocks/messages/tests/behat/block_messages_course.feature b/blocks/messages/tests/behat/block_messages_course.feature
deleted file mode 100644 (file)
index 63dd4a5..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-@block @block_messages
-Feature: The messages block allows users to list new messages an a course
-  In order to enable the messages block in a course
-  As a teacher
-  I can add the messages block to a course and view my messages
-
-  Background:
-    Given the following "users" exist:
-      | username | firstname | lastname | email | idnumber |
-      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
-      | student1 | Student | 1 | student1@example.com | S1 |
-    And the following "courses" exist:
-      | fullname | shortname | category |
-      | Course 1 | C1 | 0 |
-    And the following "course enrolments" exist:
-      | user | course | role |
-      | teacher1 | C1 | editingteacher |
-      | student1 | C1 | student |
-
-  Scenario: View the block by a user with messaging disabled.
-    Given the following config values are set as admin:
-      | messaging       | 0 |
-    And I log in as "teacher1"
-    And I am on "Course 1" course homepage with editing mode on
-    And I add the "Messages" block
-    Then I should see "Messaging is disabled on this site" in the "Messages" "block"
-
-  Scenario: View the block by a user who does not have any messages.
-    Given I log in as "teacher1"
-    And I am on "Course 1" course homepage with editing mode on
-    And I add the "Messages" block
-    Then I should see "No messages" in the "Messages" "block"
-
-  @javascript
-  Scenario: View the block by a user who has messages.
-    Given I log in as "student1"
-    And I follow "Messages" in the user menu
-    And I send "This is message 1" message to "Teacher 1" user
-    And I send "This is message 2" message to "Teacher 1" user
-    And I log out
-    And I log in as "teacher1"
-    And I am on "Course 1" course homepage with editing mode on
-    And I add the "Messages" block
-    Then I should see "Student 1" in the "Messages" "block"
-
-  @javascript
-  Scenario: Use the block to send a message to a user.
-    Given I log in as "teacher1"
-    And I am on "Course 1" course homepage with editing mode on
-    And I add the "Messages" block
-    And I click on "//a[normalize-space(.) = 'Messages']" "xpath_element" in the "Messages" "block"
-    And I send "This is message 1" message to "Student 1" user
-    And I log out
-    When I log in as "student1"
-    And I am on "Course 1" course homepage
-    Then I should see "Teacher 1" in the "Messages" "block"
diff --git a/blocks/messages/tests/behat/block_messages_dashboard.feature b/blocks/messages/tests/behat/block_messages_dashboard.feature
deleted file mode 100644 (file)
index 509057e..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-@block @block_messages
-Feature: The messages block allows users to list new messages on the dashboard
-  In order to enable the messages block on the dashboard
-  As a user
-  I can add the messages block to a my dashboard and view my messages
-
-  Background:
-    Given the following "users" exist:
-      | username | firstname | lastname | email | idnumber |
-      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
-      | student1 | Student | 1 | student1@example.com | S1 |
-
-  Scenario: View the block by a user with messaging disabled.
-    Given the following config values are set as admin:
-      | messaging       | 0 |
-    And I log in as "teacher1"
-    And I press "Customise this page"
-    When I add the "Messages" block
-    Then I should see "Messaging is disabled on this site" in the "Messages" "block"
-
-  Scenario: View the block by a user who does not have any messages.
-    Given I log in as "teacher1"
-    And I press "Customise this page"
-    When I add the "Messages" block
-    Then I should see "No messages" in the "Messages" "block"
-
-  @javascript
-  Scenario: View the block by a user who has messages.
-    Given I log in as "student1"
-    And I follow "Messages" in the user menu
-    And I send "This is message 1" message to "Teacher 1" user
-    And I send "This is message 2" message to "Teacher 1" user
-    And I log out
-    When I log in as "teacher1"
-    And I press "Customise this page"
-    And I add the "Messages" block
-    Then I should see "Student 1" in the "Messages" "block"
-
-  @javascript
-  Scenario: Use the block to send a message to a user.
-    Given I log in as "teacher1"
-    And I press "Customise this page"
-    And I add the "Messages" block
-    And I click on "//a[normalize-space(.) = 'Messages']" "xpath_element" in the "Messages" "block"
-    And I send "This is message 1" message to "Student 1" user
-    And I log out
-    When I log in as "student1"
-    And I press "Customise this page"
-    And I add the "Messages" block
-    Then I should see "Teacher 1" in the "Messages" "block"
diff --git a/blocks/messages/tests/behat/block_messages_frontpage.feature b/blocks/messages/tests/behat/block_messages_frontpage.feature
deleted file mode 100644 (file)
index 2c71001..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-@block @block_messages
-Feature: The messages block allows users to list new messages on the frontpage
-  In order to enable the messages block on the frontpage
-  As an admin
-  I can add the messages block to a the frontpage and view my messages
-
-  Background:
-    Given the following "users" exist:
-      | username | firstname | lastname | email | idnumber |
-      | teacher1 | Teacher | 1 | teacher1@example.com | T1 |
-      | student1 | Student | 1 | student1@example.com | S1 |
-    And I log in as "admin"
-    And I am on site homepage
-    And I navigate to "Turn editing on" node in "Front page settings"
-    And I add the "Messages" block
-    And I log out
-
-  Scenario: View the block by a user with messaging disabled.
-    Given the following config values are set as admin:
-      | messaging       | 0 |
-    And I log in as "admin"
-    And I am on site homepage
-    When I navigate to "Turn editing on" node in "Front page settings"
-    And I should see "Messaging is disabled on this site" in the "Messages" "block"
-    Then I navigate to "Turn editing off" node in "Front page settings"
-    And I should not see "Messaging is disabled on this site"
-
-  Scenario: View the block by a user who does not have any messages.
-    Given I log in as "teacher1"
-    When I am on site homepage
-    Then I should see "No messages" in the "Messages" "block"
-
-  Scenario: Try to view the block as a guest user.
-    Given I log in as "guest"
-    When I am on site homepage
-    Then I should not see "Messages"
-
-  @javascript
-  Scenario: View the block by a user who has messages.
-    Given I log in as "student1"
-    And I follow "Messages" in the user menu
-    And I send "This is message 1" message to "Teacher 1" user
-    And I send "This is message 2" message to "Teacher 1" user
-    And I log out
-    When I log in as "teacher1"
-    And I am on site homepage
-    Then I should see "Student 1" in the "Messages" "block"
-
-  @javascript
-  Scenario: Use the block to send a message to a user.
-    Given I log in as "teacher1"
-    And I am on site homepage
-    And I click on "//a[normalize-space(.) = 'Messages']" "xpath_element" in the "Messages" "block"
-    And I send "This is message 1" message to "Student 1" user
-    And I log out
-    When I log in as "student1"
-    And I am on site homepage
-    Then I should see "Teacher 1" in the "Messages" "block"
diff --git a/blocks/messages/version.php b/blocks/messages/version.php
deleted file mode 100644 (file)
index 9faef4d..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Version details
- *
- * @package    block_messages
- * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-$plugin->version   = 2017051500;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017050500;        // Requires this Moodle version
-$plugin->component = 'block_messages';  // Full name of the plugin (used for diagnostics)
index 6b8fc56..7ef8f0a 100644 (file)
@@ -9,6 +9,7 @@ information provided here is intended especially for developers.
 * Blocks can now be included in Moodle global search, with some limitations (at present, the search
   works only for blocks located directly on course pages or site home page). See the HTML block for
   an example.
+* Block block_messages is no longer a part of core.
 
 === 3.3 ===
 
index 1999702..a1c8e36 100644 (file)
Binary files a/calendar/amd/build/calendar.min.js and b/calendar/amd/build/calendar.min.js differ
index 979e92e..57db248 100644 (file)
Binary files a/calendar/amd/build/calendar_mini.min.js and b/calendar/amd/build/calendar_mini.min.js differ
diff --git a/calendar/amd/build/calendar_threemonth.min.js b/calendar/amd/build/calendar_threemonth.min.js
new file mode 100644 (file)
index 0000000..ac1bb8c
Binary files /dev/null and b/calendar/amd/build/calendar_threemonth.min.js differ
index 77b2153..99bf77b 100644 (file)
Binary files a/calendar/amd/build/events.min.js and b/calendar/amd/build/events.min.js differ
diff --git a/calendar/amd/build/modal_delete.min.js b/calendar/amd/build/modal_delete.min.js
new file mode 100644 (file)
index 0000000..78456c6
Binary files /dev/null and b/calendar/amd/build/modal_delete.min.js differ
index a33feed..c970b3f 100644 (file)
Binary files a/calendar/amd/build/repository.min.js and b/calendar/amd/build/repository.min.js differ
index 8dbeb18..a81f332 100644 (file)
Binary files a/calendar/amd/build/selectors.min.js and b/calendar/amd/build/selectors.min.js differ
index 0a9f53a..fdca2a5 100644 (file)
Binary files a/calendar/amd/build/summary_modal.min.js and b/calendar/amd/build/summary_modal.min.js differ
index 301ef42..61f7942 100644 (file)
Binary files a/calendar/amd/build/view_manager.min.js and b/calendar/amd/build/view_manager.min.js differ
index 2958c83..0c436cc 100644 (file)
@@ -66,7 +66,8 @@ define([
         LOADING_ICON: '.loading-icon',
         VIEW_DAY_LINK: "[data-action='view-day-link']",
         CALENDAR_MONTH_WRAPPER: ".calendarwrapper",
-        COURSE_SELECTOR: 'select[name="course"]'
+        COURSE_SELECTOR: 'select[name="course"]',
+        TODAY: '.today',
     };
 
     /**
@@ -82,21 +83,6 @@ define([
         });
     };
 
-    /**
-     * Get the event source.
-     *
-     * @param {Object} subscription The event subscription object.
-     * @return {promise} The lang string promise.
-     */
-    var getEventSource = function(subscription) {
-        return Str.get_string('subsource', 'core_calendar', subscription).then(function(langStr) {
-            if (subscription.url) {
-                return '<a href="' + subscription.url + '">' + langStr + '</a>';
-            }
-            return langStr;
-        });
-    };
-
     /**
      * Render the event summary modal.
      *
@@ -109,31 +95,11 @@ define([
                 throw new Error('Error encountered while trying to fetch calendar event with ID: ' + eventId);
             }
             var eventData = getEventResponse.event;
-            var eventTypePromise = getEventType(eventData.eventtype);
-
-            // If the calendar event has event source, get the source's language string/link.
-            if (eventData.displayeventsource) {
-                eventData.subscription = JSON.parse(eventData.subscription);
-                var eventSourceParams = {
-                    url: eventData.subscription.url,
-                    name: eventData.subscription.name
-                };
-                var eventSourcePromise = getEventSource(eventSourceParams);
-
-                // Return event data with event type and event source info.
-                return $.when(eventTypePromise, eventSourcePromise).then(function(eventType, eventSource) {
-                    eventData.eventtype = eventType;
-                    eventData.source = eventSource;
-                    return eventData;
-                });
-            }
 
-            // Return event data with event type info.
-            return eventTypePromise.then(function(eventType) {
+            return getEventType(eventData.eventtype).then(function(eventType) {
                 eventData.eventtype = eventType;
                 return eventData;
             });
-
         }).then(function(eventData) {
             // Build the modal parameters from the event data.
             var modalParams = {
@@ -245,8 +211,7 @@ define([
                 templateContext: {
                     contextid: contextId
                 }
-            },
-            [root, SELECTORS.NEW_EVENT_BUTTON]
+            }
         );
     };
 
@@ -290,11 +255,14 @@ define([
             });
             modal.setCourseId(courseId);
             return;
-        });
+        })
+        .fail(Notification.exception);
     };
 
     /**
      * Register event listeners for the module.
+     *
+     * @param {object} root The calendar root element
      */
     var registerEventListeners = function(root) {
         // Bind click events to event links.
@@ -330,6 +298,24 @@ define([
         var eventFormPromise = registerEventFormModal(root);
         registerCalendarEventListeners(root, eventFormPromise);
 
+        // Bind click event on the new event button.
+        root.on('click', SELECTORS.NEW_EVENT_BUTTON, function(e) {
+            eventFormPromise.then(function(modal) {
+                // Attempt to find the cell for today.
+                // If it can't be found, then use the start time of the first day on the calendar.
+                var today = root.find(SELECTORS.TODAY);
+                if (!today.length) {
+                    modal.setStartTime(root.find(SELECTORS.DAY).attr('data-new-event-timestamp'));
+                }
+
+                modal.show();
+                return;
+            })
+            .fail(Notification.exception);
+
+            e.preventDefault();
+        });
+
         // Bind click events to calendar days.
         root.on('click', SELECTORS.DAY, function(e) {
             var target = $(e.target);
@@ -340,7 +326,8 @@ define([
                     modal.setStartTime(startTime);
                     modal.show();
                     return;
-                });
+                })
+                .fail(Notification.exception);
 
                 e.preventDefault();
             }
index 48a4f44..6853bf7 100644 (file)
@@ -38,6 +38,44 @@ function(
     CalendarViewManager
 ) {
 
+    /**
+     * Listen to and handle any calendar events fired by the calendar UI.
+     *
+     * @method registerCalendarEventListeners
+     * @param {object} root The calendar root element
+     */
+    var registerCalendarEventListeners = function(root) {
+        var body = $('body');
+        var namespace = '.' + root.attr('id');
+
+        body.on(CalendarEvents.created + namespace, root, reloadMonth);
+        body.on(CalendarEvents.deleted + namespace, root, reloadMonth);
+        body.on(CalendarEvents.updated + namespace, root, reloadMonth);
+        body.on(CalendarEvents.eventMoved + namespace, root, reloadMonth);
+    };
+
+    /**
+     * Reload the month view in this month.
+     *
+     * @param {EventFacade} e
+     */
+    var reloadMonth = function(e) {
+        var root = e.data;
+        var body = $('body');
+        var namespace = '.' + root.attr('id');
+
+        if (root.is(':visible')) {
+            CalendarViewManager.reloadCurrentMonth(root);
+        } else {
+            // The root has been removed.
+            // Remove all events in the namespace.
+            body.on(CalendarEvents.created + namespace);
+            body.on(CalendarEvents.deleted + namespace);
+            body.on(CalendarEvents.updated + namespace);
+            body.on(CalendarEvents.eventMoved + namespace);
+        }
+    };
+
     var registerEventListeners = function(root) {
         $('body').on(CalendarEvents.filterChanged, function(e, data) {
             var daysWithEvent = root.find(CalendarSelectors.eventType[data.type]);
@@ -52,6 +90,7 @@ function(
 
             CalendarViewManager.init(root);
             registerEventListeners(root);
+            registerCalendarEventListeners(root);
         }
     };
 });
diff --git a/calendar/amd/src/calendar_threemonth.js b/calendar/amd/src/calendar_threemonth.js
new file mode 100644 (file)
index 0000000..a043887
--- /dev/null
@@ -0,0 +1,123 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This module handles display of multiple mini calendars in a view, and
+ * movement through them.
+ *
+ * @module     core_calendar/calendar_threemonth
+ * @package    core_calendar
+ * @copyright  2017 Andrew Nicols <andrew@nicols.co.uk>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define([
+    'jquery',
+    'core_calendar/selectors',
+    'core_calendar/events',
+    'core/templates',
+    'core_calendar/view_manager',
+],
+function(
+    $,
+    CalendarSelectors,
+    CalendarEvents,
+    Templates,
+    CalendarViewManager
+) {
+
+    /**
+     * Listen to and handle any calendar events fired by the calendar UI.
+     *
+     * @method registerCalendarEventListeners
+     * @param {object} root The calendar root element
+     */
+    var registerCalendarEventListeners = function(root) {
+        var body = $('body');
+        body.on(CalendarEvents.monthChanged, function(e, year, month, courseId) {
+            // We have to use a queue here because the calling code is decoupled from these listeners.
+            // It's possible for the event to be called multiple times before one call is fully resolved.
+            root.queue(function(next) {
+                return processRequest(e, year, month, courseId)
+                .then(function() {
+                    return next();
+                });
+            });
+        });
+
+        var processRequest = function(e, year, month, courseId) {
+            var newCurrentMonth = root.find('[data-year="' + year + '"][data-month="' + month + '"]');
+            var newParent = newCurrentMonth.closest(CalendarSelectors.calendarPeriods.month);
+            var allMonths = root.find(CalendarSelectors.calendarPeriods.month);
+
+            var previousMonth = $(allMonths[0]);
+            var nextMonth = $(allMonths[2]);
+
+            var placeHolder = $('<span>');
+            placeHolder.attr('data-template', 'core_calendar/threemonth_month');
+            placeHolder.attr('data-includenavigation', false);
+            var placeHolderContainer = $('<div>');
+            placeHolderContainer.hide();
+            placeHolderContainer.append(placeHolder);
+
+            var requestYear;
+            var requestMonth;
+            var oldMonth;
+
+            if (newParent.is(previousMonth)) {
+                // Fetch the new previous month.
+                placeHolderContainer.insertBefore(previousMonth);
+
+                requestYear = previousMonth.data('previousYear');
+                requestMonth = previousMonth.data('previousMonth');
+                oldMonth = nextMonth;
+            } else if (newParent.is(nextMonth)) {
+                // Fetch the new next month.
+                placeHolderContainer.insertAfter(nextMonth);
+                requestYear = nextMonth.data('nextYear');
+                requestMonth = nextMonth.data('nextMonth');
+                oldMonth = previousMonth;
+            }
+
+            return CalendarViewManager.refreshMonthContent(
+                placeHolder,
+                requestYear,
+                requestMonth,
+                courseId,
+                placeHolder
+            )
+            .then(function() {
+                var slideUpPromise = $.Deferred();
+                var slideDownPromise = $.Deferred();
+                oldMonth.slideUp('fast', function() {
+                    $(this).remove();
+                    slideUpPromise.resolve();
+                });
+                placeHolderContainer.slideDown('fast', function() {
+                    slideDownPromise.resolve();
+                });
+
+                return $.when(slideUpPromise, slideDownPromise);
+            });
+        };
+    };
+
+    return {
+        init: function(root) {
+            root = $(root);
+
+            registerCalendarEventListeners(root);
+        }
+    };
+});
index 29b5fd2..9134944 100644 (file)
@@ -26,6 +26,7 @@ define([], function() {
     return {
         created: 'calendar-events:created',
         deleted: 'calendar-events:deleted',
+        deleteAll: 'calendar-events:delete_all',
         updated: 'calendar-events:updated',
         editEvent: 'calendar-events:edit_event',
         editActionEvent: 'calendar-events:edit_action_event',
diff --git a/calendar/amd/src/modal_delete.js b/calendar/amd/src/modal_delete.js
new file mode 100644 (file)
index 0000000..9541dec
--- /dev/null
@@ -0,0 +1,112 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contain the logic for the save/cancel modal.
+ *
+ * @module     core_calendar/modal_delete
+ * @class      modal_delete
+ * @package    core_calendar
+ * @copyright  2017 Andrew Nicols <andrew@nicols.co.uk>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define([
+    'jquery',
+    'core/notification',
+    'core/custom_interaction_events',
+    'core/modal',
+    'core/modal_events',
+    'core/modal_registry',
+    'core_calendar/events',
+],
+function(
+    $,
+    Notification,
+    CustomEvents,
+    Modal,
+    ModalEvents,
+    ModalRegistry,
+    CalendarEvents
+) {
+
+    var registered = false;
+    var SELECTORS = {
+        DELETE_ONE_BUTTON: '[data-action="deleteone"]',
+        DELETE_ALL_BUTTON: '[data-action="deleteall"]',
+        CANCEL_BUTTON: '[data-action="cancel"]',
+    };
+
+    /**
+     * Constructor for the Modal.
+     *
+     * @param {object} root The root jQuery element for the modal
+     */
+    var ModalDelete = function(root) {
+        Modal.call(this, root);
+    };
+
+    ModalDelete.TYPE = 'core_calendar-modal_delete';
+    ModalDelete.prototype = Object.create(Modal.prototype);
+    ModalDelete.prototype.constructor = ModalDelete;
+
+    /**
+     * Set up all of the event handling for the modal.
+     *
+     * @method registerEventListeners
+     */
+    ModalDelete.prototype.registerEventListeners = function() {
+        // Apply parent event listeners.
+        Modal.prototype.registerEventListeners.call(this);
+
+        this.getModal().on(CustomEvents.events.activate, SELECTORS.DELETE_ONE_BUTTON, function(e, data) {
+            var saveEvent = $.Event(ModalEvents.save);
+            this.getRoot().trigger(saveEvent, this);
+
+            if (!saveEvent.isDefaultPrevented()) {
+                this.hide();
+                data.originalEvent.preventDefault();
+            }
+        }.bind(this));
+
+        this.getModal().on(CustomEvents.events.activate, SELECTORS.DELETE_ALL_BUTTON, function(e, data) {
+            var saveEvent = $.Event(CalendarEvents.deleteAll);
+            this.getRoot().trigger(saveEvent, this);
+
+            if (!saveEvent.isDefaultPrevented()) {
+                this.hide();
+                data.originalEvent.preventDefault();
+            }
+        }.bind(this));
+
+        this.getModal().on(CustomEvents.events.activate, SELECTORS.CANCEL_BUTTON, function(e, data) {
+            var cancelEvent = $.Event(ModalEvents.cancel);
+            this.getRoot().trigger(cancelEvent, this);
+
+            if (!cancelEvent.isDefaultPrevented()) {
+                this.hide();
+                data.originalEvent.preventDefault();
+            }
+        }.bind(this));
+    };
+
+    // Automatically register with the modal registry the first time this module is imported so that you can create modals
+    // of this type using the modal factory.
+    if (!registered) {
+        ModalRegistry.register(ModalDelete.TYPE, ModalDelete, 'calendar/event_delete_modal');
+        registered = true;
+    }
+
+    return ModalDelete;
+});
index 55c9db9..5e1321c 100644 (file)
@@ -29,16 +29,19 @@ define(['jquery', 'core/ajax'], function($, Ajax) {
      *
      * @method deleteEvent
      * @param {int} eventId The event id.
+     * @arapm {bool} deleteSeries Whether to delete all events in the series
      * @return {promise} Resolved with requested calendar event
      */
-    var deleteEvent = function(eventId) {
-
+    var deleteEvent = function(eventId, deleteSeries) {
+        if (typeof deleteSeries === 'undefined') {
+            deleteSeries = false;
+        }
         var request = {
             methodname: 'core_calendar_delete_calendar_events',
             args: {
                 events: [{
                     eventid: eventId,
-                    repeat: 1
+                    repeat: deleteSeries,
                 }]
             }
         };
@@ -87,16 +90,20 @@ define(['jquery', 'core/ajax'], function($, Ajax) {
      * Get calendar data for the month view.
      *
      * @method getCalendarMonthData
-     * @param {Number} time Timestamp.
+     * @param {Number} year Year
+     * @param {Number} month Month
      * @param {Number} courseid The course id.
+     * @param {Bool} includenavigation Whether to include navigation.
      * @return {promise} Resolved with the month view data.
      */
-    var getCalendarMonthData = function(time, courseid) {
+    var getCalendarMonthData = function(year, month, courseid, includenavigation) {
         var request = {
             methodname: 'core_calendar_get_calendar_monthly_view',
             args: {
-                time: time,
-                courseid: courseid
+                year: year,
+                month: month,
+                courseid: courseid,
+                includenavigation: includenavigation,
             }
         };
 
index 89bb65a..a22a86d 100644 (file)
@@ -36,5 +36,8 @@ define([], function() {
             group: "[data-popover-eventtype-group]",
             user: "[data-popover-eventtype-user]",
         },
+        calendarPeriods: {
+            month: "[data-period='month']",
+        },
     };
 });
index da138c3..ff9317f 100644 (file)
  * @copyright  2017 Simey Lameze <simey@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-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($, Str, Notification, CustomEvents, Modal, ModalRegistry, ModalFactory, ModalEvents, CalendarRepository,
-             CalendarEvents) {
+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',
+    'core_calendar/modal_delete',
+],
+function(
+    $,
+    Str,
+    Notification,
+    CustomEvents,
+    Modal,
+    ModalRegistry,
+    ModalFactory,
+    ModalEvents,
+    CalendarRepository,
+    CalendarEvents,
+    ModalDelete
+) {
 
     var registered = false;
     var SELECTORS = {
@@ -89,6 +110,18 @@ define(['jquery', 'core/str', 'core/notification', 'core/custom_interaction_even
         return this.getBody().find(SELECTORS.ROOT).attr('data-event-id');
     };
 
+    /**
+     * Get the number of events in the series for the event being shown in
+     * this modal. This value is not cached because it will change
+     * depending on which event is being displayed.
+     *
+     * @method getEventCount
+     * @return {int}
+     */
+    ModalEventSummary.prototype.getEventCount = function() {
+        return this.getBody().find(SELECTORS.ROOT).attr('data-event-event-count');
+    };
+
     /**
      * Get the url for the event being shown in this modal.
      *
@@ -163,34 +196,76 @@ define(['jquery', 'core/str', 'core/notification', 'core/custom_interaction_even
                 key: 'deleteevent',
                 component: 'calendar'
             },
-            {
+        ];
+
+        var eventCount = parseInt(summaryModal.getEventCount(), 10);
+        var deletePromise;
+        var isRepeatedEvent = eventCount > 1;
+        if (isRepeatedEvent) {
+            deleteStrings.push({
+                key: 'confirmeventseriesdelete',
+                component: 'calendar',
+                param: {
+                    name: eventTitle,
+                    count: eventCount,
+                },
+            });
+
+            deletePromise = ModalFactory.create(
+                {
+                    type: ModalDelete.TYPE
+                },
+                summaryModal.getDeleteButton()
+            );
+        } else {
+            deleteStrings.push({
                 key: 'confirmeventdelete',
                 component: 'calendar',
                 param: eventTitle
-            }
-        ];
+            });
+
+            deletePromise = ModalFactory.create(
+                {
+                    type: ModalFactory.types.SAVE_CANCEL
+                },
+                summaryModal.getDeleteButton()
+            );
+        }
+
         var eventId = summaryModal.getEventId();
         var stringsPromise = Str.get_strings(deleteStrings);
-        var deletePromise = ModalFactory.create(
-            {
-                type: ModalFactory.types.SAVE_CANCEL
-            },
-            summaryModal.getDeleteButton()
-        );
 
-        $.when(stringsPromise, deletePromise).then(function(strings, deleteModal) {
+        $.when(stringsPromise, deletePromise)
+        .then(function(strings, deleteModal) {
             deleteModal.setTitle(strings[0]);
             deleteModal.setBody(strings[1]);
-            deleteModal.setSaveButtonText(strings[0]);
+            if (!isRepeatedEvent) {
+                deleteModal.setSaveButtonText(strings[0]);
+            }
+
             deleteModal.getRoot().on(ModalEvents.save, function() {
-                CalendarRepository.deleteEvent(eventId).then(function() {
-                    $('body').trigger(CalendarEvents.deleted, [eventId]);
-                    summaryModal.hide();
-                    return;
-                }).catch(Notification.exception);
+                CalendarRepository.deleteEvent(eventId, false)
+                    .then(function() {
+                        $('body').trigger(CalendarEvents.deleted, [eventId, false]);
+                        summaryModal.hide();
+                        return;
+                    })
+                    .catch(Notification.exception);
             });
+
+            deleteModal.getRoot().on(CalendarEvents.deleteAll, function() {
+                CalendarRepository.deleteEvent(eventId, true)
+                    .then(function() {
+                        $('body').trigger(CalendarEvents.deleted, [eventId, true]);
+                        summaryModal.hide();
+                        return;
+                    })
+                    .catch(Notification.exception);
+            });
+
             return deleteModal;
-        }).fail(Notification.exception);
+        })
+        .fail(Notification.exception);
     }
 
     // Automatically register with the modal registry the first time this module is imported so that you can create modals
index f8636ef..0934a51 100644 (file)
@@ -42,7 +42,7 @@ define(['jquery', 'core/templates', 'core/notification', 'core_calendar/reposito
             root.on('click', SELECTORS.CALENDAR_NAV_LINK, function(e) {
                 var courseId = $(root).find(SELECTORS.CALENDAR_MONTH_WRAPPER).data('courseid');
                 var link = $(e.currentTarget);
-                changeMonth(root, link.attr('href'), link.data('time'), courseId);
+                changeMonth(root, link.attr('href'), link.data('year'), link.data('month'), courseId);
 
                 e.preventDefault();
             });
@@ -51,25 +51,33 @@ define(['jquery', 'core/templates', 'core/notification', 'core_calendar/reposito
         /**
          * Refresh the month content.
          *
-         * @param {Number} time The calendar time to be shown
+         * @param {object} root The root element.
+         * @param {Number} year Year
+         * @param {Number} month Month
          * @param {Number} courseid The id of the course whose events are shown
+         * @param {object} target The element being replaced. If not specified, the calendarwrapper is used.
          * @return {promise}
          */
-        var refreshMonthContent = function(root, time, courseid) {
+        var refreshMonthContent = function(root, year, month, courseid, target) {
             startLoading(root);
 
-            return CalendarRepository.getCalendarMonthData(time, courseid)
+            target = target || root.find(SELECTORS.CALENDAR_MONTH_WRAPPER);
+
+            M.util.js_pending([root.get('id'), year, month, courseid].join('-'));
+            var includenavigation = root.data('includenavigation');
+            return CalendarRepository.getCalendarMonthData(year, month, courseid, includenavigation)
                 .then(function(context) {
                     return Templates.render(root.attr('data-template'), context);
                 })
                 .then(function(html, js) {
-                    return Templates.replaceNode(root.find(SELECTORS.CALENDAR_MONTH_WRAPPER), html, js);
+                    return Templates.replaceNode(target, html, js);
                 })
                 .then(function() {
                     $('body').trigger(CalendarEvents.viewUpdated);
                     return;
                 })
                 .always(function() {
+                    M.util.js_complete([root.get('id'), year, month, courseid].join('-'));
                     return stopLoading(root);
                 })
                 .fail(Notification.exception);
@@ -78,13 +86,15 @@ define(['jquery', 'core/templates', 'core/notification', 'core_calendar/reposito
         /**
          * Handle changes to the current calendar view.
          *
+         * @param {object} root The root element.
          * @param {String} url The calendar url to be shown
-         * @param {Number} time The calendar time to be shown
+         * @param {Number} year Year
+         * @param {Number} month Month
          * @param {Number} courseid The id of the course whose events are shown
          * @return {promise}
          */
-        var changeMonth = function(root, url, time, courseid) {
-            return refreshMonthContent(root, time, courseid)
+        var changeMonth = function(root, url, year, month, courseid) {
+            return refreshMonthContent(root, year, month, courseid)
                 .then(function() {
                     if (url.length && url !== '#') {
                         window.history.pushState({}, '', url);
@@ -92,7 +102,7 @@ define(['jquery', 'core/templates', 'core/notification', 'core_calendar/reposito
                     return arguments;
                 })
                 .then(function() {
-                    $('body').trigger(CalendarEvents.monthChanged, [time, courseid]);
+                    $('body').trigger(CalendarEvents.monthChanged, [year, month, courseid]);
                     return arguments;
                 });
         };
@@ -105,12 +115,13 @@ define(['jquery', 'core/templates', 'core/notification', 'core_calendar/reposito
          * @return {promise}
          */
         var reloadCurrentMonth = function(root, courseId) {
-            var time = root.find(SELECTORS.CALENDAR_MONTH_WRAPPER).data('current-time');
+            var year = root.find(SELECTORS.CALENDAR_MONTH_WRAPPER).data('year');
+            var month = root.find(SELECTORS.CALENDAR_MONTH_WRAPPER).data('month');
 
             if (!courseId) {
                 courseId = root.find(SELECTORS.CALENDAR_MONTH_WRAPPER).data('courseid');
             }
-            return refreshMonthContent(root, time, courseId);
+            return refreshMonthContent(root, year, month, courseId);
         };
 
         /**
index f83f273..f20c7f7 100644 (file)
@@ -28,7 +28,7 @@ defined('MOODLE_INTERNAL') || die();
 
 use \core_course\external\course_summary_exporter;
 use \renderer_base;
-
+require_once($CFG->dirroot . '/course/lib.php');
 /**
  * Class for displaying a calendar event.
  *
@@ -71,12 +71,26 @@ class calendar_event_exporter extends event_exporter_base {
         global $CFG;
 
         $values = parent::get_other_values($output);
+        $event = $this->event;
+
+        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]);
+
+            // 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 if ($event->get_type() == 'course') {
+            $url = course_get_url($event->get_course()->get('id') ?: SITEID);
+        } else {
+            // TODO MDL-58866 We do not have any way to find urls for events outside of course modules.
+            $course = $event->get_course()->get('id') ?: SITEID;
 
-        $eventid = $this->event->get_id();
-
-        $url = new \moodle_url($this->related['daylink'], [], "event_{$eventid}");
+            $url = course_get_url($course);
+        }
         $values['url'] = $url->out(false);
-
         $values['islastday'] = false;
         $today = $this->related['type']->timestamp_to_date_array($this->related['today']);
 
diff --git a/calendar/classes/external/date_exporter.php b/calendar/classes/external/date_exporter.php
new file mode 100644 (file)
index 0000000..4615b6c
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Class for normalising the date data.
+ *
+ * @package   core_calendar
+ * @copyright 2017 Andrew Nicols <andrew@nicols.co.uk>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_calendar\external;
+
+defined('MOODLE_INTERNAL') || die();
+
+use core\external\exporter;
+use renderer_base;
+use moodle_url;
+
+/**
+ * Class for normalising the date data.
+ *
+ * @package   core_calendar
+ * @copyright 2017 Andrew Nicols <andrew@nicols.co.uk>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class date_exporter extends exporter {
+
+    /**
+     * Constructor for date_exporter.
+     *
+     * @param array $data
+     * @param array $related The related information
+     */
+    public function __construct($data, $related = []) {
+        $data['timestamp'] = $data[0];
+        unset($data[0]);
+
+        parent::__construct($data, $related);
+    }
+
+    protected static function define_properties() {
+        return [
+            'seconds' => [
+                'type' => PARAM_INT,
+            ],
+            'minutes' => [
+                'type' => PARAM_INT,
+            ],
+            'hours' => [
+                'type' => PARAM_INT,
+            ],
+            'mday' => [
+                'type' => PARAM_INT,
+            ],
+            'wday' => [
+                'type' => PARAM_INT,
+            ],
+            'mon' => [
+                'type' => PARAM_INT,
+            ],
+            'year' => [
+                'type' => PARAM_INT,
+            ],
+            'yday' => [
+                'type' => PARAM_INT,
+            ],
+            'weekday' => [
+                'type' => PARAM_RAW,
+            ],
+            'month' => [
+                'type' => PARAM_RAW,
+            ],
+            'timestamp' => [
+                'type' => PARAM_INT,
+            ],
+        ];
+    }
+}
index 0f5b92b..2965451 100644 (file)
@@ -26,6 +26,8 @@ namespace core_calendar\external;
 
 defined('MOODLE_INTERNAL') || die();
 
+require_once($CFG->dirroot . '/calendar/lib.php');
+
 use core\external\exporter;
 use renderer_base;
 use moodle_url;
@@ -44,6 +46,10 @@ class day_exporter extends exporter {
      */
     protected $calendar;
 
+    /**
+     * @var moodle_url
+     */
+    protected $url;
     /**
      * Constructor.
      *
@@ -53,7 +59,11 @@ class day_exporter extends exporter {
      */
     public function __construct(\calendar_information $calendar, $data, $related) {
         $this->calendar = $calendar;
-
+        $this->url = new moodle_url('/calendar/view.php', [
+            'view' => 'day',
+            'time' => $calendar->time,
+            'course' => $this->calendar->course->id,
+        ]);
         parent::__construct($data, $related);
     }
 
@@ -87,15 +97,6 @@ class day_exporter extends exporter {
             'yday' => [
                 'type' => PARAM_INT,
             ],
-            // These are additional params.
-            'istoday' => [
-                'type' => PARAM_BOOL,
-                'default' => false,
-            ],
-            'isweekend' => [
-                'type' => PARAM_BOOL,
-                'default' => false,
-            ],
         ];
     }
 
@@ -124,6 +125,15 @@ class day_exporter extends exporter {
                 'type' => PARAM_RAW,
                 'multiple' => true,
             ],
+            'previousperiod' => [
+                'type' => PARAM_INT,
+            ],
+            'nextperiod' => [
+                'type' => PARAM_INT,
+            ],
+            'navigation' => [
+                'type' => PARAM_RAW,
+            ],
             'popovertitle' => [
                 'type' => PARAM_RAW,
                 'default' => '',
@@ -132,6 +142,12 @@ class day_exporter extends exporter {
                 'type' => PARAM_BOOL,
                 'default' => false,
             ],
+            'filter_selector' => [
+                'type' => PARAM_RAW,
+            ],
+            'new_event_button' => [
+                'type' => PARAM_RAW,
+            ],
         ];
     }
 
@@ -142,6 +158,7 @@ class day_exporter extends exporter {
      * @return array Keys are the property names, values are their values.
      */
     protected function get_other_values(renderer_base $output) {
+        $daytimestamp = $this->calendar->time;
         $timestamp = $this->data[0];
         // Need to account for user's timezone.
         $usernow = usergetdate(time());
@@ -156,24 +173,24 @@ class day_exporter extends exporter {
 
         $return = [
             'timestamp' => $timestamp,
-            'neweventtimestamp' => $neweventstarttime->getTimestamp()
+            'neweventtimestamp' => $neweventstarttime->getTimestamp(),
+            'previousperiod' => $this->get_previous_day_timestamp($daytimestamp),
+            'nextperiod' => $this->get_next_day_timestamp($daytimestamp),
+            'navigation' => $this->get_navigation(),
+            'filter_selector' => $this->get_course_filter_selector($output),
+            'new_event_button' => $this->get_new_event_button(),
         ];
 
-        $url = new moodle_url('/calendar/view.php', [
-                'view' => 'day',
-                'time' => $timestamp,
-                'course' => $this->calendar->course->id,
-            ]);
-        $return['viewdaylink'] = $url->out(false);
+        $return['viewdaylink'] = $this->url->out(false);
 
         $cache = $this->related['cache'];
-        $eventexporters = array_map(function($event) use ($cache, $output, $url) {
+        $eventexporters = array_map(function($event) use ($cache, $output) {
             $context = $cache->get_context($event);
             $course = $cache->get_course($event);
             $exporter = new calendar_event_exporter($event, [
                 'context' => $context,
                 'course' => $course,
-                'daylink' => $url,
+                'daylink' => $this->url,
                 'type' => $this->related['type'],
                 'today' => $this->data[0],
             ]);
@@ -185,10 +202,6 @@ class day_exporter extends exporter {
             return $exporter->export($output);
         }, $eventexporters);
 
-        if ($popovertitle = $this->get_popover_title()) {
-            $return['popovertitle'] = $popovertitle;
-        }
-
         $return['calendareventtypes'] = array_map(function($exporter) {
             return $exporter->get_calendar_event_type();
         }, $eventexporters);
@@ -219,24 +232,112 @@ class day_exporter extends exporter {
     }
 
     /**
-     * Get the title for this popover.
+     * Get the previous day timestamp.
+     *
+     * @param int $daytimestamp The current day timestamp.
+     * @return int The previous day timestamp.
+     */
+    protected function get_previous_day_timestamp($daytimestamp) {
+        return $this->related['type']->get_prev_day($daytimestamp);
+    }
+
+    /**
+     * Get the next day timestamp.
+     *
+     * @param int $daytimestamp The current day timestamp.
+     * @return int The next day timestamp.
+     */
+    protected function get_next_day_timestamp($daytimestamp) {
+        return $this->related['type']->get_next_day($daytimestamp);
+    }
+
+    /**
+     * Get the calendar navigation controls.
+     *
+     * @return string The html code to the calendar top navigation.
+     */
+    protected function get_navigation() {
+        return calendar_top_controls('day', [
+            'id' => $this->calendar->courseid,
+            'time' => $this->calendar->time,
+        ]);
+    }
+
+    /**
+     * Get the course filter selector.
+     *
+     * This is a temporary solution, this code will be removed by MDL-60096.
      *
-     * @return string
+     * @param renderer_base $output
+     * @return string The html code for the course filter selector.
      */
-    protected function get_popover_title() {
-        $title = null;
-
-        $userdate = userdate($this->data[0], get_string('strftimedayshort'));
-        if (count($this->related['events'])) {
-            $title = get_string('eventsfor', 'calendar', $userdate);
-        } else if ($this->data['istoday']) {
-            $title = $userdate;
+    protected function get_course_filter_selector(renderer_base $output) {
+        global $CFG;
+        // TODO remove this code on MDL-60096.
+        if (!isloggedin() or isguestuser()) {
+            return '';
         }
 
-        if ($this->data['istoday']) {
-            $title = get_string('todayplustitle', 'calendar', $userdate);
+        if (has_capability('moodle/calendar:manageentries', \context_system::instance()) && !empty($CFG->calendar_adminseesall)) {
+            $courses = get_courses('all', 'c.shortname', 'c.id, c.shortname');
+        } else {
+            $courses = enrol_get_my_courses();
         }
 
-        return $title;
+        unset($courses[SITEID]);
+
+        $courseoptions = array();
+        $courseoptions[SITEID] = get_string('fulllistofcourses');
+        foreach ($courses as $course) {
+            $coursecontext = \context_course::instance($course->id);
+            $courseoptions[$course->id] = format_string($course->shortname, true, array('context' => $coursecontext));
+        }
+
+        if ($this->calendar->courseid !== SITEID) {
+            $selected = $this->calendar->courseid;
+        } else {
+            $selected = '';
+        }
+
+        $courseurl = new moodle_url($this->url);
+        $courseurl->remove_params('course');
+        $select = new \single_select($courseurl, 'courseselect', $courseoptions, $selected, null);
+        $select->class = 'm-r-1';
+        $label = get_string('dayviewfor', 'calendar');
+        if ($label !== null) {
+            $select->set_label($label);
+        } else {
+            $select->set_label(get_string('listofcourses'), array('class' => 'accesshide'));
+        }
+
+        return $output->render($select);
+    }
+
+    /**
+     * Get the course filter selector.
+     *
+     * This is a temporary solution, this code will be removed by MDL-60096.
+     *
+     * @return string The html code for the course filter selector.
+     */
+    protected function get_new_event_button() {
+        // TODO remove this code on MDL-60096.
+        $output = \html_writer::start_tag('div', array('class' => 'buttons'));
+        $output .= \html_writer::start_tag('form',
+                array('action' => CALENDAR_URL . 'event.php', 'method' => 'get'));
+        $output .= \html_writer::start_tag('div');
+        $output .= \html_writer::empty_tag('input',
+                array('type' => 'hidden', 'name' => 'action', 'value' => 'new'));
+        $output .= \html_writer::empty_tag('input',
+                array('type' => 'hidden', 'name' => 'course', 'value' => $this->calendar->courseid));
+        $output .= \html_writer::empty_tag('input',
+                array('type' => 'hidden', 'name' => 'time', 'value' => $this->calendar->time));
+        $attributes = array('type' => 'submit', 'value' => get_string('newevent', 'calendar'),
+            'class' => 'btn btn-secondary');
+        $output .= \html_writer::empty_tag('input', $attributes);
+        $output .= \html_writer::end_tag('div');
+        $output .= \html_writer::end_tag('form');
+        $output .= \html_writer::end_tag('div');
+        return $output;
     }
 }
index 917f07e..2642423 100644 (file)
@@ -50,17 +50,6 @@ class event_exporter extends event_exporter_base {
     protected static function define_other_properties() {
 
         $values = parent::define_other_properties();
-
-        $values['displayeventsource'] = ['type' => PARAM_BOOL];
-        $values['subscription'] = [
-            'type' => PARAM_RAW,
-            'optional' => true,
-            'default' => null,
-            'null' => NULL_ALLOWED
-        ];
-        $values['isactionevent'] = ['type' => PARAM_BOOL];
-        $values['iscourseevent'] = ['type' => PARAM_BOOL];
-        $values['candelete'] = ['type' => PARAM_BOOL];
         $values['url'] = ['type' => PARAM_URL];
         $values['action'] = [
             'type' => event_action_exporter::read_properties_definition(),
@@ -70,12 +59,6 @@ class event_exporter extends event_exporter_base {
             'type' => PARAM_URL,
             'optional' => true,
         ];
-        $values['groupname'] = [
-            'type' => PARAM_RAW,
-            'optional' => true,
-            'default' => null,
-            'null' => NULL_ALLOWED
-        ];
 
         return $values;
     }
@@ -94,21 +77,16 @@ class event_exporter extends event_exporter_base {
 
         $event = $this->event;
         $context = $this->related['context'];
-        $values['isactionevent'] = false;
-        $values['iscourseevent'] = 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 if ($event->get_type() == 'course') {
-            $values['iscourseevent'] = true;
             $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.
@@ -125,31 +103,7 @@ class event_exporter extends event_exporter_base {
             $values['action'] = $actionexporter->export($output);
         }
 
-        if ($course = $this->related['course']) {
-            $coursesummaryexporter = new course_summary_exporter($course, ['context' => $context]);
-            $values['course'] = $coursesummaryexporter->export($output);
-        }
 
-        // Handle event subscription.
-        $values['subscription'] = null;
-        $values['displayeventsource'] = false;
-        if ($event->get_subscription()) {
-            $subscription = calendar_get_subscription($event->get_subscription()->get('id'));
-            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);
-            }
-        }
-
-        if ($group = $event->get_group()) {
-            $values['groupname'] = format_string($group->get('name'), true,
-                ['context' => \context_course::instance($event->get_course()->get('id'))]);
-        }
 
         return $values;
     }
index 813cb58..cb3ba80 100644 (file)
@@ -35,6 +35,7 @@ use \core_calendar\local\event\entities\event_interface;
 use \core_calendar\local\event\entities\action_event_interface;
 use \core_course\external\course_summary_exporter;
 use \renderer_base;
+use moodle_url;
 
 /**
  * Class for displaying a calendar event.
@@ -87,6 +88,7 @@ class event_exporter_base extends exporter {
 
         if ($repeats = $event->get_repeats()) {
             $data->repeatid = $repeats->get_id();
+            $data->eventcount = $repeats->get_num() + 1;
         }
 
         if ($cm = $event->get_course_module()) {
@@ -136,6 +138,12 @@ class event_exporter_base extends exporter {
                 'default' => null,
                 'null' => NULL_ALLOWED
             ],
+            'eventcount' => [
+                'type' => PARAM_INT,
+                'optional' => true,
+                'default' => null,
+                'null' => NULL_ALLOWED
+            ],
             'modulename' => [
                 'type' => PARAM_TEXT,
                 'optional' => true,
@@ -171,12 +179,37 @@ class event_exporter_base extends exporter {
                 'type' => course_summary_exporter::read_properties_definition(),
                 'optional' => true,
             ],
+            'subscription' => [
+                'type' => event_subscription_exporter::read_properties_definition(),
+                'optional' => true,
+            ],
             'canedit' => [
                 'type' => PARAM_BOOL
             ],
             'candelete' => [
                 'type' => PARAM_BOOL
             ],
+            'deleteurl' => [
+                'type' => PARAM_URL
+            ],
+            'editurl' => [
+                'type' => PARAM_URL
+            ],
+            'formattedtime' => [
+                'type' => PARAM_RAW,
+            ],
+            'isactionevent' => [
+                'type' => PARAM_BOOL
+            ],
+            'iscourseevent' => [
+                'type' => PARAM_BOOL
+            ],
+            'groupname' => [
+                'type' => PARAM_RAW,
+                'optional' => true,
+                'default' => null,
+                'null' => NULL_ALLOWED
+            ],
         ];
     }
 
@@ -191,19 +224,48 @@ class event_exporter_base extends exporter {
         $event = $this->event;
         $legacyevent = container::get_event_mapper()->from_event_to_legacy_event($event);
         $context = $this->related['context'];
+        $values['isactionevent'] = false;
+        $values['iscourseevent'] = false;
+        if ($moduleproxy = $event->get_course_module()) {
+            $values['isactionevent'] = true;
+        } else if ($event->get_type() == 'course') {
+            $values['iscourseevent'] = true;
+        }
         $timesort = $event->get_times()->get_sort_time()->getTimestamp();
         $iconexporter = new event_icon_exporter($event, ['context' => $context]);
 
         $values['icon'] = $iconexporter->export($output);
 
+        $subscriptionexporter = new event_subscription_exporter($event);
+        $values['subscription'] = $subscriptionexporter->export($output);
+
         if ($course = $this->related['course']) {
             $coursesummaryexporter = new course_summary_exporter($course, ['context' => $context]);
             $values['course'] = $coursesummaryexporter->export($output);
         }
+        $courseid = (!$course) ? SITEID : $course->id;
 
         $values['canedit'] = calendar_edit_event_allowed($legacyevent, true);
         $values['candelete'] = calendar_delete_event_allowed($legacyevent);
 
+        $deleteurl = new moodle_url('/calendar/delete.php', ['id' => $event->get_id(), 'course' => $courseid]);
+        $values['deleteurl'] = $deleteurl->out(false);
+
+        $editurl = new moodle_url('/calendar/event.php', ['action' => 'edit', 'id' => $event->get_id(),
+                'course' => $courseid]);
+        $values['editurl'] = $editurl->out(false);
+        $values['formattedtime'] = calendar_format_event_time($legacyevent, time(), null, false,
+                $timesort);
+
+        if ($course = $this->related['course']) {
+            $coursesummaryexporter = new course_summary_exporter($course, ['context' => $context]);
+            $values['course'] = $coursesummaryexporter->export($output);
+        }
+
+        if ($group = $event->get_group()) {
+            $values['groupname'] = format_string($group->get('name'), true,
+                ['context' => \context_course::instance($event->get_course()->get('id'))]);
+        }
         return $values;
     }
 
diff --git a/calendar/classes/external/event_subscription_exporter.php b/calendar/classes/external/event_subscription_exporter.php
new file mode 100644 (file)
index 0000000..5a8075b
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contains event class for displaying a calendar event's subscription.
+ *
+ * @package   core_calendar
+ * @copyright 2017 Simey Lameze <simey@moodle.com>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_calendar\external;
+
+defined('MOODLE_INTERNAL') || die();
+
+use \core\external\exporter;
+use \core_calendar\local\event\entities\event_interface;
+
+/**
+ * Class for displaying a calendar event's subscription.
+ *
+ * @package   core_calendar
+ * @copyright 2017 Simey Lameze <simey@moodle.com>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class event_subscription_exporter extends exporter {
+
+    /**
+     * Constructor.
+     *
+     * @param event_interface $event
+     */
+    public function __construct(event_interface $event) {
+        global $CFG;
+
+        $data = new \stdClass();
+        $data->displayeventsource = false;
+        if ($event->get_subscription()) {
+            $subscription = calendar_get_subscription($event->get_subscription()->get('id'));
+            if (!empty($subscription) && $CFG->calendar_showicalsource) {
+                $data->displayeventsource = true;
+                if (!empty($subscription->url)) {
+                    $data->url = $subscription->url;
+                }
+                $data->name = $subscription->name;
+            }
+        }
+
+        parent::__construct($data);
+    }
+
+    /**
+     * Return the list of properties.
+     *
+     * @return array
+     */
+    protected static function define_properties() {
+        return [
+            'displayeventsource' => [
+                'type' => PARAM_BOOL
+            ],
+            'name' => [
+                'type' => PARAM_RAW,
+                'optional' => true
+            ],
+            'url' => [
+                'type' => PARAM_URL,
+                'optional' => true
+            ],
+        ];
+    }
+}
index 23bb42f..e4478bb 100644 (file)
@@ -82,9 +82,10 @@ class footer_options_exporter extends exporter {
      * @return string The iCal url.
      */
     protected function get_ical_url() {
-        return new moodle_url('/calendar/export_execute.php', ['preset_what' => 'all',
-                'preset_time' => 'recentupcoming', 'userid' => $this->userid, 'authtoken' => $this->token]);
-
+        if ($this->token) {
+            return new moodle_url('/calendar/export_execute.php', ['preset_what' => 'all',
+                    'preset_time' => 'recentupcoming', 'userid' => $this->userid, 'authtoken' => $this->token]);
+        }
     }
 
     /**
@@ -113,10 +114,12 @@ class footer_options_exporter extends exporter {
         $values = new stdClass();
 
         if (!empty($CFG->enablecalendarexport)) {
-            $exportbutton = $this->get_export_calendar_button();
-            $managesubscriptionbutton = $this->get_manage_subscriptions_button();
-            $values->exportcalendarbutton = $exportbutton->export_for_template($output);
-            $values->managesubscriptionbutton = $managesubscriptionbutton->export_for_template($output);
+            if ($exportbutton = $this->get_export_calendar_button()) {
+                $values->exportcalendarbutton = $exportbutton->export_for_template($output);
+            }
+            if ($managesubscriptionbutton = $this->get_manage_subscriptions_button()) {
+                $values->managesubscriptionbutton = $managesubscriptionbutton->export_for_template($output);
+            }
             $values->icalurl = $this->get_ical_url()->out(false);
         }
 
@@ -132,12 +135,15 @@ class footer_options_exporter extends exporter {
         return array(
             'exportcalendarbutton' => [
                 'type' => PARAM_RAW,
+                'default' => null,
             ],
             'managesubscriptionbutton' => [
                 'type' => PARAM_RAW,
+                'default' => null,
             ],
             'icalurl' => [
                 'type' => PARAM_URL,
+                'default' => null,
             ],
         );
     }
index 6d180aa..b71ccc8 100644 (file)
@@ -54,6 +54,11 @@ class month_exporter extends exporter {
      */
     protected $url;
 
+    /**
+     * @var bool $includenavigation Whether navigation should be included on the output.
+     */
+    protected $includenavigation = true;
+
     /**
      * Constructor for month_exporter.
      *
@@ -104,9 +109,6 @@ class month_exporter extends exporter {
             'filter_selector' => [
                 'type' => PARAM_RAW,
             ],
-            'navigation' => [
-                'type' => PARAM_RAW,
-            ],
             'weeks' => [
                 'type' => week_exporter::read_properties_definition(),
                 'multiple' => true,
@@ -118,16 +120,23 @@ class month_exporter extends exporter {
             'view' => [
                 'type' => PARAM_ALPHA,
             ],
-            'time' => [
-                'type' => PARAM_INT,
+            'date' => [
+                'type' => date_exporter::read_properties_definition(),
             ],
             'periodname' => [
                 // Note: We must use RAW here because the calendar type returns the formatted month name based on a
                 // calendar format.
                 'type' => PARAM_RAW,
             ],
+            'includenavigation' => [
+                'type' => PARAM_BOOL,
+                'default' => true,
+            ],
             'previousperiod' => [
-                'type' => PARAM_INT,
+                'type' => date_exporter::read_properties_definition(),
+            ],
+            'previousperiodlink' => [
+                'type' => PARAM_URL,
             ],
             'previousperiodname' => [
                 // Note: We must use RAW here because the calendar type returns the formatted month name based on a
@@ -135,13 +144,16 @@ class month_exporter extends exporter {
                 'type' => PARAM_RAW,
             ],
             'nextperiod' => [
-                'type' => PARAM_INT,
+                'type' => date_exporter::read_properties_definition(),
             ],
             'nextperiodname' => [
                 // Note: We must use RAW here because the calendar type returns the formatted month name based on a
                 // calendar format.
                 'type' => PARAM_RAW,
             ],
+            'nextperiodlink' => [
+                'type' => PARAM_URL,
+            ],
             'larrow' => [
                 // The left arrow defined by the theme.
                 'type' => PARAM_RAW,
@@ -150,6 +162,10 @@ class month_exporter extends exporter {
                 // The right arrow defined by the theme.
                 'type' => PARAM_RAW,
             ],
+            'defaulteventcontext' => [
+                'type' => PARAM_INT,
+                'default' => null,
+            ],
         ];
     }
 
@@ -160,25 +176,40 @@ class month_exporter extends exporter {
      * @return array Keys are the property names, values are their values.
      */
     protected function get_other_values(renderer_base $output) {
-        $previousperiod = $this->get_previous_month_timestamp();
-        $nextperiod = $this->get_next_month_timestamp();
+        $previousperiod = $this->get_previous_month_data();
+        $nextperiod = $this->get_next_month_data();
+        $date = $this->related['type']->timestamp_to_date_array($this->calendar->time);
 
-        return [
+        $nextperiodlink = new moodle_url($this->url);
+        $nextperiodlink->param('time', $nextperiod[0]);
+
+        $previousperiodlink = new moodle_url($this->url);
+        $previousperiodlink->param('time', $previousperiod[0]);
+
+        $return = [
             'courseid' => $this->calendar->courseid,
             'filter_selector' => $this->get_course_filter_selector($output),
-            'navigation' => $this->get_navigation($output),
             'weeks' => $this->get_weeks($output),
             'daynames' => $this->get_day_names($output),
             'view' => 'month',
-            'time' => $this->calendar->time,
+            'date' => (new date_exporter($date))->export($output),
             'periodname' => userdate($this->calendar->time, get_string('strftimemonthyear')),
-            'previousperiod' => $previousperiod,
-            'previousperiodname' => userdate($previousperiod, get_string('strftimemonthyear')),
-            'nextperiod' => $nextperiod,
-            'nextperiodname' => userdate($nextperiod, get_string('strftimemonthyear')),
+            'previousperiod' => (new date_exporter($previousperiod))->export($output),
+            'previousperiodname' => userdate($previousperiod[0], get_string('strftimemonthyear')),
+            'previousperiodlink' => $previousperiodlink->out(false),
+            'nextperiod' => (new date_exporter($nextperiod))->export($output),
+            'nextperiodname' => userdate($nextperiod[0], get_string('strftimemonthyear')),
+            'nextperiodlink' => $nextperiodlink->out(false),
             'larrow' => $output->larrow(),
             'rarrow' => $output->rarrow(),
+            'includenavigation' => $this->includenavigation,
         ];
+
+        if ($context = $this->get_default_add_context()) {
+            $return['defaulteventcontext'] = $context->id;
+        }
+
+        return $return;
     }
 
     /**
@@ -190,26 +221,10 @@ class month_exporter extends exporter {
     protected function get_course_filter_selector(renderer_base $output) {
         $content = '';
         $content .= $output->course_filter_selector($this->url, get_string('detailedmonthviewfor', 'calendar'));
-        if (calendar_user_can_add_event($this->calendar->course)) {
-            $content .= $output->add_event_button($this->calendar->courseid, 0, 0, 0, $this->calendar->time);
-        }
 
         return $content;
     }
 
-    /**
-     * Get the calendar navigation controls.
-     *
-     * @param renderer_base $output
-     * @return string The html code to the calendar top navigation.
-     */
-    protected function get_navigation(renderer_base $output) {
-        return calendar_top_controls('month', [
-            'id' => $this->calendar->courseid,
-            'time' => $this->calendar->time,
-        ]);
-    }
-
     /**
      * Get the list of day names for display, re-ordered from the first day
      * of the week.
@@ -302,17 +317,30 @@ class month_exporter extends exporter {
         ];
     }
 
+    /**
+     * Get the current month timestamp.
+     *
+     * @return int The month timestamp.
+     */
+    protected function get_month_data() {
+        $date = $this->related['type']->timestamp_to_date_array($this->calendar->time);
+        $monthtime = $this->related['type']->convert_to_gregorian($date['year'], $date['month'], 1);
+
+        return make_timestamp($monthtime['year'], $monthtime['month']);
+    }
+
     /**
      * Get the previous month timestamp.
      *
      * @return int The previous month timestamp.
      */
-    protected function get_previous_month_timestamp() {
-        $date = $this->related['type']->timestamp_to_date_array($this->calendar->time);
-        $month = calendar_sub_month($date['mon'], $date['year']);
-        $monthtime = $this->related['type']->convert_to_gregorian($month[1], $month[0], 1);
+    protected function get_previous_month_data() {
+        $type = $this->related['type'];
+        $date = $type->timestamp_to_date_array($this->calendar->time);
+        list($date['mon'], $date['year']) = $type->get_prev_month($date['year'], $date['mon']);
+        $time = $type->convert_to_timestamp($date['year'], $date['mon'], 1);
 
-        return make_timestamp($monthtime['year'], $monthtime['month'], $monthtime['day'], $monthtime['hour'], $monthtime['minute']);
+        return $type->timestamp_to_date_array($time);
     }
 
     /**
@@ -320,11 +348,37 @@ class month_exporter extends exporter {
      *
      * @return int The next month timestamp.
      */
-    protected function get_next_month_timestamp() {
-        $date = $this->related['type']->timestamp_to_date_array($this->calendar->time);
-        $month = calendar_add_month($date['mon'], $date['year']);
-        $monthtime = $this->related['type']->convert_to_gregorian($month[1], $month[0], 1);
+    protected function get_next_month_data() {
+        $type = $this->related['type'];
+        $date = $type->timestamp_to_date_array($this->calendar->time);
+        list($date['mon'], $date['year']) = $type->get_next_month($date['year'], $date['mon']);
+        $time = $type->convert_to_timestamp($date['year'], $date['mon'], 1);
+
+        return $type->timestamp_to_date_array($time);
+    }
+
+    /**
+     * Set whether the navigation should be shown.
+     *
+     * @param   bool    $include
+     * @return  $this
+     */
+    public function set_includenavigation($include) {
+        $this->includenavigation = $include;
+
+        return $this;
+    }
+
+    /**
+     * Get the default context for use when adding a new event.
+     *
+     * @return null|\context
+     */
+    protected function get_default_add_context() {
+        if (calendar_user_can_add_event($this->calendar->course)) {
+            return \context_course::instance($this->calendar->course->id);
+        }
 
-        return make_timestamp($monthtime['year'], $monthtime['month'], $monthtime['day'], $monthtime['hour'], $monthtime['minute']);
+        return null;
     }
 }
index 67442f5..e974154 100644 (file)
@@ -38,6 +38,27 @@ use moodle_url;
  */
 class week_day_exporter extends day_exporter {
 
+    /**
+     * Return the list of properties.
+     *
+     * @return array
+     */
+    protected static function define_properties() {
+        $return = parent::define_properties();
+        $return = array_merge($return, [
+            // These are additional params.
+            'istoday' => [
+                'type' => PARAM_BOOL,
+                'default' => false,
+            ],
+            'isweekend' => [
+                'type' => PARAM_BOOL,
+                'default' => false,
+            ],
+        ]);
+
+        return $return;
+    }
     /**
      * Return the list of additional properties.
      *
@@ -92,18 +113,18 @@ class week_day_exporter extends day_exporter {
             $usernow['seconds']
         );
 
-        $return = [
-            'timestamp' => $timestamp,
-            'neweventtimestamp' => $neweventstarttime->getTimestamp()
-        ];
+        $return = parent::get_other_values($output);
 
         $url = new moodle_url('/calendar/view.php', [
                 'view' => 'day',
                 'time' => $timestamp,
                 'course' => $this->calendar->course->id,
-            ]);
-        $return['viewdaylink'] = $url->out(false);
+        ]);
 
+        $return['viewdaylink'] = $url->out(false);
+        if ($popovertitle = $this->get_popover_title()) {
+            $return['popovertitle'] = $popovertitle;
+        }
         $cache = $this->related['cache'];
         $eventexporters = array_map(function($event) use ($cache, $output, $url) {
             $context = $cache->get_context($event);
index 5c5d7d6..0ba6d54 100644 (file)
@@ -231,15 +231,47 @@ class api {
     ) {
         $mapper = container::get_event_mapper();
         $legacyevent = $mapper->from_event_to_legacy_event($event);
+        $hascoursemodule = !empty($event->get_course_module());
         $starttime = $event->get_times()->get_start_time()->setDate(
             $startdate->format('Y'),
             $startdate->format('n'),
             $startdate->format('j')
         );
 
+        if ($hascoursemodule) {
+            $legacyevent->timestart = $starttime->getTimestamp();
+            // If this event is from an activity then we need to call
+            // the activity callback to let it validate that the changes
+            // to the event are correct.
+            component_callback(
+                'mod_' . $event->get_course_module()->get('modname'),
+                'core_calendar_validate_event_timestart',
+                [$legacyevent]
+            );
+        }
+
         // This function does our capability checks.
         $legacyevent->update((object) ['timestart' => $starttime->getTimestamp()]);
 
+        // Check that the user is allowed to manually edit calendar events before
+        // calling the event updated callback. The manual flag causes the code to
+        // check the user has the capabilities to modify the modules.
+        //
+        // We don't want to call the event update callback if the user isn't allowed
+        // to modify course modules because depending on the callback it can make
+        // some changes that would be considered security issues, such as updating the
+        // due date for and assignment.
+        if ($hascoursemodule && calendar_edit_event_allowed($legacyevent, true)) {
+            // If this event is from an activity then we need to call
+            // the activity callback to let it know that the event it
+            // created has been modified so it needs to update accordingly.
+            component_callback(
+                'mod_' . $event->get_course_module()->get('modname'),
+                'core_calendar_event_timestart_updated',
+                [$legacyevent]
+            );
+        }
+
         return $mapper->from_legacy_event_to_event($legacyevent);
     }
 }
index a211be1..75e4bad 100644 (file)
@@ -239,4 +239,32 @@ abstract class type_base {
             $gregorianinfo['minute'],
             0);
     }
+
+    /**
+     * Get the previous day.
+     *
+     * @param int $daytimestamp The day timestamp.
+     * @return int previous day timestamp
+     */
+    public function get_prev_day($daytimestamp) {
+        $date = new \DateTime();
+        $date->setTimestamp($daytimestamp);
+        $date->modify('-1 day');
+
+        return $date->getTimestamp();
+    }
+
+    /**
+     * Get the next day.
+     *
+     * @param int $daytimestamp The day timestamp.
+     * @return int the following day
+     */
+    public function get_next_day($daytimestamp) {
+        $date = new \DateTime();
+        $date->setTimestamp($daytimestamp);
+        $date->modify('+1 day');
+
+        return $date->getTimestamp();
+    }
 }
index afad7dd..336c0f0 100644 (file)
@@ -879,18 +879,22 @@ class core_calendar_external extends external_api {
     /**
      * Get data for the monthly calendar view.
      *
-     * @param   int     $time The time to be shown
+     * @param   int     $year The year to be shown
+     * @param   int     $month The month to be shown
      * @param   int     $courseid The course to be included
+     * @param   bool    $includenavigation Whether to include navigation
      * @return  array
      */
-    public static function get_calendar_monthly_view($time, $courseid) {
+    public static function get_calendar_monthly_view($year, $month, $courseid, $includenavigation) {
         global $CFG, $DB, $USER, $PAGE;
         require_once($CFG->dirroot."/calendar/lib.php");
 
         // Parameter validation.
         $params = self::validate_parameters(self::get_calendar_monthly_view_parameters(), [
-            'time' => $time,
+            'year' => $year,
+            'month' => $month,
             'courseid' => $courseid,
+            'includenavigation' => $includenavigation,
         ]);
 
         if ($courseid != SITEID && !empty($courseid)) {
@@ -906,10 +910,13 @@ class core_calendar_external extends external_api {
         $context = \context_user::instance($USER->id);
         self::validate_context($context);
 
+        $type = \core_calendar\type_factory::get_calendar_instance();
+
+        $time = $type->convert_to_timestamp($year, $month, 1);
         $calendar = new calendar_information(0, 0, 0, $time);
         $calendar->prepare_for_view($course, $courses);
 
-        list($data, $template) = calendar_get_view($calendar, 'month');
+        list($data, $template) = calendar_get_view($calendar, 'month', $params['includenavigation']);
 
         return $data;
     }
@@ -922,8 +929,16 @@ class core_calendar_external extends external_api {
     public static function get_calendar_monthly_view_parameters() {
         return new external_function_parameters(
             [
-                'time' => new external_value(PARAM_INT, 'Time to be viewed', VALUE_REQUIRED, '', NULL_NOT_ALLOWED),
+                'year' => new external_value(PARAM_INT, 'Month to be viewed', VALUE_REQUIRED),
+                'month' => new external_value(PARAM_INT, 'Year to be viewed', VALUE_REQUIRED),
                 'courseid' => new external_value(PARAM_INT, 'Course being viewed', VALUE_DEFAULT, SITEID, NULL_ALLOWED),
+                'includenavigation' => new external_value(
+                    PARAM_BOOL,
+                    'Whether to show course navigation',
+                    VALUE_DEFAULT,
+                    true,
+                    NULL_ALLOWED
+                ),
             ]
         );
     }
index 0c168ba..d511497 100644 (file)
@@ -973,15 +973,29 @@ class calendar_information {
                 $year =  $date['year'];
             }
             if (checkdate($month, $day, $year)) {
-                $this->time = make_timestamp($year, $month, $day);
+                $time = make_timestamp($year, $month, $day);
             } else {
-                $this->time = time();
+                $time = time();
             }
-        } else if (!empty($time)) {
-            $this->time = $time;
-        } else {
+        }
+
+        $this->set_time($time);
+    }
+
+    /**
+     * Set the time period of this instance.
+     *
+     * @param   int $time the unixtimestamp representing the date we want to view.
+     * @return  $this
+     */
+    public function set_time($time = null) {
+        if ($time === null) {
             $this->time = time();
+        } else {
+            $this->time = $time;
         }
+
+        return $this;
     }
 
     /**
@@ -1207,393 +1221,6 @@ function calendar_get_starting_weekday() {
     return $calendartype->get_starting_weekday();
 }
 
-/**
- * Generates the HTML for a miniature calendar.
- *
- * @param array $courses list of course to list events from
- * @param array $groups list of group
- * @param array $users user's info
- * @param int|bool $calmonth calendar month in numeric, default is set to false
- * @param int|bool $calyear calendar month in numeric, default is set to false
- * @param string|bool $placement the place/page the calendar is set to appear - passed on the the controls function
- * @param int|bool $courseid id of the course the calendar is displayed on - passed on the the controls function
- * @param int $time the unixtimestamp representing the date we want to view, this is used instead of $calmonth
- *     and $calyear to support multiple calendars
- * @return string $content return html table for mini calendar
- */
-function calendar_get_mini($courses, $groups, $users, $calmonth = false, $calyear = false, $placement = false,
-                           $courseid = false, $time = 0) {
-    global $CFG, $OUTPUT;
-
-    // Get the calendar type we are using.
-    $calendartype = \core_calendar\type_factory::get_calendar_instance();
-
-    $display = new \stdClass;
-
-    // Assume we are not displaying this month for now.
-    $display->thismonth = false;
-
-    $content = '';
-
-    // Do this check for backwards compatibility.
-    // The core should be passing a timestamp rather than month and year.
-    // If a month and year are passed they will be in Gregorian.
-    if (!empty($calmonth) && !empty($calyear)) {
-        // Ensure it is a valid date, else we will just set it to the current timestamp.
-        if (checkdate($calmonth, 1, $calyear)) {
-            $time = make_timestamp($calyear, $calmonth, 1);
-        } else {
-            $time = time();
-        }
-        $date = usergetdate($time);
-        if ($calmonth == $date['mon'] && $calyear == $date['year']) {
-            $display->thismonth = true;
-        }
-        // We can overwrite date now with the date used by the calendar type,
-        // if it is not Gregorian, otherwise there is no need as it is already in Gregorian.
-        if ($calendartype->get_name() != 'gregorian') {
-            $date = $calendartype->timestamp_to_date_array($time);
-        }
-    } else if (!empty($time)) {
-        // Get the specified date in the calendar type being used.
-        $date = $calendartype->timestamp_to_date_array($time);
-        $thisdate = $calendartype->timestamp_to_date_array(time());
-        if ($date['month'] == $thisdate['month'] && $date['year'] == $thisdate['year']) {
-            $display->thismonth = true;
-            // If we are the current month we want to set the date to the current date, not the start of the month.
-            $date = $thisdate;
-        }
-    } else {
-        // Get the current date in the calendar type being used.
-        $time = time();
-        $date = $calendartype->timestamp_to_date_array($time);
-        $display->thismonth = true;
-    }
-
-    list($d, $m, $y) = array($date['mday'], $date['mon'], $date['year']); // This is what we want to display.
-
-    // Get Gregorian date for the start of the month.
-    $gregoriandate = $calendartype->convert_to_gregorian($date['year'], $date['mon'], 1);
-
-    // Store the gregorian date values to be used later.
-    list($gy, $gm, $gd, $gh, $gmin) = array($gregoriandate['year'], $gregoriandate['month'], $gregoriandate['day'],
-        $gregoriandate['hour'], $gregoriandate['minute']);
-
-    // Get the max number of days in this month for this calendar type.
-    $display->maxdays = calendar_days_in_month($m, $y);
-    // Get the starting week day for this month.
-    $startwday = dayofweek(1, $m, $y);
-    // Get the days in a week.
-    $daynames = calendar_get_days();
-    // Store the number of days in a week.
-    $numberofdaysinweek = $calendartype->get_num_weekdays();
-
-    // Set the min and max weekday.
-    $display->minwday = calendar_get_starting_weekday();
-    $display->maxwday = $display->minwday + ($numberofdaysinweek - 1);
-
-    // These are used for DB queries, so we want unixtime, so we need to use Gregorian dates.
-    $display->tstart = make_timestamp($gy, $gm, $gd, $gh, $gmin, 0);
-    $display->tend = $display->tstart + ($display->maxdays * DAYSECS) - 1;
-
-    // Align the starting weekday to fall in our display range.
-    // This is simple, not foolproof.
-    if ($startwday < $display->minwday) {
-        $startwday += $numberofdaysinweek;
-    }
-
-    // Get the events matching our criteria. Don't forget to offset the timestamps for the user's TZ.
-    $events = calendar_get_legacy_events($display->tstart, $display->tend, $users, $groups, $courses);
-
-    // Set event course class for course events.
-    if (!empty($events)) {
-        foreach ($events as $eventid => $event) {
-            if (!empty($event->modulename)) {
-                $instances = get_fast_modinfo($event->courseid)->get_instances_of($event->modulename);
-                if (empty($instances[$event->instance]->uservisible)) {
-                    unset($events[$eventid]);
-                }
-            }
-        }
-    }
-
-    // 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);
-        }
-    }
-
-    // We want to have easy access by day, since the display is on a per-day basis.
-    calendar_events_by_day($events, $m, $y, $eventsbyday, $durationbyday, $typesbyday, $courses);
-
-    // Accessibility: added summary and <abbr> elements.
-    $summary = get_string('calendarheading', 'calendar', userdate($display->tstart, get_string('strftimemonthyear')));
-    // Begin table.
-    $content .= '<table class="minicalendar calendartable" summary="' . $summary . '">';
-    if (($placement !== false) && ($courseid !== false)) {
-        $content .= '<caption>' . calendar_top_controls($placement,
-                array('id' => $courseid, 'time' => $time)) . '</caption>';
-    }
-    $content .= '<tr class="weekdays">'; // Header row: day names.
-
-    // Print out the names of the weekdays.
-    for ($i = $display->minwday; $i <= $display->maxwday; $i++) {
-        $pos = $i % $numberofdaysinweek;
-        $content .= '<th scope="col"><abbr title="' . $daynames[$pos]['fullname'] . '">' .
-            $daynames[$pos]['shortname'] . "</abbr></th>\n";
-    }
-
-    $content .= '</tr><tr>'; // End of day names; prepare for day numbers.
-
-    // For the table display. $week is the row; $dayweek is the column.
-    $dayweek = $startwday;
-
-    // Padding (the first week may have blank days in the beginning).
-    for ($i = $display->minwday; $i < $startwday; ++$i) {
-        $content .= '<td class="dayblank">&nbsp;</td>' ."\n";
-    }
-
-    $weekend = CALENDAR_DEFAULT_WEEKEND;
-    if (isset($CFG->calendar_weekend)) {
-        $weekend = intval($CFG->calendar_weekend);
-    }
-
-    // Now display all the calendar.
-    $daytime = strtotime('-1 day', $display->tstart);
-    for ($day = 1; $day <= $display->maxdays; ++$day, ++$dayweek) {
-        $cellattributes = array();
-        $daytime = strtotime('+1 day', $daytime);
-        if ($dayweek > $display->maxwday) {
-            // We need to change week (table row).
-            $content .= '</tr><tr>';
-            $dayweek = $display->minwday;
-        }
-
-        // Reset vars.
-        if ($weekend & (1 << ($dayweek % $numberofdaysinweek))) {
-            // Weekend. This is true no matter what the exact range is.
-            $class = 'weekend day';
-        } else {
-            // Normal working day.
-            $class = 'day';
-        }
-
-        $eventids = array();
-        if (!empty($eventsbyday[$day])) {
-            $eventids = $eventsbyday[$day];
-        }
-
-        if (!empty($durationbyday[$day])) {
-            $eventids = array_unique(array_merge($eventids, $durationbyday[$day]));
-        }
-
-        $finishclass = false;
-
-        if (!empty($eventids)) {
-            // There is at least one event on this day.
-            $class .= ' hasevent';
-            $hrefparams['view'] = 'day';
-            $dayhref = calendar_get_link_href(new \moodle_url(CALENDAR_URL . 'view.php', $hrefparams), 0, 0, 0, $daytime);
-
-            $popupcontent = '';
-            foreach ($eventids as $eventid) {
-                if (!isset($events[$eventid])) {
-                    continue;
-                }
-                $event = new \calendar_event($events[$eventid]);
-                $popupalt  = '';
-                $component = 'moodle';
-                if (!empty($event->modulename)) {
-                    $popupicon = 'icon';
-                    $popupalt  = $event->modulename;
-                    $component = $event->modulename;
-                } else if ($event->courseid == SITEID) { // Site event.
-                    $popupicon = 'i/siteevent';
-                } else if ($event->courseid != 0 && $event->courseid != SITEID
-                    && $event->groupid == 0) { // Course event.
-                    $popupicon = 'i/courseevent';
-                } else if ($event->groupid) { // Group event.
-                    $popupicon = 'i/groupevent';
-                } else { // Must be a user event.
-                    $popupicon = 'i/userevent';
-                }
-
-                if ($event->timeduration) {
-                    $startdate = $calendartype->timestamp_to_date_array($event->timestart);
-                    $enddate = $calendartype->timestamp_to_date_array($event->timestart + $event->timeduration - 1);
-                    if ($enddate['mon'] == $m && $enddate['year'] == $y && $enddate['mday'] == $day) {
-                        $finishclass = true;
-                    }
-                }
-
-                $dayhref->set_anchor('event_' . $event->id);
-
-                $popupcontent .= \html_writer::start_tag('div');
-                $popupcontent .= $OUTPUT->pix_icon($popupicon, $popupalt, $component);
-                // Show ical source if needed.
-                if (!empty($event->subscription) && $CFG->calendar_showicalsource) {
-                    $a = new \stdClass();
-                    $a->name = format_string($event->name, true);
-                    $a->source = $event->subscription->name;
-                    $name = get_string('namewithsource', 'calendar', $a);
-                } else {
-                    if ($finishclass) {
-                        $samedate = $startdate['mon'] == $enddate['mon'] &&
-                            $startdate['year'] == $enddate['year'] &&
-                            $startdate['mday'] == $enddate['mday'];
-
-                        if ($samedate) {
-                            $name = format_string($event->name, true);
-                        } else {
-                            $name = format_string($event->name, true) . ' (' . get_string('eventendtime', 'calendar') . ')';
-                        }
-                    } else {
-                        $name = format_string($event->name, true);
-                    }
-                }
-                // Include course's shortname into the event name, if applicable.
-                if (!empty($event->courseid) && $event->courseid !== SITEID) {
-                    $course = get_course($event->courseid);
-                    $eventnameparams = (object)[
-                        'name' => $name,
-                        'course' => format_string($course->shortname, true, array('context' => $event->context))
-                    ];
-                    $name = get_string('eventnameandcourse', 'calendar', $eventnameparams);
-                }
-                $popupcontent .= \html_writer::link($dayhref, $name);
-                $popupcontent .= \html_writer::end_tag('div');
-            }
-
-            if ($display->thismonth && $day == $d) {
-                $popupdata = calendar_get_popup(true, $daytime, $popupcontent);
-            } else {
-                $popupdata = calendar_get_popup(false, $daytime, $popupcontent);
-            }
-
-            // Class and cell content.
-            if (isset($typesbyday[$day]['startglobal'])) {
-                $class .= ' calendar_event_site';
-            } else if (isset($typesbyday[$day]['startcourse'])) {
-                $class .= ' calendar_event_course';
-            } else if (isset($typesbyday[$day]['startgroup'])) {
-                $class .= ' calendar_event_group';
-            } else if (isset($typesbyday[$day]['startuser'])) {
-                $class .= ' calendar_event_user';
-            }
-            if ($finishclass) {
-                $class .= ' duration_finish';
-            }
-            $data = array(
-                'url' => $dayhref->out(false),
-                'day' => $day,
-                'content' => $popupdata['data-core_calendar-popupcontent'],
-                'title' => $popupdata['data-core_calendar-title']
-            );
-            $cell = $OUTPUT->render_from_template('core_calendar/minicalendar_day_link', $data);
-        } else {
-            $cell = $day;
-        }
-
-        $durationclass = false;
-        if (isset($typesbyday[$day]['durationglobal'])) {
-            $durationclass = ' duration_global';
-        } else if (isset($typesbyday[$day]['durationcourse'])) {
-            $durationclass = ' duration_course';
-        } else if (isset($typesbyday[$day]['durationgroup'])) {
-            $durationclass = ' duration_group';
-        } else if (isset($typesbyday[$day]['durationuser'])) {
-            $durationclass = ' duration_user';
-        }
-        if ($durationclass) {
-            $class .= ' duration ' . $durationclass;
-        }
-
-        // If event has a class set then add it to the table day <td> tag.
-        // Note: only one colour for minicalendar.
-        if (isset($eventsbyday[$day])) {
-            foreach ($eventsbyday[$day] as $eventid) {
-                if (!isset($events[$eventid])) {
-                    continue;
-                }
-                $event = $events[$eventid];
-                if (!empty($event->class)) {
-                    $class .= ' ' . $event->class;
-                }
-                break;
-            }
-        }
-
-        if ($display->thismonth && $day == $d) {
-            // The current cell is for today - add appropriate classes and additional information for styling.
-            $class .= ' today';
-            $today = get_string('today', 'calendar') . ' ' . userdate(time(), get_string('strftimedayshort'));
-
-            if (!isset($eventsbyday[$day]) && !isset($durationbyday[$day])) {
-                $class .= ' eventnone';
-                $popupdata = calendar_get_popup(true, false);
-                $data = array(
-                    'url' => '#',
-                    'day' => $day,
-                    'content' => $popupdata['data-core_calendar-popupcontent'],
-                    'title' => $popupdata['data-core_calendar-title']
-                );
-                $cell = $OUTPUT->render_from_template('core_calendar/minicalendar_day_link', $data);
-            }
-            $cell = get_accesshide($today . ' ') . $cell;
-        }
-
-        // Just display it.
-        $cellattributes['class'] = $class;
-        $content .= \html_writer::tag('td', $cell, $cellattributes);
-    }
-
-    // Padding (the last week may have blank days at the end).
-    for ($i = $dayweek; $i <= $display->maxwday; ++$i) {
-        $content .= '<td class="dayblank">&nbsp;</td>';
-    }
-    $content .= '</tr>'; // Last row ends.
-
-    $content .= '</table>'; // Tabular display of days ends.
-    return $content;
-}
-
-/**
- * Gets the calendar popup.
- *
- * It called at multiple points in from calendar_get_mini.
- * Copied and modified from calendar_get_mini.
- *
- * @param bool $today false except when called on the current day.
- * @param mixed $timestart $events[$eventid]->timestart, OR false if there are no events.
- * @param string $popupcontent content for the popup window/layout.
- * @return string eventid for the calendar_tooltip popup window/layout.
- */
-function calendar_get_popup($today = false, $timestart, $popupcontent = '') {
-    $popupcaption = '';
-    if ($today) {
-        $popupcaption = get_string('today', 'calendar') . ' ';
-    }
-
-    if (false === $timestart) {
-        $popupcaption .= userdate(time(), get_string('strftimedayshort'));
-        $popupcontent = get_string('eventnone', 'calendar');
-
-    } else {
-        $popupcaption .= get_string('eventsfor', 'calendar', userdate($timestart, get_string('strftimedayshort')));
-    }
-
-    return array(
-        'data-core_calendar-title' => $popupcaption,
-        'data-core_calendar-popupcontent' => $popupcontent,
-    );
-}
-
 /**
  * Gets the calendar upcoming event.
  *
@@ -2372,9 +1999,35 @@ function calendar_edit_event_allowed($event, $manualedit = false) {
     }
 
     if ($manualedit && !empty($event->modulename)) {
-        // A user isn't allowed to directly edit an event generated
-        // by a module.
-        return false;
+        $hascallback = component_callback_exists(
+            'mod_' . $event->modulename,
+            'core_calendar_event_timestart_updated'
+        );
+
+        if (!$hascallback) {
+            // If the activity hasn't implemented the correct callback
+            // to handle changes to it's events then don't allow any
+            // manual changes to them.
+            return false;
+        }
+
+        $coursemodules = get_fast_modinfo($event->courseid)->instances;
+        $hasmodule = isset($coursemodules[$event->modulename]);
+        $hasinstance = isset($coursemodules[$event->modulename][$event->instance]);
+
+        // If modinfo doesn't know about the module, return false to be safe.
+        if (!$hasmodule || !$hasinstance) {
+            return false;
+        }
+
+        $coursemodule = $coursemodules[$event->modulename][$event->instance];
+        $context = context_module::instance($coursemodule->id);
+        // This is the capability that allows a user to modify the activity
+        // settings. Since the activity generated this event we need to check
+        // that the current user has the same capability before allowing them
+        // to update the event because the changes to the event will be
+        // reflected within the activity.
+        return has_capability('moodle/course:manageactivities', $context);
     }
 
     // You cannot edit URL based calendar subscription events presently.
@@ -3354,10 +3007,11 @@ function calendar_get_legacy_events($tstart, $tend, $users, $groups, $courses, $
  * Get the calendar view output.
  *
  * @param   \calendar_information $calendar The calendar being represented
- * @param   string      $view The type of calendar to have displayed
+ * @param   string  $view The type of calendar to have displayed
+ * @param   bool    $includenavigation Whether to include navigation
  * @return  array[array, string]
  */
-function calendar_get_view(\calendar_information $calendar, $view) {
+function calendar_get_view(\calendar_information $calendar, $view, $includenavigation = true) {
     global $PAGE, $CFG;
 
     $renderer = $PAGE->get_renderer('core_calendar');
@@ -3365,24 +3019,24 @@ function calendar_get_view(\calendar_information $calendar, $view) {
 
     // Calculate the bounds of the month.
     $date = $type->timestamp_to_date_array($calendar->time);
-    $tstart = $type->convert_to_timestamp($date['year'], $date['mon'], 1);
 
     if ($view === 'day') {
+        $tstart = $type->convert_to_timestamp($date['year'], $date['mon'], $date['mday']);
         $tend = $tstart + DAYSECS - 1;
-        $selectortitle = get_string('dayviewfor', 'calendar');
     } else if ($view === 'upcoming') {
         if (isset($CFG->calendar_lookahead)) {
             $defaultlookahead = intval($CFG->calendar_lookahead);
         } else {
             $defaultlookahead = CALENDAR_DEFAULT_UPCOMING_LOOKAHEAD;
         }
+        $tstart = $type->convert_to_timestamp($date['year'], $date['mon'], 1);
         $tend = $tstart + get_user_preferences('calendar_lookahead', $defaultlookahead);
-        $selectortitle = get_string('upcomingeventsfor', 'calendar');
     } else {
+        $tstart = $type->convert_to_timestamp($date['year'], $date['mon'], 1);
         $monthdays = $type->get_num_days_in_month($date['year'], $date['mon']);
         $tend = $tstart + ($monthdays * DAYSECS) - 1;
         $selectortitle = get_string('detailedmonthviewfor', 'calendar');
-        if ($view === 'mini') {
+        if ($view === 'mini' || $view === 'minithree') {
             $template = 'core_calendar/calendar_mini';
         } else {
             $template = 'core_calendar/calendar_month';
@@ -3437,10 +3091,20 @@ function calendar_get_view(\calendar_information $calendar, $view) {
     $related = [
         'events' => $events,
         'cache' => new \core_calendar\external\events_related_objects_cache($events),
+        'type' => $type,
     ];
 
-    $month = new \core_calendar\external\month_exporter($calendar, $type, $related);
-    $data = $month->export($renderer);
+    $data = [];
+    if ($view == "month" || $view == "mini" || $view == "minithree") {
+        $month = new \core_calendar\external\month_exporter($calendar, $type, $related);
+        $month->set_includenavigation($includenavigation);
+        $data = $month->export($renderer);
+    } else if ($view == "day") {
+        $daydata = $type->timestamp_to_date_array($tstart);
+        $day = new \core_calendar\external\day_exporter($calendar, $daydata, $related);
+        $data = $day->export($renderer);
+        $template = 'core_calendar/day_detailed';
+    }
 
     return [$data, $template];
 }
index dc597ab..484265e 100644 (file)
@@ -61,31 +61,45 @@ class core_calendar_renderer extends plugin_renderer_base {
     public function fake_block_threemonths(calendar_information $calendar) {
         // Get the calendar type we are using.
         $calendartype = \core_calendar\type_factory::get_calendar_instance();
+        $time = $calendartype->timestamp_to_date_array($calendar->time);
 
-        $date = $calendartype->timestamp_to_date_array($calendar->time);
-
-        $prevmonth = calendar_sub_month($date['mon'], $date['year']);
-        $prevmonthtime = $calendartype->convert_to_gregorian($prevmonth[1], $prevmonth[0], 1);
-        $prevmonthtime = make_timestamp($prevmonthtime['year'], $prevmonthtime['month'], $prevmonthtime['day'],
-            $prevmonthtime['hour'], $prevmonthtime['minute']);
-
-        $nextmonth = calendar_add_month($date['mon'], $date['year']);
-        $nextmonthtime = $calendartype->convert_to_gregorian($nextmonth[1], $nextmonth[0], 1);
-        $nextmonthtime = make_timestamp($nextmonthtime['year'], $nextmonthtime['month'], $nextmonthtime['day'],
-            $nextmonthtime['hour'], $nextmonthtime['minute']);
-
-        $content  = html_writer::start_tag('div', array('class' => 'minicalendarblock'));
-        $content .= calendar_get_mini($calendar->courses, $calendar->groups, $calendar->users,
-            false, false, 'display', $calendar->courseid, $prevmonthtime);
-        $content .= html_writer::end_tag('div');
-        $content .= html_writer::start_tag('div', array('class' => 'minicalendarblock'));
-        $content .= calendar_get_mini($calendar->courses, $calendar->groups, $calendar->users,
-            false, false, 'display', $calendar->courseid, $calendar->time);
-        $content .= html_writer::end_tag('div');
-        $content .= html_writer::start_tag('div', array('class' => 'minicalendarblock'));
-        $content .= calendar_get_mini($calendar->courses, $calendar->groups, $calendar->users,
-            false, false, 'display', $calendar->courseid, $nextmonthtime);
-        $content .= html_writer::end_tag('div');
+        $current = $calendar->time;
+        $prev = $calendartype->convert_to_timestamp(
+                $time['year'],
+                $time['mon'] - 1,
+                $time['mday']
+            );
+        $next = $calendartype->convert_to_timestamp(
+                $time['year'],
+                $time['mon'] + 1,
+                $time['mday']
+            );
+
+        $content = '';
+
+        // Previous.
+        $calendar->set_time($prev);
+        list($previousmonth, ) = calendar_get_view($calendar, 'minithree', false);
+
+        // Current month.
+        $calendar->set_time($current);
+        list($currentmonth, ) = calendar_get_view($calendar, 'minithree', false);
+
+        // Next month.
+        $calendar->set_time($next);
+        list($nextmonth, ) = calendar_get_view($calendar, 'minithree', false);
+
+        // Reset the time back.
+        $calendar->set_time($current);
+
+        $data = (object) [
+            'previousmonth' => $previousmonth,
+            'currentmonth' => $currentmonth,
+            'nextmonth' => $nextmonth,
+        ];
+
+        $template = 'core_calendar/calendar_threemonth';
+        $content .= $this->render_from_template($template, $data);
         return $content;
     }
 
@@ -100,98 +114,20 @@ class core_calendar_renderer extends plugin_renderer_base {
     }
 
     /**
-     * Creates a button to add a new event
+     * Creates a button to add a new event.
      *
      * @param int $courseid
-     * @param int $day
-     * @param int $month
-     * @param int $year
-     * @param int $time the unixtime, used for multiple calendar support. The values $day,
-     *     $month and $year are kept for backwards compatibility.
+     * @param int $unused1
+     * @param int $unused2
+     * @param int $unused3
+     * @param int $unused4
      * @return string
      */
-    public function add_event_button($courseid, $day = null, $month = null, $year = null, $time = null) {
-        // If a day, month and year were passed then convert it to a timestamp. If these were passed
-        // then we can assume the day, month and year are passed as Gregorian, as no where in core
-        // should we be passing these values rather than the time. This is done for BC.
-        if (!empty($day) && !empty($month) && !empty($year)) {
-            if (checkdate($month, $day, $year)) {
-                $time = make_timestamp($year, $month, $day);
-            } else {
-                $time = time();
-            }
-        } else if (empty($time)) {
-            $time = time();
-        }
-
-        $coursecontext = \context_course::instance($courseid);
-        $attributes = [
-            'class' => 'btn btn-secondary pull-xs-right pull-right',
-            'data-context-id' => $coursecontext->id,
-            'data-action' => 'new-event-button'
+    public function add_event_button($courseid, $unused1 = null, $unused2 = null, $unused3 = null, $unused4 = null) {
+        $data = [
+            'contextid' => (\context_course::instance($courseid))->id,
         ];
-        return html_writer::tag('button', get_string('newevent', 'calendar'), $attributes);
-    }
-
-    /**
-     * Displays the calendar for a single day
-     *
-     * @param calendar_information $calendar
-     * @return string
-     */
-    public function show_day(calendar_information $calendar, moodle_url $returnurl = null) {
-
-        if ($returnurl === null) {
-            $returnurl = $this->page->url;
-        }
-
-        $events = calendar_get_upcoming($calendar->courses, $calendar->groups, $calendar->users,
-            1, 100, $calendar->timestamp_today());
-
-        $output  = html_writer::start_tag('div', array('class'=>'header'));
-        $output .= $this->course_filter_selector($returnurl, get_string('dayviewfor', 'calendar'));
-        if (calendar_user_can_add_event($calendar->course)) {
-            $output .= $this->add_event_button($calendar->course->id, 0, 0, 0, $calendar->time);
-        }
-        $output .= html_writer::end_tag('div');
-        // Controls
-        $output .= html_writer::tag('div', calendar_top_controls('day', array('id' => $calendar->courseid,
-            'time' => $calendar->time)), array('class' => 'controls'));
-
-        if (empty($events)) {
-            // There is nothing to display today.
-            $output .= html_writer::span(get_string('daywithnoevents', 'calendar'), 'calendar-information calendar-no-results');
-        } else {
-            $output .= html_writer::start_tag('div', array('class' => 'eventlist'));
-            $underway = array();
-            // First, print details about events that start today
-            foreach ($events as $event) {
-                $event = new calendar_event($event);
-                $event->calendarcourseid = $calendar->courseid;
-                if ($event->timestart >= $calendar->timestamp_today() && $event->timestart <= $calendar->timestamp_tomorrow()-1) {  // Print it now
-                    $event->time = calendar_format_event_time($event, time(), null, false,
-                        $calendar->timestamp_today());
-                    $output .= $this->event($event);
-                } else {                                                                 // Save this for later
-                    $underway[] = $event;
-                }
-            }
-
-            // Then, show a list of all events that just span this day
-            if (!empty($underway)) {
-                $output .= html_writer::span(get_string('spanningevents', 'calendar'),
-                    'calendar-information calendar-span-multiple-days');
-                foreach ($underway as $event) {
-                    $event->time = calendar_format_event_time($event, time(), null, false,
-                        $calendar->timestamp_today());
-                    $output .= $this->event($event);
-                }
-            }
-
-            $output .= html_writer::end_tag('div');
-        }
-
-        return $output;
+        return $this->render_from_template('core_calendar/add_event_button', $data);
     }
 
     /**
@@ -255,10 +191,11 @@ class core_calendar_renderer extends plugin_renderer_base {
         // Show subscription source if needed.
         if (!empty($event->subscription) && $CFG->calendar_showicalsource) {
             if (!empty($event->subscription->url)) {
-                $source = html_writer::link($event->subscription->url, get_string('subsource', 'calendar', $event->subscription));
+                $source = html_writer::link($event->subscription->url,
+                        get_string('subscriptionsource', 'calendar', $event->subscription->name));
             } else {
                 // File based ical.
-                $source = get_string('subsource', 'calendar', $event->subscription);
+                $source = get_string('subscriptionsource', 'calendar', $event->subscription->name);
             }
             $output .= html_writer::tag('div', $source, array('class' => 'subscription'));
         }
diff --git a/calendar/templates/add_event_button.mustache b/calendar/templates/add_event_button.mustache
new file mode 100644 (file)
index 0000000..654a9d9
--- /dev/null
@@ -0,0 +1,43 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template calendar/add_event_button
+
+    Button to launch the "Add new event" dialogue.
+
+    The purpose of this template is to render the button used to generate the new event dialogue.
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Example context (json):
+    {
+        "defaulteventcontext": "2"
+    }
+}}
+{{#defaulteventcontext}}
+<button{{!
+    }} class="btn btn-secondary pull-xs-right pull-right"{{!
+    }} data-context-id="{{defaulteventcontext}}"{{!
+    }} data-action="new-event-button"{{!
+    }}>
+    {{#str}}newevent, core_calendar{{/str}}
+</button>
+{{/defaulteventcontext}}
index 6e28cbf..5b91ac6 100644 (file)
@@ -32,7 +32,7 @@
     }
 }}
 <div{{!
-  }} id="calendar-month-{{uniqid}}-{{time}}" {{!
+    }} id="calendar-month-{{date.year}}-{{date.month}}-{{uniqid}}" {{!
     }} data-template="core_calendar/month_mini" {{!
     }} data-includenavigation="{{#includenavigation}}true{{/includenavigation}}{{^includenavigation}}false{{/includenavigation}}"{{!
     }}>
@@ -40,6 +40,6 @@
 </div>
 {{#js}}
 require(['jquery', 'core_calendar/calendar_mini'], function($, CalendarMini) {
-    CalendarMini.init($("#calendar-month-{{uniqid}}-{{time}}"));
+    CalendarMini.init($("#calendar-month-{{date.year}}-{{date.month}}-{{uniqid}}"));
 });
 {{/js}}
diff --git a/calendar/templates/calendar_threemonth.mustache b/calendar/templates/calendar_threemonth.mustache
new file mode 100644 (file)
index 0000000..b9e41b3
--- /dev/null
@@ -0,0 +1,49 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template calendar/calendar_threemonth
+
+    Calendar view to show three months as a block.
+
+    The purpose of this template is to render a set of three months of calendar_mini in a block.
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Example context (json):
+    {
+    }
+}}
+<div id="calendar-multi-{{uniqid}}">
+    {{#previousmonth}}
+        {{> core_calendar/threemonth_month}}
+    {{/previousmonth}}
+    {{#currentmonth}}
+        {{> core_calendar/threemonth_month}}
+    {{/currentmonth}}
+    {{#nextmonth}}
+        {{> core_calendar/threemonth_month}}
+    {{/nextmonth}}
+</div>
+{{#js}}
+require(['jquery', 'core_calendar/calendar_threemonth'], function($, CalendarThreeMonth) {
+    CalendarThreeMonth.init($("#calendar-multi-{{uniqid}}"));
+});
+{{/js}}
diff --git a/calendar/templates/day_detailed.mustache b/calendar/templates/day_detailed.mustache
new file mode 100644 (file)
index 0000000..cddfae3
--- /dev/null
@@ -0,0 +1,39 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template calendar/day_detailed
+
+    Calendar day view.
+
+    The purpose of this template is to render the calendar day view.
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Example context (json):
+    {
+    }
+}}
+<div class="header">
+    {{{filter_selector}}}
+    {{{new_event_button}}}
+</div>
+{{> core_calendar/day_navigation }}
+{{> core_calendar/event_list }}
\ No newline at end of file
diff --git a/calendar/templates/day_navigation.mustache b/calendar/templates/day_navigation.mustache
new file mode 100644 (file)
index 0000000..fce9dc2
--- /dev/null
@@ -0,0 +1,39 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template calendar/day_navigation
+
+    Calendar day navigation.
+
+    The purpose of this template is to render the navigation to switch to previous and next months.
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Example context (json):
+    {
+    }
+}}
+{{#navigation}}
+<div class="controls" data-view="{{view}}">
+    {{{navigation}}}
+</div>
+{{/navigation}}
+
diff --git a/calendar/templates/event_delete_modal.mustache b/calendar/templates/event_delete_modal.mustache
new file mode 100644 (file)
index 0000000..5f33933
--- /dev/null
@@ -0,0 +1,47 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template core_calendar/event_delete_modal
+
+    Moodle modal template with save and cancel buttons.
+
+    The purpose of this template is to render a modal.
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Context variables required for this template:
+    * title A cleaned string (use clean_text()) to display.
+    * body HTML content for the boday
+
+    Example context (json):
+    {
+        "title": "Example delete event seriesmodal",
+        "body": "Do you want to delete this event, or all events in the series?"
+    }
+}}
+
+{{< core/modal }}
+    {{$footer}}
+        <button type="button" class="btn btn-primary" data-action="deleteone">{{#str}} deleteoneevent, core_calendar {{/str}}</button>
+        <button type="button" class="btn btn-secondary" data-action="deleteall">{{#str}} deleteallevents, core_calendar {{/str}}</button>
+        <button type="button" class="btn btn-secondary" data-action="cancel">{{#str}} cancel {{/str}}</button>
+    {{/footer}}
+{{/ core/modal }}
diff --git a/calendar/templates/event_item.mustache b/calendar/templates/event_item.mustache
new file mode 100644 (file)
index 0000000..3f4f31a
--- /dev/null
@@ -0,0 +1,68 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template calendar/event_item
+
+    Calendar event item.
+
+    The purpose of this template is to render the event item.
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Example context (json):
+    {
+    }
+}}
+<div class="event">
+    <div class="card">
+        <div class="box card-header clearfix p-y-1">
+            <div class="commands pull-xs-right">
+                {{#canedit}}
+                    {{#candelete}}
+                        <a href="{{deleteurl}}">
+                            {{#pix}}t/delete, core, {{#str}}delete{{/str}}{{/pix}}
+                        </a>
+                    {{/candelete}}
+                    <a href="{{editurl}}">
+                        {{#pix}}t/edit, core, {{#str}}edit{{/str}}{{/pix}}
+                    </a>
+                {{/canedit}}
+            </div>
+            {{#icon}}{{#pix}} {{key}}, {{component}}, {{alttext}} {{/pix}}{{/icon}}
+            <h3 class="name d-inline-block">{{name}}</h3>
+            <span class="date pull-xs-right m-r-1">{{{formattedtime}}}</span>
+        </div>
+        <div class="description card-block calendar_event_{{eventtype}}">
+            <p>{{{description}}}</p>
+            {{#iscourseevent}}
+                <div><a href="{{url}}">{{course.fullname}}</a></div>
+            {{/iscourseevent}}
+            {{> core_calendar/event_subscription}}
+            {{#isactionevent}}
+                <a href="{{url}}">{{#str}} gotoactivity, core_calendar {{/str}}</a>
+            {{/isactionevent}}
+            {{#groupname}}
+                <div><a href="{{url}}">{{{course.fullname}}}</a></div>
+                <div>{{{groupname}}}</div>
+            {{/groupname}}
+        </div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/calendar/templates/event_list.mustache b/calendar/templates/event_list.mustache
new file mode 100644 (file)
index 0000000..dec4fa2
--- /dev/null
@@ -0,0 +1,43 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template calendar/event_list
+
+    Calendar event list.
+
+    The purpose of this template is to render a list of events.
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Example context (json):
+    {
+    }
+}}
+<div class="eventlist">
+    {{#events}}
+        {{> core_calendar/event_item }}
+    {{/events}}
+    {{^events}}
+        <span class="calendar-information calendar-no-results">
+            {{#str}}daywithnoevents, calendar{{/str}}
+        </span>
+    {{/events}}
+</div>
\ No newline at end of file
diff --git a/calendar/templates/event_subscription.mustache b/calendar/templates/event_subscription.mustache
new file mode 100644 (file)
index 0000000..0a57928
--- /dev/null
@@ -0,0 +1,48 @@
+{{!
+    This file is part of Moodle - http://moodle.org/
+
+    Moodle is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    Moodle is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @template calendar/event_subscription
+
+    Calendar event subscription.
+
+    The purpose of this template is to render the event subscription data.
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Example context (json):
+    {
+    }
+}}
+
+{{#subscription}}
+    {{#displayeventsource}}
+        <div>
+            {{#url}}
+                <p><a href="{{url}}">{{#str}}subscriptionsource, core_calendar, {{name}}{{/str}}</a></p>
+            {{/url}}
+            {{^url}}
+                <p>{{#str}}subscriptionsource, core_calendar, {{name}}{{/str}}</p>
+            {{/url}}
+        </div>
+    {{/displayeventsource}}
+{{/subscription}}
+
+
index 2ad48aa..b139b69 100644 (file)
         "groupname": "Group 1"
     }
 }}
-<div data-region="summary-modal-container" data-event-id="{{id}}" data-event-title="{{name}}"
-     data-action-event="{{isactionevent}}" data-edit-url="{{editurl}}">
+<div{{!
+    }} data-region="summary-modal-container"{{!
+    }} data-event-id="{{id}}"{{!
+    }} data-event-title="{{name}}"{{!
+    }} data-event-event-count="{{eventcount}}"{{!
+    }} data-event-="{{repeatid}}"{{!
+    }} data-action-event="{{isactionevent}}"{{!
+    }} data-edit-url="{{editurl}}"{{!
+    }}>
     <h4>{{#str}} when, core_calendar {{/str}}</h4>
     {{#userdate}} {{timestart}}, {{#str}} strftimerecentfull {{/str}} {{/userdate}}
     <br>
@@ -42,9 +49,7 @@
     {{#iscourseevent}}
         <div><a href="{{url}}">{{course.fullname}}</a></div>
     {{/iscourseevent}}
-    {{#source}}
-        <div>{{{source}}}</div>
-    {{/source}}
+    {{> core_calendar/event_subscription}}
     {{#groupname}}
         <div><a href="{{url}}">{{{course.fullname}}}</a></div>
         <div>{{{groupname}}}</div>
index 583f500..a6e7c2d 100644 (file)
     }
 }}
 {{< core/modal }}
-{{$footer}}
-{{#canedit}}
-    {{#candelete}}
-        <button type="button" class="btn btn-secondary" data-action="delete">{{#str}} delete {{/str}}</button>
-    {{/candelete}}
-    <button type="button" class="btn btn-primary" data-action="edit">{{#str}} edit {{/str}}</button>
-{{/canedit}}
-{{#isactionevent}}
-    <a href="{{url}}">{{#str}} gotoactivity, core_calendar {{/str}}</a>
-{{/isactionevent}}
-{{/footer}}
+    {{$footer}}
+        {{#candelete}}
+            <button type="button" class="btn btn-secondary" data-action="delete">{{#str}} delete {{/str}}</button>
+        {{/candelete}}
+        {{#isactionevent}}
+            <a href="{{url}}">{{#str}} gotoactivity, core_calendar {{/str}}</a>
+        {{/isactionevent}}
+        {{^isactionevent}}
+            {{#canedit}}
+                <button type="button" class="btn btn-primary" data-action="edit">{{#str}} edit {{/str}}</button>
+            {{/canedit}}
+        {{/isactionevent}}
+    {{/footer}}
 {{/ core/modal }}
index 05c2941..d9769b2 100644 (file)
@@ -33,5 +33,7 @@
     {{#managesubscriptionbutton}}
         {{> core/single_button }}
     {{/managesubscriptionbutton}}
-    <a href="{{icalurl}}" title="{{#str}} quickdownloadcalendar, calendar {{/str}}" class="ical-link m-l-1">iCal</a>
+    {{#icalurl}}
+        <a href="{{icalurl}}" title="{{#str}} quickdownloadcalendar, calendar {{/str}}" class="ical-link m-l-1">iCal</a>
+    {{/icalurl}}
 </div>
similarity index 94%
rename from calendar/templates/month_header.mustache
rename to calendar/templates/header.mustache
index 56d6e49..626470d 100644 (file)
@@ -15,9 +15,9 @@
     along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 }}
 {{!
-    @template calendar/month_header
+    @template calendar/header
 
-    Calendar month header.
+    Calendar header.
 
     The purpose of this template is to render the month header.
 
index 463b687..baa9013 100644 (file)
     {
     }
 }}
-<div class="calendarwrapper" data-courseid="{{courseid}}" data-current-time="{{time}}">
-    {{> core_calendar/month_header }}
+<div{{!
+    }} class="calendarwrapper"{{!
+    }} data-courseid="{{courseid}}"{{!
+    }} data-month="{{date.mon}}"{{!
+    }} data-year="{{date.year}}"{{!
+    }}>
+    {{> core_calendar/header }}
+    {{> core_calendar/add_event_button}}
     {{> core_calendar/month_navigation }}
     {{> core/overlay_loading}}
     <table id="month-detailed-{{uniqid}}" class="calendarmonth calendartable card-deck m-b-0">