diff --git a/blocks/admin_presets/.github/ISSUE_TEMPLATE/bug_report.md b/blocks/admin_presets/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000000000000000000000000000000000..dd84ea7824f11be1eeda22377549cbc1aec7f980 --- /dev/null +++ b/blocks/admin_presets/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/blocks/admin_presets/.travis.yml b/blocks/admin_presets/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..7351ed03f04ec5d7bb84c452739606ac0b4caa68 --- /dev/null +++ b/blocks/admin_presets/.travis.yml @@ -0,0 +1,45 @@ +sudo: required + +language: php + +dist: xenial + +services: + - mysql + +php: + - 7.2 + +env: + global: + - MOODLE_BRANCH=master + - IGNORE_PATHS=amd/build,amd/src/bootstrap.js + - IGNORE_NAMES=*.txt,moodle.css,moodle-rtl.css,moodle_min.css,editor.css,editor_min.css,Gruntfile.js + - DB=mysqli + +matrix: + - php: 7.2 + env: DB=mysqli TASK=PHPUNIT + +cache: + directories: + - $HOME/.composer/cache + - $HOME/.npm + +before_install: + - cd ../.. + - composer selfupdate + - composer create-project -n --no-dev moodlerooms/moodle-plugin-ci ci ^1 + - export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH" + +install: + - moodle-plugin-ci install + +script: + - moodle-plugin-ci phplint + - moodle-plugin-ci phpcpd + - moodle-plugin-ci phpmd + - moodle-plugin-ci codechecker + - moodle-plugin-ci csslint + - moodle-plugin-ci jshint + #- moodle-plugin-ci phpunit \ No newline at end of file diff --git a/blocks/admin_presets/README.md b/blocks/admin_presets/README.md new file mode 100644 index 0000000000000000000000000000000000000000..703b0468aa161a50305f8140e46d3f78d88c3211 --- /dev/null +++ b/blocks/admin_presets/README.md @@ -0,0 +1,31 @@ +# Admin presets for Moodle + +Block to export and import Moodle administration settings + +## Build status + +[](https://travis-ci.org/DigiDago/moodle-block_admin_presets) + +## Features + +* Export system settings to XML files +* Import presets files +* Preset preview and partial load +* Allows rollback +* Option to autoexclude the sensitive data when exporting settings (you can edit the sensitive settings list in Site Administration -> Plugins -> Blocks -> Admin presets) +* Third parties plugins supported + +## See also +* Modules and Plugins entry: https://moodle.org/plugins/view.php?plugin=block_admin_presets + + +Maintainer +============ +AdminPreset was initialy developed by David Monllaó. It is currently maintained by Pimenko team. + + +Any Problems, questions, suggestions +=================== +If you have a problem with this block, suggestions for improvement, drop an email at : +- Pimenko : contact@pimenko.com +- Github : https://github.com/DigiDago/moodle-block_admin_presets diff --git a/blocks/admin_presets/block_admin_presets.php b/blocks/admin_presets/block_admin_presets.php new file mode 100644 index 0000000000000000000000000000000000000000..2182036fa0fa1d576cd86dcf1678d0b4629d1443 --- /dev/null +++ b/blocks/admin_presets/block_admin_presets.php @@ -0,0 +1,95 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +class block_admin_presets extends block_list { + + /** + * @throws coding_exception + */ + public function init() { + $this->title = get_string('pluginname', 'block_admin_presets'); + } + + public function get_content() { + + global $CFG, $OUTPUT; + + if (empty($this->instance)) { + $this->content = ''; + return $this->content; + } + + $this->content = new stdClass(); + $this->content->items = array(); + $this->content->icons = array(); + $this->content->footer = ''; + + if (!has_capability('moodle/site:config', context_system::instance())) { + $this->content = ''; + return $this->content; + } + + $this->content->items[] = $OUTPUT->pix_icon("i/backup", + get_string('actionexport', 'block_admin_presets'), + "moodle", array("class" => "icon")) . '<a title="' . + get_string('actionexport', 'block_admin_presets') . + '" href="' . $CFG->wwwroot . '/blocks/admin_presets/index.php?action=export">' . + get_string('actionexport', 'block_admin_presets') . + '</a>'; + + $this->content->items[] = $OUTPUT->pix_icon("i/restore", + get_string('actionimport', 'block_admin_presets'), + "moodle", array("class" => "icon")) . + '<a title="' . get_string('actionimport', 'block_admin_presets') . + '" href="' . $CFG->wwwroot . + '/blocks/admin_presets/index.php?action=import">' . + get_string('actionimport', 'block_admin_presets') . + '</a>'; + + $this->content->items[] = $OUTPUT->pix_icon("i/repository", + get_string('actionbase', 'block_admin_presets'), + "moodle", array("class" => "icon")) . + '<a title="' . + get_string('actionbase', 'block_admin_presets') . + '" href="' . + $CFG->wwwroot . + '/blocks/admin_presets/index.php">' + . get_string('actionbase', 'block_admin_presets') . '</a>'; + + return $this->content; + } + + public function applicable_formats() { + return array('site' => true); + } + + public function has_config() { + return true; + } + +} diff --git a/blocks/admin_presets/classes/event/preset_deleted.php b/blocks/admin_presets/classes/event/preset_deleted.php new file mode 100644 index 0000000000000000000000000000000000000000..39b956b9762159bc3f6f2c94cdcaf984664ac33b --- /dev/null +++ b/blocks/admin_presets/classes/event/preset_deleted.php @@ -0,0 +1,51 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace block_admin_presets\event; + +defined('MOODLE_INTERNAL') || die(); + +class preset_deleted extends \core\event\base { + + public static function get_name() { + return get_string('eventpresetdeleted', 'block_admin_presets'); + } + + public function get_description() { + return "User {$this->userid} has deleted the preset with id {$this->objectid}."; + } + + public function get_legacy_logdata() { + return array($this->courseid, 'block_admin_presets', 'delete', '', + $this->objectid, $this->contextinstanceid); + } + + protected function init() { + $this->data['crud'] = 'd'; + $this->data['edulevel'] = self::LEVEL_OTHER; + $this->data['objecttable'] = 'block_admin_presets'; + } +} diff --git a/blocks/admin_presets/classes/event/preset_downloaded.php b/blocks/admin_presets/classes/event/preset_downloaded.php new file mode 100644 index 0000000000000000000000000000000000000000..127c8dbcd615b015b68901e89e0df4ab9568c82e --- /dev/null +++ b/blocks/admin_presets/classes/event/preset_downloaded.php @@ -0,0 +1,41 @@ +<?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/>. + +namespace block_admin_presets\event; + +defined('MOODLE_INTERNAL') || die(); + +class preset_downloaded extends \core\event\base { + + public static function get_name() { + return get_string('eventpresetdownloaded', 'block_admin_presets'); + } + + public function get_description() { + return "User {$this->userid} has downloaded the preset with id {$this->objectid}."; + } + + public function get_url() { + return new \moodle_url('/blocks/admin_presets/index.php', + array('action' => 'export', 'mode' => 'download_xml', 'id' => $this->objectid, 'sesskey' => sesskey())); + } + + protected function init() { + $this->data['crud'] = 'r'; + $this->data['edulevel'] = self::LEVEL_OTHER; + $this->data['objecttable'] = 'block_admin_presets'; + } +} diff --git a/blocks/admin_presets/classes/event/preset_exported.php b/blocks/admin_presets/classes/event/preset_exported.php new file mode 100644 index 0000000000000000000000000000000000000000..815aa7ff88fbc6435558e4af9a45eea526493504 --- /dev/null +++ b/blocks/admin_presets/classes/event/preset_exported.php @@ -0,0 +1,56 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace block_admin_presets\event; + +defined('MOODLE_INTERNAL') || die(); + +class preset_exported extends \core\event\base { + + public static function get_name() { + return get_string('eventpresetexported', 'block_admin_presets'); + } + + public function get_description() { + return "User {$this->userid} has exported the preset with id {$this->objectid}."; + } + + public function get_url() { + return new \moodle_url('/blocks/admin_presets/index.php', + array('action' => 'load', 'mode' => 'preview', 'id' => $this->objectid)); + } + + public function get_legacy_logdata() { + return array($this->courseid, 'block_admin_presets', 'export', '', + $this->objectid, $this->contextinstanceid); + } + + protected function init() { + $this->data['crud'] = 'c'; + $this->data['edulevel'] = self::LEVEL_OTHER; + $this->data['objecttable'] = 'block_admin_presets'; + } +} diff --git a/blocks/admin_presets/classes/event/preset_imported.php b/blocks/admin_presets/classes/event/preset_imported.php new file mode 100644 index 0000000000000000000000000000000000000000..d25c2366f0f7123fe1ec273a5c0435c65eb22e1e --- /dev/null +++ b/blocks/admin_presets/classes/event/preset_imported.php @@ -0,0 +1,56 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace block_admin_presets\event; + +defined('MOODLE_INTERNAL') || die(); + +class preset_imported extends \core\event\base { + + public static function get_name() { + return get_string('eventpresetimported', 'block_admin_presets'); + } + + public function get_description() { + return "User {$this->userid} has imported the preset with id {$this->objectid}."; + } + + public function get_url() { + return new \moodle_url('/blocks/admin_presets/index.php', + array('action' => 'load', 'mode' => 'preview', 'id' => $this->objectid)); + } + + public function get_legacy_logdata() { + return array($this->courseid, 'block_admin_presets', 'import', '', + $this->objectid, $this->contextinstanceid); + } + + protected function init() { + $this->data['crud'] = 'c'; + $this->data['edulevel'] = self::LEVEL_OTHER; + $this->data['objecttable'] = 'block_admin_presets'; + } +} diff --git a/blocks/admin_presets/classes/event/preset_loaded.php b/blocks/admin_presets/classes/event/preset_loaded.php new file mode 100644 index 0000000000000000000000000000000000000000..7ef06627fbffb8ecac09741294d99430c586ba69 --- /dev/null +++ b/blocks/admin_presets/classes/event/preset_loaded.php @@ -0,0 +1,56 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace block_admin_presets\event; + +defined('MOODLE_INTERNAL') || die(); + +class preset_loaded extends \core\event\base { + + public static function get_name() { + return get_string('eventpresetloaded', 'block_admin_presets'); + } + + public function get_description() { + return "User {$this->userid} has loaded the preset with id {$this->objectid}."; + } + + public function get_url() { + return new \moodle_url('/blocks/admin_presets/index.php', + array('action' => 'load', 'mode' => 'preview', 'id' => $this->objectid)); + } + + public function get_legacy_logdata() { + return array($this->courseid, 'block_admin_presets', 'load', '', + $this->objectid, $this->contextinstanceid); + } + + protected function init() { + $this->data['crud'] = 'u'; + $this->data['edulevel'] = self::LEVEL_OTHER; + $this->data['objecttable'] = 'block_admin_presets'; + } +} diff --git a/blocks/admin_presets/classes/event/preset_previewed.php b/blocks/admin_presets/classes/event/preset_previewed.php new file mode 100644 index 0000000000000000000000000000000000000000..92bc397cbbcbccc1527dd7a9503b92bd01268c20 --- /dev/null +++ b/blocks/admin_presets/classes/event/preset_previewed.php @@ -0,0 +1,51 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace block_admin_presets\event; + +defined('MOODLE_INTERNAL') || die(); + +class preset_previewed extends \core\event\base { + + public static function get_name() { + return get_string('eventpresetpreviewed', 'block_admin_presets'); + } + + public function get_description() { + return "User {$this->userid} has previewed the preset with id {$this->objectid}."; + } + + public function get_url() { + return new \moodle_url('/blocks/admin_presets/index.php', + array('action' => 'load', 'mode' => 'preview', 'id' => $this->objectid)); + } + + protected function init() { + $this->data['crud'] = 'r'; + $this->data['edulevel'] = self::LEVEL_OTHER; + $this->data['objecttable'] = 'block_admin_presets'; + } +} diff --git a/blocks/admin_presets/classes/event/preset_reverted.php b/blocks/admin_presets/classes/event/preset_reverted.php new file mode 100644 index 0000000000000000000000000000000000000000..51bf4275653169facfefbb685c118925c8284960 --- /dev/null +++ b/blocks/admin_presets/classes/event/preset_reverted.php @@ -0,0 +1,51 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace block_admin_presets\event; + +defined('MOODLE_INTERNAL') || die(); + +class preset_reverted extends \core\event\base { + + public static function get_name() { + return get_string('eventpresetreverted', 'block_admin_presets'); + } + + public function get_description() { + return "User {$this->userid} has reverted the preset with id {$this->objectid}."; + } + + public function get_legacy_logdata() { + return array($this->courseid, 'block_admin_presets', 'rollback', '', + $this->objectid, $this->contextinstanceid); + } + + protected function init() { + $this->data['crud'] = 'u'; + $this->data['edulevel'] = self::LEVEL_OTHER; + $this->data['objecttable'] = 'block_admin_presets'; + } +} diff --git a/blocks/admin_presets/classes/event/presets_listed.php b/blocks/admin_presets/classes/event/presets_listed.php new file mode 100644 index 0000000000000000000000000000000000000000..3625448d6a55e6ad4045228f96d6428e6dc6ec61 --- /dev/null +++ b/blocks/admin_presets/classes/event/presets_listed.php @@ -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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace block_admin_presets\event; + +defined('MOODLE_INTERNAL') || die(); + +class presets_listed extends \core\event\base { + + public static function get_name() { + return get_string('eventpresetslisted', 'block_admin_presets'); + } + + public function get_description() { + return "User {$this->userid} listed the system presets."; + } + + public function get_url() { + return new \moodle_url('/block/admin_presets/index.php'); + } + + public function get_legacy_logdata() { + return array($this->courseid, 'block_admin_presets', 'base', '', + $this->objectid, $this->contextinstanceid); + } + + protected function init() { + $this->data['crud'] = 'r'; + $this->data['edulevel'] = self::LEVEL_OTHER; + $this->data['objecttable'] = 'block_admin_presets'; + } +} diff --git a/blocks/admin_presets/classes/privacy/provider.php b/blocks/admin_presets/classes/privacy/provider.php new file mode 100644 index 0000000000000000000000000000000000000000..c1a6f4f4869333fea4453e8a4773876975f3c228 --- /dev/null +++ b/blocks/admin_presets/classes/privacy/provider.php @@ -0,0 +1,36 @@ +<?php +// This file is part of The Course Module Navigation Block +// +// 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/>. + +namespace block_admin_presets\privacy; + +defined('MOODLE_INTERNAL') || die(); + +use core_privacy\local\metadata\null_provider; + +class provider implements + // This plugin does not store any personal user data. + null_provider { + + /** + * Get the language string identifier with the component's language + * file to explain why this plugin stores no data. + * + * @return string + */ + public static function get_reason() : string { + return 'privacy:null_reason'; + } +} diff --git a/blocks/admin_presets/db/access.php b/blocks/admin_presets/db/access.php new file mode 100644 index 0000000000000000000000000000000000000000..35ef3c3ece4ab558a45f4252cbd652025b5240e7 --- /dev/null +++ b/blocks/admin_presets/db/access.php @@ -0,0 +1,39 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$capabilities = array( + 'block/admin_presets:addinstance' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_SYSTEM, + 'archetypes' => array( + 'manager' => CAP_ALLOW + ) + ) +); + + diff --git a/blocks/admin_presets/db/install.xml b/blocks/admin_presets/db/install.xml new file mode 100644 index 0000000000000000000000000000000000000000..26633faff66621ff2f05d22de0ab5815e3deb13f --- /dev/null +++ b/blocks/admin_presets/db/install.xml @@ -0,0 +1,127 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<XMLDB PATH="blocks/admin_presets/db" VERSION="20120314" COMMENT="Admin presets block tables, to store exported/imported presets" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"> + <TABLES> + <TABLE NAME="block_admin_presets" COMMENT="Table to store presets data" NEXT="block_admin_presets_it"> + <FIELDS> + <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="userid"/> + <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="false" + PREVIOUS="id" NEXT="name"/> + <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="userid" + NEXT="comments"/> + <FIELD NAME="comments" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" PREVIOUS="name" + NEXT="site"/> + <FIELD NAME="site" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="comments" + NEXT="author"/> + <FIELD NAME="author" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" PREVIOUS="site" + NEXT="moodleversion"/> + <FIELD NAME="moodleversion" TYPE="char" LENGTH="20" NOTNULL="true" SEQUENCE="false" PREVIOUS="author" + NEXT="moodlerelease"/> + <FIELD NAME="moodlerelease" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" + PREVIOUS="moodleversion" NEXT="timecreated"/> + <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" + SEQUENCE="false" PREVIOUS="moodlerelease" NEXT="timeimported"/> + <FIELD NAME="timeimported" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" + SEQUENCE="false" PREVIOUS="timecreated"/> + </FIELDS> + <KEYS> + <KEY NAME="primary" TYPE="primary" FIELDS="id"/> + </KEYS> + </TABLE> + <TABLE NAME="block_admin_presets_it" COMMENT="Table to store settings" PREVIOUS="block_admin_presets" + NEXT="block_admin_presets_it_a"> + <FIELDS> + <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" + NEXT="adminpresetid"/> + <FIELD NAME="adminpresetid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="false" + PREVIOUS="id" NEXT="plugin"/> + <FIELD NAME="plugin" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false" PREVIOUS="adminpresetid" + NEXT="name"/> + <FIELD NAME="name" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" PREVIOUS="plugin" + NEXT="value"/> + <FIELD NAME="value" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" PREVIOUS="name"/> + </FIELDS> + <KEYS> + <KEY NAME="primary" TYPE="primary" FIELDS="id"/> + </KEYS> + <INDEXES> + <INDEX NAME="adminpresetid" UNIQUE="false" FIELDS="adminpresetid"/> + </INDEXES> + </TABLE> + <TABLE NAME="block_admin_presets_it_a" + COMMENT="Admin presets items attributes. For settings with attributes (extra values like 'advanced')" + PREVIOUS="block_admin_presets_it" NEXT="block_admin_presets_app"> + <FIELDS> + <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="itemid"/> + <FIELD NAME="itemid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="false" + PREVIOUS="id" NEXT="name"/> + <FIELD NAME="name" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" PREVIOUS="itemid" + NEXT="value"/> + <FIELD NAME="value" TYPE="text" LENGTH="medium" NOTNULL="false" SEQUENCE="false" PREVIOUS="name"/> + </FIELDS> + <KEYS> + <KEY NAME="primary" TYPE="primary" FIELDS="id"/> + </KEYS> + <INDEXES> + <INDEX NAME="itemid" UNIQUE="false" FIELDS="itemid"/> + </INDEXES> + </TABLE> + <TABLE NAME="block_admin_presets_app" COMMENT="Applied presets" PREVIOUS="block_admin_presets_it_a" + NEXT="block_admin_presets_app_it"> + <FIELDS> + <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" + NEXT="adminpresetid"/> + <FIELD NAME="adminpresetid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="false" + PREVIOUS="id" NEXT="userid"/> + <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="false" + PREVIOUS="adminpresetid" NEXT="time"/> + <FIELD NAME="time" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="false" + PREVIOUS="userid"/> + </FIELDS> + <KEYS> + <KEY NAME="primary" TYPE="primary" FIELDS="id"/> + </KEYS> + <INDEXES> + <INDEX NAME="adminpresetid" UNIQUE="false" FIELDS="adminpresetid"/> + </INDEXES> + </TABLE> + <TABLE NAME="block_admin_presets_app_it" + COMMENT="Admin presets applied items. To maintain the relation with config_log" + PREVIOUS="block_admin_presets_app" NEXT="block_admin_presets_app_it_a"> + <FIELDS> + <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" + NEXT="adminpresetapplyid"/> + <FIELD NAME="adminpresetapplyid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="false" + PREVIOUS="id" NEXT="configlogid"/> + <FIELD NAME="configlogid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="false" + PREVIOUS="adminpresetapplyid"/> + </FIELDS> + <KEYS> + <KEY NAME="primary" TYPE="primary" FIELDS="id"/> + </KEYS> + <INDEXES> + <INDEX NAME="configlogid" UNIQUE="false" FIELDS="configlogid" NEXT="adminpresetapplyid"/> + <INDEX NAME="adminpresetapplyid" UNIQUE="false" FIELDS="adminpresetapplyid" PREVIOUS="configlogid"/> + </INDEXES> + </TABLE> + <TABLE NAME="block_admin_presets_app_it_a" COMMENT="Attributes of the applied items" + PREVIOUS="block_admin_presets_app_it"> + <FIELDS> + <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" + NEXT="adminpresetapplyid"/> + <FIELD NAME="adminpresetapplyid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="false" + PREVIOUS="id" NEXT="configlogid"/> + <FIELD NAME="configlogid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="false" + PREVIOUS="adminpresetapplyid" NEXT="itemname"/> + <FIELD NAME="itemname" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false" + COMMENT="Necessary to rollback" PREVIOUS="configlogid"/> + </FIELDS> + <KEYS> + <KEY NAME="primary" TYPE="primary" FIELDS="id"/> + </KEYS> + <INDEXES> + <INDEX NAME="configlogid" UNIQUE="false" FIELDS="configlogid" NEXT="adminpresetapplyid"/> + <INDEX NAME="adminpresetapplyid" UNIQUE="false" FIELDS="adminpresetapplyid" PREVIOUS="configlogid"/> + </INDEXES> + </TABLE> + </TABLES> +</XMLDB> \ No newline at end of file diff --git a/blocks/admin_presets/db/upgrade.php b/blocks/admin_presets/db/upgrade.php new file mode 100644 index 0000000000000000000000000000000000000000..0a057c23845638a125053ba09edd4db96c959c36 --- /dev/null +++ b/blocks/admin_presets/db/upgrade.php @@ -0,0 +1,100 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * @param int $oldversion + * @param object $block + * @return bool + * @throws coding_exception + * @throws ddl_exception + * @throws ddl_field_missing_exception + * @throws ddl_table_missing_exception + * @throws downgrade_exception + * @throws moodle_exception + * @throws upgrade_exception + * @global moodle_database $DB + */ +function xmldb_block_admin_presets_upgrade($oldversion, $block) { + global $DB; + + $dbman = $DB->get_manager(); + + if ($oldversion < 2011063000) { + + // Changing type of field moodleversion on table admin_preset to char. + $table = new xmldb_table('admin_preset'); + $field = new xmldb_field('moodleversion', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, 'author'); + + // Launch change of type for field moodleversion. + $dbman->change_field_type($table, $field); + + upgrade_block_savepoint(true, 2011063000, 'admin_presets'); + } + + // Renaming DB tables. + if ($oldversion < 2012031401) { + + $tablenamechanges = array('admin_preset' => 'block_admin_presets', + 'admin_preset_apply' => 'block_admin_presets_app', + 'admin_preset_apply_item' => 'block_admin_presets_app_it', + 'admin_preset_apply_item_attr' => 'block_admin_presets_app_it_a', + 'admin_preset_item' => 'block_admin_presets_it', + 'admin_preset_item_attr' => 'block_admin_presets_it_a'); + + // Just in case it gets to the max number of chars defined in the XSD. + try { + + // Renaming the tables. + foreach ($tablenamechanges as $from => $to) { + + $table = new xmldb_table($from); + if ($dbman->table_exists($table)) { + $dbman->rename_table($table, $to); + } + } + + // Print error and rollback changes. + } catch (Exception $e) { + + // Rollback tablename changes. + foreach ($tablenamechanges as $to => $from) { + + $table = new xmldb_table($from); + if ($dbman->table_exists($table)) { + $dbman->rename_table($table, $to); + } + } + + $debuginfo = get_string('errorupgradetablenamesdebug', 'block_admin_presets'); + throw new moodle_exception('errorupgradetablenames', 'block_admin_presets', '', null, $debuginfo); + } + + upgrade_block_savepoint(true, 2012031401, 'admin_presets'); + } + return true; +} diff --git a/blocks/admin_presets/forms/admin_presets_export_form.php b/blocks/admin_presets/forms/admin_presets_export_form.php new file mode 100644 index 0000000000000000000000000000000000000000..0fe4e06102f7db58d91cae32b63385ece7cec2a9 --- /dev/null +++ b/blocks/admin_presets/forms/admin_presets_export_form.php @@ -0,0 +1,68 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/lib/formslib.php'); + +class admin_presets_export_form extends moodleform { + + public function definition() { + + global $USER, $OUTPUT; + + $mform = &$this->_form; + + // Preset attributes. + $mform->addElement('header', 'general', + get_string('presetsettings', 'block_admin_presets')); + + $mform->addElement('text', 'name', get_string('name'), 'maxlength="254" size="60"'); + $mform->addRule('name', null, 'required', null, 'client'); + $mform->setType('name', PARAM_TEXT); + + $mform->addElement('editor', 'comments', get_string('comments')); + $mform->setType('comments', PARAM_CLEANHTML); + + $mform->addElement('text', 'author', + get_string('author', 'block_admin_presets'), 'maxlength="254" size="60"'); + $mform->setType('author', PARAM_TEXT); + $mform->setDefault('author', $USER->firstname . ' ' . $USER->lastname); + + $mform->addElement('checkbox', 'excludesensiblesettings', + get_string('autohidesensiblesettings', 'block_admin_presets')); + + // Moodle settings table. + $mform->addElement('header', 'general', + get_string('adminsettings', 'block_admin_presets')); + $mform->addElement('html', '<div id="settings_tree_div" class="ygtv-checkbox"><img src="' . + $OUTPUT->pix_icon('i/loading_small', get_string('loading', + 'block_admin_presets')) . '"/></div><br/>'); + + // Submit. + $mform->addElement('submit', 'admin_presets_submit', get_string('savechanges')); + } +} diff --git a/blocks/admin_presets/forms/admin_presets_import_form.php b/blocks/admin_presets/forms/admin_presets_import_form.php new file mode 100644 index 0000000000000000000000000000000000000000..9fea1de7955dffad7dd20f8bec469dfea9411051 --- /dev/null +++ b/blocks/admin_presets/forms/admin_presets_import_form.php @@ -0,0 +1,52 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/lib/formslib.php'); + +class admin_presets_import_form extends moodleform { + + public function definition() { + + $mform = &$this->_form; + + $mform->addElement('header', 'general', + get_string('selectfile', 'block_admin_presets')); + + // File upload + $mform->addElement('filepicker', 'xmlfile', + get_string('selectfile', 'block_admin_presets')); + $mform->addRule('xmlfile', null, 'required'); + + // Rename input + $mform->addElement('text', 'name', + get_string('renamepreset', 'block_admin_presets'), 'maxlength="254" size="40"'); + $mform->setType('name', PARAM_TEXT); + + $mform->addElement('submit', 'admin_presets_submit', get_string('savechanges')); + } +} diff --git a/blocks/admin_presets/forms/admin_presets_load_form.php b/blocks/admin_presets/forms/admin_presets_load_form.php new file mode 100644 index 0000000000000000000000000000000000000000..d03acfdcb4d967e280dba6c71d6c57a757b7857e --- /dev/null +++ b/blocks/admin_presets/forms/admin_presets_load_form.php @@ -0,0 +1,67 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/lib/formslib.php'); + +class admin_presets_load_form extends moodleform { + + private $preview; + + public function __construct($url, $preview = false) { + $this->preview = $preview; + parent::__construct($url); + } + + public function definition() { + + global $OUTPUT; + + $mform = &$this->_form; + + // Moodle settings table. + $mform->addElement('header', 'general', + get_string('adminsettings', 'block_admin_presets')); + + $class = ''; + if (!$this->preview) { + $class = 'ygtv-checkbox'; + } + $mform->addElement('html', '<div id="settings_tree_div" class="' . $class . + '"><img src="' . $OUTPUT->pix_icon('i/loading_small', + get_string('loading', 'block_admin_presets')) . '"/></div>'); + + $mform->addElement('hidden', 'id'); + $mform->setType('id', PARAM_INT); + + // Submit. + if (!$this->preview) { + $mform->addElement('submit', 'admin_presets_submit', + get_string('loadselected', 'block_admin_presets')); + } + } +} diff --git a/blocks/admin_presets/index.php b/blocks/admin_presets/index.php new file mode 100644 index 0000000000000000000000000000000000000000..1c83fd2b2e03b7590006285a3153dd95935eb90c --- /dev/null +++ b/blocks/admin_presets/index.php @@ -0,0 +1,69 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once('../../config.php'); + +$action = optional_param('action', 'base', PARAM_ALPHA); +$mode = optional_param('mode', 'show', PARAM_ALPHAEXT); + +require_login(); + +if (!$context = context_system::instance()) { + print_error('wrongcontext', 'error'); +} + +require_capability('moodle/site:config', $context); + +// Loads the required action class and form. +$classname = 'admin_presets_' . $action; +$formname = $classname . '_form'; +$formpath = $CFG->dirroot . '/blocks/admin_presets/forms/' . $formname . '.php'; +require_once($CFG->dirroot . '/blocks/admin_presets/lib/' . $classname . '.class.php'); +if (file_exists($formpath)) { + require_once($formpath); +} + +if (!class_exists($classname)) { + print_error('falseaction', 'block_admin_presets', $action); +} + +$url = new moodle_url('/blocks/admin_presets/index.php'); +$url->param('action', $action); +$url->param('mode', $mode); +$PAGE->set_url($url); +$PAGE->set_pagelayout('admin'); +$PAGE->set_context($context); + +// Executes the required action. +$instance = new $classname(); +if (!method_exists($instance, $mode)) { + print_error('falsemode', 'block_admin_presets', $mode); +} + +// Executes the required method and displays output. +$instance->$mode(); +$instance->log(); +$instance->display(); diff --git a/blocks/admin_presets/lang/en/block_admin_presets.php b/blocks/admin_presets/lang/en/block_admin_presets.php new file mode 100644 index 0000000000000000000000000000000000000000..033cec57acfabe1b5afecfb9bcee1d5d7156e444 --- /dev/null +++ b/blocks/admin_presets/lang/en/block_admin_presets.php @@ -0,0 +1,120 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['accessdenied'] = 'Access denied'; +$string['actionbase'] = 'Presets'; +$string['actiondelete'] = 'Delete preset'; +$string['actionexport'] = 'Export settings'; +$string['actionimport'] = 'Import settings'; +$string['actionload'] = 'Load settings'; +$string['actionrollback'] = 'Revert applied changes'; +$string['actualvalue'] = 'Actual value'; +$string['admin_presets:addinstance'] = 'Add a new admin presets block'; +$string['adminsettings'] = 'Admin settings'; +$string['author'] = 'Author'; +$string['autohidesensiblesettings'] = 'Auto exclude sensitive settings'; +$string['baseshow'] = 'list presets'; +$string['created'] = 'Created'; +$string['deletepreset'] = 'Preset {$a} will be deleted, are you sure?'; +$string['deletepreviouslyapplied'] = 'This preset has been previously applied, + if you delete it you can not return to the previous state'; +$string['deleteexecute'] = 'execution'; +$string['deleteshow'] = 'confirm'; +$string['errorupgradetablenames'] = 'admin_presets upgrade failed, + upgrade Moodle in order to upgrade admin_presets. You can restore the previous blocks/admin_presets code until then'; +$string['errorupgradetablenamesdebug'] = 'The table names exceeds the limit of allowed characters, + this is solved using the latest Moodle 2.0, Moodle 2.1 and Moodle 2.2 releases'; +$string['errordeleting'] = 'Error deleting from DB'; +$string['errorinserting'] = 'Error inserting into DB'; +$string['errornopreset'] = 'It doesn\'t exists a preset with that name'; +$string['eventpresetdeleted'] = 'Preset deleted'; +$string['eventpresetdownloaded'] = 'Preset downloaded'; +$string['eventpresetexported'] = 'Preset exported'; +$string['eventpresetimported'] = 'Preset imported'; +$string['eventpresetloaded'] = 'Preset loaded'; +$string['eventpresetpreviewed'] = 'Preset previewed'; +$string['eventpresetreverted'] = 'Preset reverted'; +$string['eventpresetslisted'] = 'Presets have been listed'; +$string['exportexecute'] = 'saving'; +$string['exportshow'] = 'select settings'; +$string['falseaction'] = 'Action not supported in this version'; +$string['falsemode'] = 'Mode not supported in this version'; +$string['headingload'] = 'Select settings to load'; +$string['imported'] = 'Imported'; +$string['importexecute'] = 'importing'; +$string['importshow'] = 'select file'; +$string['load'] = 'load'; +$string['loadexecute'] = 'applied changes'; +$string['loadpreview'] = 'preview preset'; +$string['loadselected'] = 'Load selected settings'; +$string['loadshow'] = 'select settings'; +$string['markedasadvanced'] = 'marked as advanced'; +$string['markedasforced'] = 'marked as forced'; +$string['markedaslocked'] = 'marked as locked'; +$string['markedasnonadvanced'] = 'marked as non advanced'; +$string['markedasnonforced'] = 'marked as non forced'; +$string['markedasnonlocked'] = 'marked as non locked'; +$string['newvalue'] = 'New setting value'; +$string['loading'] = 'loading'; +$string['noparamtype'] = 'There are no param type for that setting'; +$string['nopresets'] = 'You don\'t have presets'; +$string['nothingloaded'] = 'All preset settings skipped, they are already loaded'; +$string['notpreviouslyapplied'] = 'Preset not previously applied'; +$string['novalidsettings'] = 'No valid settings'; +$string['novalidsettingsselected'] = 'No valid settings selected'; +$string['oldvalue'] = 'Old setting value'; +$string['pluginname'] = 'Admin presets'; +$string['presetmoodlerelease'] = 'Moodle release'; +$string['presetname'] = 'Preset name'; +$string['presetsettings'] = 'Preset settings'; +$string['preview'] = 'preview'; +$string['previewpreset'] = 'Preview preset'; +$string['renamepreset'] = 'Rename preset'; +$string['rollback'] = 'revert'; +$string['rollbackexecute'] = 'return to previous state'; +$string['rollbackfailures'] = 'The following settings can not be restored, + the actual values differs from the values applied by the preset'; +$string['rollbackresults'] = 'Settings successfully restored'; +$string['rollbackshow'] = 'preset applications list'; +$string['selectedvalues'] = 'setting selected values'; +$string['selectfile'] = 'Select file'; +$string['sensiblesettings'] = 'Sensitive setting to skip if "Auto exclude sensitive settings" is checked'; +$string['sensiblesettingstext'] = 'Add elements separating by \',\' and with format SETTINGNAME@@PLUGINNAME'; +$string['settingname'] = 'Setting name'; +$string['settingvalue'] = 'with value'; +$string['settingsapplied'] = 'Settings applied'; +$string['settingsnotapplicable'] = 'Settings not applicable to this Moodle version'; +$string['settingsnotapplied'] = 'Settings skipped, they are all already loaded'; +$string['site'] = 'Site'; +$string['successimported'] = 'Preset imported'; +$string['timeapplied'] = 'Time applied'; +$string['toexportclick'] = 'To export your settings click {$a}'; +$string['toimportclick'] = 'To import a admin preset click {$a}'; +$string['value'] = 'setting value'; +$string['voidvalue'] = 'that setting does not have a value'; +$string['wrongfile'] = 'Wrong file'; +$string['wrongid'] = 'Wrong id'; +$string['privacy:null_reason'] = 'The admin presets block does not effect or store any user data'; \ No newline at end of file diff --git a/blocks/admin_presets/lib/admin_presets_base.class.php b/blocks/admin_presets/lib/admin_presets_base.class.php new file mode 100644 index 0000000000000000000000000000000000000000..697a899bc9752b95f4959acf5020ff479b9f5a73 --- /dev/null +++ b/blocks/admin_presets/lib/admin_presets_base.class.php @@ -0,0 +1,650 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->libdir . '/adminlib.php'); +require_once($CFG->dirroot . '/blocks/admin_presets/lib/admin_presets_settings_types.php'); + +class admin_presets_base { + + protected static $eventsactionsmap = array( + 'base' => 'presets_listed', + 'delete' => 'preset_deleted', + 'export' => 'preset_exported', + 'import' => 'preset_imported', + 'preview' => 'preset_previewed', + 'load' => 'preset_loaded', + 'rollback' => 'preset_reverted', + 'download_xml' => 'preset_downloaded' + ); + protected $action; + protected $mode; + protected $adminroot; + protected $outputs; + protected $moodleform; + protected $rel; + + /** + * Loads common class attributes and initializes sensible settings and DB - XML relations + */ + public function __construct() { + + $this->action = optional_param('action', 'base', PARAM_ALPHA); + $this->mode = optional_param('mode', 'show', PARAM_ALPHAEXT); + $this->id = optional_param('id', false, PARAM_INT); + + // DB - XML relations. + $this->rel = array('name' => 'NAME', 'comments' => 'COMMENTS', + 'timecreated' => 'PRESET_DATE', 'site' => 'SITE_URL', 'author' => 'AUTHOR', + 'moodleversion' => 'MOODLE_VERSION', 'moodlerelease' => 'MOODLE_RELEASE'); + + // Sensible settings. + $sensiblesettings = explode(',', + str_replace(' ', '', get_config('admin_presets', 'sensiblesettings'))); + $this->sensiblesettings = array_combine($sensiblesettings, $sensiblesettings); + } + + /** + * Method to list the presets available on the system + * + * It allows users to access the different preset + * actions (preview, load, download, delete and rollback) + */ + public function show() { + + global $CFG, $DB, $OUTPUT; + + $presets = $DB->get_records('block_admin_presets'); + $this->outputs = ''; + + if ($presets) { + + // Initialize table. + $table = $this->_create_preset_data_table(); + + foreach ($presets as $preset) { + + // Preset actions. + $previewlink = $CFG->wwwroot . + '/blocks/admin_presets/index.php?action=load&mode=preview&id=' . $preset->id; + $loadlink = $CFG->wwwroot . + '/blocks/admin_presets/index.php?action=load&id=' . $preset->id; + $downloadlink = $CFG->wwwroot . + '/blocks/admin_presets/index.php?action=export&mode=download_xml&sesskey=' . + sesskey() . '&id=' . $preset->id; + $deletelink = $CFG->wwwroot . + '/blocks/admin_presets/index.php?action=delete&id=' . $preset->id; + $rollbacklink = $CFG->wwwroot . + '/blocks/admin_presets/index.php?action=rollback&id=' . $preset->id; + + $actions = array(); + $actions[] = html_writer::link($previewlink, strtolower(get_string("preview"))); + $actions[] = html_writer::link($loadlink, get_string("load", + "block_admin_presets")); + $actions[] = html_writer::link($downloadlink, strtolower(get_string("download"))); + $actions[] = html_writer::link($deletelink, strtolower(get_string("delete"))); + + // Look for preset applications. + if ($DB->get_records('block_admin_presets_app', array('adminpresetid' => $preset->id))) { + $actions[] = html_writer::link($rollbacklink, + get_string("rollback", "block_admin_presets")); + } + + if ($preset->timeimported) { + $timeimportedstring = userdate($preset->timeimported); + } else { + $timeimportedstring = ''; + } + + // Populate table. + $table->data[] = array(format_text($preset->name, FORMAT_PLAIN), + format_text($preset->comments, FORMAT_HTML), + format_text($preset->moodlerelease, FORMAT_PLAIN), + format_text($preset->author, FORMAT_PLAIN), + format_text(clean_text($preset->site, PARAM_URL), FORMAT_PLAIN), + userdate($preset->timecreated), + $timeimportedstring, + '<div>' . implode('</div><div>', $actions) . '</div>'); + } + + $this->outputs .= html_writer::table($table); + + // If there aren't presets notify it. + } else { + + $exportlink = '<a href="' . $CFG->wwwroot . + '/blocks/admin_presets/index.php?action=export">' . + strtolower(get_string("actionexport", "block_admin_presets")) . '</a>'; + $importlink = '<a href="' . + $CFG->wwwroot . '/blocks/admin_presets/index.php?action=import">' . + strtolower(get_string("actionimport", "block_admin_presets")) . '</a>'; + + $this->outputs = $OUTPUT->box_start('generalbox', 'id_nopresets'); + $this->outputs .= '<ul>' . get_string('nopresets', 'block_admin_presets'); + $this->outputs .= '<li>' . get_string('toexportclick', + 'block_admin_presets', $exportlink) . '</li>'; + $this->outputs .= '<li>' . get_string('toimportclick', + 'block_admin_presets', $importlink) . '</li>'; + $this->outputs .= '</ul>'; + $this->outputs .= $OUTPUT->box_end(); + } + + } + + /** + * Table to display preset/s data + * + * @param boolean $actionstable If is set to true adds a column to display actions + * @return html_table + * @throws coding_exception + */ + protected function _create_preset_data_table($actionstable = true) { + + $table = new html_table(); + $table->attributes['class'] = 'generaltable boxaligncenter'; + $table->align = array('left', 'left', 'center', 'left', 'left', 'center', 'center'); + $table->head = array(get_string('name'), get_string('description'), + get_string('presetmoodlerelease', 'block_admin_presets'), + get_string('author', 'block_admin_presets'), + get_string('site', 'block_admin_presets'), + get_string('created', 'block_admin_presets'), + get_string('imported', 'block_admin_presets')); + + if ($actionstable) { + $table->align[] = 'left'; + $table->head[] = get_string('actions'); + $table->size = array('14%', '16%', '12%', '11%', '17%', '10%', '10%', '10%'); + } else { + $table->size = array('17%', '20%', '13%', '12%', '18%', '10%', '10%'); + } + + return $table; + } + + /** + * Main display method + * + * Prints the block header and the common block outputs, the + * selected action outputs, his form and the footer + * + * $outputs value depends on $mode and $action selected + */ + public function display() { + global $OUTPUT; + + $this->_display_header(); + + // Other outputs. + if (!empty($this->outputs)) { + echo $this->outputs; + } + + // Form. + if ($this->moodleform) { + $this->moodleform->display(); + } + + // Footer. + echo $OUTPUT->footer(); + } + + /** + * Displays the header + */ + protected function _display_header() { + + global $CFG, $PAGE, $OUTPUT, $SITE; + + // Strings. + $actionstr = get_string('action' . $this->action, 'block_admin_presets'); + $modestr = get_string($this->action . $this->mode, 'block_admin_presets'); + $titlestr = get_string('pluginname', 'block_admin_presets'); + + // Header. + $PAGE->set_title($titlestr); + $PAGE->set_heading($SITE->fullname); + + $PAGE->navbar->add(get_string('pluginname', 'block_admin_presets'), + new moodle_url($CFG->wwwroot . '/blocks/admin_presets/index.php')); + + $PAGE->navbar->add($actionstr . ': ' . $modestr); + + echo $OUTPUT->header(); + + include(dirname(dirname(__FILE__)) . '/tabs.php'); + + echo $OUTPUT->heading($actionstr . ': ' . $modestr, 1); + } + + public function log() { + // TODO please, me of the future, fix this ununderstandable code. + + // The only read action we store is list presets. + if ($this->mode != 'show' || + ($this->mode == 'show' && $this->action == 'base')) { + + $action = $this->action; + if ($this->mode != 'execute' && $this->mode != 'show') { + $action = $this->mode; + } + + $eventnamespace = '\\block_admin_presets\\event\\' . self::$eventsactionsmap[$action]; + $eventdata = array( + 'context' => context_system::instance(), + 'objectid' => $this->id + ); + $event = $eventnamespace::create($eventdata); + $event->trigger(); + } + } + + /** + * Gets the system settings + * + * Loads the DB $CFG->prefix.'config' values and the + * $CFG->prefix.'config_plugins' values and redirects + * the flow through $this->_get_settings() + * + * @return array $settings Array format $array['plugin']['settingname'] = admin_preset_setting child class + * @throws dml_exception + */ + protected function _get_site_settings() { + + global $DB; + + // Db configs (to avoid multiple queries). + $dbconfig = $DB->get_records_select('config', '', array(), '', 'name, value'); + + // Adding site settings in course table. + $frontpagevalues = $DB->get_record_select('course', 'id = 1', + array(), 'fullname, shortname, summary'); + foreach ($frontpagevalues as $field => $value) { + $dbconfig[$field] = new StdClass(); + $dbconfig[$field]->name = $field; + $dbconfig[$field]->value = $value; + } + $sitedbsettings['none'] = $dbconfig; + + // Config plugins. + $configplugins = $DB->get_records('config_plugins'); + foreach ($configplugins as $configplugin) { + $sitedbsettings[$configplugin->plugin][$configplugin->name] = new StdClass(); + $sitedbsettings[$configplugin->plugin][$configplugin->name]->name = $configplugin->name; + $sitedbsettings[$configplugin->plugin][$configplugin->name]->value = $configplugin->value; + } + // Get an array with the common format. + return $this->_get_settings($sitedbsettings, true, $settings = array()); + } + + /** + * Constructs an array with all the system settings + * + * If a setting value can't be found on the DB it considers + * the default value as the setting value + * + * Settings without plugin are marked as 'none' in the plugin field + * + * Returns an standarized settings array format, $this->_get_settings_branches + * will get the html or js to display the settings tree + * + * @param array $dbsettings Standarized array, + * format $array['plugin']['name'] = obj('name'=>'settingname', 'value'=>'settingvalue') + * @param boolean $sitedbvalues Indicates if $dbsettings comes from the site db or not + * @param array $settings Array format $array['plugin']['settingname'] = admin_preset_setting child class + * @param bool $children admin_category children + * @return array Array format $array['plugin']['settingname'] = admin_preset_setting child class + * @throws dml_exception + */ + protected function _get_settings($dbsettings, $sitedbvalues = false, $settings, $children = false) { + + global $DB; + // If there are no children, load admin tree and iterate through. + if (!$children) { + $this->adminroot = admin_get_root(false, true); + $children = $this->adminroot->children; + } + + // Iteates through children. + foreach ($children as $key => $child) { + + // We must search category children. + if (is_a($child, 'admin_category')) { + + if ($child->children) { + $settings = $this->_get_settings($dbsettings, $sitedbvalues, $settings, $child->children); + } + + // Settings page. + } else if (is_a($child, 'admin_settingpage')) { + + if ($child->settings) { + + foreach ($child->settings as $values) { + $settingname = $values->name; + + unset($settingvalue); + + // Look for his config value. + if ($values->plugin == '') { + $values->plugin = 'none'; + } + + if (!empty($dbsettings[$values->plugin][$settingname])) { + $settingvalue = $dbsettings[$values->plugin][$settingname]->value; + } + + // If no db value found default value. + if ($sitedbvalues && !isset($settingvalue)) { + // For settings with multiple values. + if (is_array($values->defaultsetting)) { + + if (isset($values->defaultsetting['value'])) { + $settingvalue = $values->defaultsetting['value']; + // Configtime case, does not have a 'value' default setting. + } else { + $settingvalue = 0; + } + } else { + $settingvalue = $values->defaultsetting; + } + } + + // If there aren't any value loaded, skip that setting. + if (!isset($settingvalue)) { + continue; + } + // If there is no setting class defined continue. + if (!$setting = $this->_get_setting($values, $settingvalue)) { + continue; + } + + // Admin_preset_setting childs with. + // attributes provides an attributes array. + if ($attributes = $setting->get_attributes()) { + + // Look for settings attributes if it is a presets. + if (!$sitedbvalues) { + $itemid = $dbsettings[$values->plugin][$settingname]->itemid; + $attrs = $DB->get_records('block_admin_presets_it_a', + array('itemid' => $itemid), '', 'name, value'); + } + foreach ($attributes as $defaultvarname => $varname) { + + unset($attributevalue); + + // Settings from site. + if ($sitedbvalues) { + if (!empty($dbsettings[$values->plugin][$varname])) { + $attributevalue = $dbsettings[$values->plugin][$varname]->value; + } + + // Settings from a preset. + } else if (!$sitedbvalues && isset($attrs[$varname])) { + $attributevalue = $attrs[$varname]->value; + } + + // If no value found, default value, + // But we may not have a default value for the attribute. + if (!isset($attributevalue) && !empty($values->defaultsetting[$defaultvarname])) { + $attributevalue = $values->defaultsetting[$defaultvarname]; + } + + // If there is no even a default for this setting will be empty. + // So we do nothing in this case. + if (isset($attributevalue)) { + $setting->set_attribute_value($varname, $attributevalue); + } + } + } + + // Setting the text. + $setting->set_text(); + + // Adding to general settings array. + $settings[$values->plugin][$settingname] = $setting; + } + } + } + } + + return $settings; + } + + /** + * Returns the class type object + * + * @param object $settingdata Setting data + * @param mixed $currentvalue + * @return bool + */ + protected function _get_setting($settingdata, $currentvalue) { + + // Getting the appropiate class to get the correct setting value. + $settingtype = get_class($settingdata); + + // Skipping admin_*. + $classname = 'admin_preset_' . $settingtype; + + // TODO: Implement all the settings types. + if (!class_exists($classname)) { + return false; + } + + $setting = new $classname($settingdata, $currentvalue); + + return $setting; + } + + /** + * Gets the javascript to populate the settings tree + * + * @param array $settings Array format $array['plugin']['settingname'] = admin_preset_setting child class + */ + protected function _get_settings_branches($settings) { + + global $PAGE; + + // Nodes should be added in hierarchical order. + $nodes = array('categories' => array(), 'pages' => array(), 'settings' => array()); + $nodes = $this->_get_settings_elements($settings, false, false, $nodes); + + $PAGE->requires->js_init_call('M.block_admin_presets.init', null, true); + + $levels = array('categories', 'pages', 'settings'); + foreach ($levels as $level) { + foreach ($nodes[$level] as $data) { + $ids[] = $data[0]; + $nodes[] = $data[1]; + $labels[] = $data[2]; + $descriptions[] = $data[3]; + $parents[] = $data[4]; + } + } + $PAGE->requires->js_init_call('M.block_admin_presets.addNodes', + array($ids, $nodes, $labels, $descriptions, $parents), true); + $PAGE->requires->js_init_call('M.block_admin_presets.render', null, true); + } + + /** + * Gets the html code to select the settings to export/import/load + * + * @param array $allsettings Array format $array['plugin']['settingname'] = admin_preset_setting child class + * @param bool $admintree The admin tree branche object or false if we are in the root + * @param bool $jsparentnode Name of the javascript parent category node + * @param array $nodes Tree nodes + * @return array Code to output + */ + protected function _get_settings_elements($allsettings, $admintree = false, $jsparentnode = false, &$nodes) { + + if (empty($this->adminroot)) { + $this->adminroot = admin_get_root(false, true); + } + + // If there are no children, load admin tree and iterate through. + if (!$admintree) { + $this->adminroot = admin_get_root(false, true); + $admintree = $this->adminroot->children; + } + + // If there are no parentnode specified the parent becomes the tree root. + if (!$jsparentnode) { + $jsparentnode = 'root'; + } + + // Iterates through children. + foreach ($admintree as $key => $child) { + $pagesettings = array(); + + // We must search category children. + if (is_a($child, 'admin_category')) { + if ($child->children) { + $categorynode = $child->name . 'Node'; + $nodehtml = '<div class="catnode">' . $child->visiblename . '</div>'; + $nodes['categories'][$categorynode] = array("category", + $categorynode, (String) $nodehtml, "", $jsparentnode); + + // Not all admin_categories have admin_settingpages. + $this->_get_settings_elements($allsettings, $child->children, $categorynode, $nodes); + } + + // Settings page. + } else if (is_a($child, 'admin_settingpage')) { + // Only if there are settings. + if ($child->settings) { + + // The name of that page tree node. + $pagenode = $child->name . 'Node'; + + foreach ($child->settings as $values) { + $settingname = $values->name; + + // IF no plugin was specified mark as 'none'. + if (!$plugin = $values->plugin) { + $plugin = 'none'; + } + + if (empty($allsettings[$plugin][$settingname])) { + continue; + } + + // Getting setting data. + $setting = $allsettings[$plugin][$settingname]; + $settingid = $setting->get_id(); + + // String to add the setting to js tree. + $pagesettings[$settingid] = array($settingid, $settingid, + $setting->get_text(), $setting->get_description(), $pagenode); + } + + // The page node only should be added if it have children. + if ($pagesettings) { + $nodehtml = '<div class="catnode">' . $child->visiblename . '</div>'; + $nodes['pages'][$pagenode] = array("page", $pagenode, (String) $nodehtml, "", $jsparentnode); + $nodes['settings'] = array_merge($nodes['settings'], $pagesettings); + } + } + } + } + + return $nodes; + } + + /** + * Gets the standarized settings array from DB records + * + * @param array $dbsettings Array of objects + * @return array Standarized array, + * format $array['plugin']['name'] = obj('name'=>'settingname', 'value'=>'settingvalue') + */ + protected function _get_settings_from_db($dbsettings) { + + if (!$dbsettings) { + return false; + } + + $settings = array(); + foreach ($dbsettings as $dbsetting) { + $settings[$dbsetting->plugin][$dbsetting->name] = new StdClass(); + $settings[$dbsetting->plugin][$dbsetting->name]->itemid = $dbsetting->id; + $settings[$dbsetting->plugin][$dbsetting->name]->name = $dbsetting->name; + $settings[$dbsetting->plugin][$dbsetting->name]->value = $dbsetting->value; + } + + return $settings; + } + + protected function _output_applied_changes($appliedchanges) { + + $appliedtable = new html_table(); + $appliedtable->attributes['class'] = 'generaltable boxaligncenter admin_presets_applied'; + $appliedtable->head = array(get_string('plugin'), + get_string('settingname', 'block_admin_presets'), + get_string('oldvalue', 'block_admin_presets'), + get_string('newvalue', 'block_admin_presets')); + + $appliedtable->align = array('center', 'center'); + + foreach ($appliedchanges as $setting) { + $appliedtable->data[] = array($setting->plugin, + $setting->visiblename, + $setting->oldvisiblevalue, + $setting->visiblevalue); + } + + $this->outputs .= html_writer::table($appliedtable); + } + + /** + * Returns a table with the preset data + * + * @param object $preset + * @return string|string + * @throws coding_exception + */ + protected function _html_writer_preset_info_table($preset) { + + if (!$preset) { + return ''; + } + + if ($preset->timeimported) { + $timeimportedstring = userdate($preset->timeimported); + } else { + $timeimportedstring = ''; + } + $infotable = $this->_create_preset_data_table(false); + $infotable->data[] = array(format_text($preset->name, FORMAT_PLAIN), + format_text($preset->comments, FORMAT_HTML), + format_text($preset->moodlerelease, FORMAT_PLAIN), + format_text($preset->author, FORMAT_PLAIN), + format_text(clean_text($preset->site, PARAM_URL), FORMAT_PLAIN), + userdate($preset->timecreated), + $timeimportedstring); + + return html_writer::table($infotable); + } +} diff --git a/blocks/admin_presets/lib/admin_presets_delete.class.php b/blocks/admin_presets/lib/admin_presets_delete.class.php new file mode 100644 index 0000000000000000000000000000000000000000..e4b6cc5bf8648dce9ac1a24380b739ef2ae8f995 --- /dev/null +++ b/blocks/admin_presets/lib/admin_presets_delete.class.php @@ -0,0 +1,116 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/blocks/admin_presets/lib/admin_presets_base.class.php'); + +class admin_presets_delete extends admin_presets_base { + + /** + * Shows a confirm box + */ + public function show() { + + global $DB, $CFG, $OUTPUT; + + // Getting the preset name. + $presetdata = $DB->get_record('block_admin_presets', array('id' => $this->id), 'name'); + + $deletetext = get_string("deletepreset", "block_admin_presets", $presetdata->name); + $confirmurl = $CFG->wwwroot . '/blocks/admin_presets/index.php?action=' . + $this->action . '&mode=execute&id=' . $this->id . '&sesskey=' . sesskey(); + $cancelurl = $CFG->wwwroot . '/blocks/admin_presets/index.php'; + + // If the preset was applied add a warning text. + if ($previouslyapplied = $DB->get_records('block_admin_presets_app', + array('adminpresetid' => $this->id))) { + + $deletetext .= '<br/><br/><strong>' . + get_string("deletepreviouslyapplied", "block_admin_presets") . '</strong>'; + } + + $this->outputs = $OUTPUT->confirm($deletetext, $confirmurl, $cancelurl); + } + + /** + * Delete the DB preset + */ + public function execute() { + + global $DB, $CFG; + + confirm_sesskey(); + + if (!$DB->delete_records('block_admin_presets', array('id' => $this->id))) { + print_error('errordeleting', 'block_admin_presets'); + } + + // Getting items ids before deleting to delete item attributes. + $items = $DB->get_records('block_admin_presets_it', array('adminpresetid' => $this->id), 'id'); + foreach ($items as $item) { + $DB->delete_records('block_admin_presets_it_a', array('itemid' => $item->id)); + } + + if (!$DB->delete_records('block_admin_presets_it', array('adminpresetid' => $this->id))) { + print_error('errordeleting', 'block_admin_presets'); + } + + // Deleting the preset applications. + if ($previouslyapplied = $DB->get_records('block_admin_presets_app', + array('adminpresetid' => $this->id), 'id')) { + + foreach ($previouslyapplied as $application) { + + // Deleting items. + if (!$DB->delete_records('block_admin_presets_app_it', + array('adminpresetapplyid' => $application->id))) { + + print_error('errordeleting', 'block_admin_presets'); + } + + // Deleting attributes. + if (!$DB->delete_records('block_admin_presets_app_it_a', + array('adminpresetapplyid' => $application->id))) { + + print_error('errordeleting', 'block_admin_presets'); + } + } + + if (!$DB->delete_records('block_admin_presets_app', + array('adminpresetid' => $this->id))) { + + print_error('errordeleting', 'block_admin_presets'); + } + } + + // Trigger the as it is usually triggered after execute finishes. + $this->log(); + + redirect($CFG->wwwroot . '/blocks/admin_presets/index.php'); + } + +} diff --git a/blocks/admin_presets/lib/admin_presets_export.class.php b/blocks/admin_presets/lib/admin_presets_export.class.php new file mode 100644 index 0000000000000000000000000000000000000000..972493daf50cc4f2a4c3caa8b7418eecb764ea3b --- /dev/null +++ b/blocks/admin_presets/lib/admin_presets_export.class.php @@ -0,0 +1,235 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/blocks/admin_presets/lib/admin_presets_base.class.php'); +require_once($CFG->dirroot . '/backup/util/xml/xml_writer.class.php'); +require_once($CFG->dirroot . '/backup/util/xml/output/xml_output.class.php'); +require_once($CFG->dirroot . '/backup/util/xml/output/memory_xml_output.class.php'); + +class admin_presets_export extends admin_presets_base { + + /** + * Shows the initial form to export/save admin settings + * + * Loads the database configuration and prints + * the settings in a hierical table + */ + public function show() { + + global $CFG; + + // Load site settings in the common format and do the js calls to populate the tree. + $settings = $this->_get_site_settings(); + $this->_get_settings_branches($settings); + + $url = $CFG->wwwroot . '/blocks/admin_presets/index.php?action=export&mode=execute'; + $this->moodleform = new admin_presets_export_form($url); + } + + /** + * Stores the preset into the DB + */ + public function execute() { + + global $CFG, $USER, $DB; + + confirm_sesskey(); + + $url = $CFG->wwwroot . '/blocks/admin_presets/index.php?action=export&mode=execute'; + $this->moodleform = new admin_presets_export_form($url); + + // Reload site settings. + $sitesettings = $this->_get_site_settings(); + + if ($data = $this->moodleform->get_data()) { + + // admin_preset record. + $preset = new StdClass(); + $preset->userid = $USER->id; + $preset->name = $data->name; + $preset->comments = $data->comments['text']; + $preset->site = $CFG->wwwroot; + $preset->author = $data->author; + $preset->moodleversion = $CFG->version; + $preset->moodlerelease = $CFG->release; + $preset->timecreated = time(); + $preset->timemodified = 0; + if (!$preset->id = $DB->insert_record('block_admin_presets', $preset)) { + print_error('errorinserting', 'block_admin_presets'); + } + + // Store it here for logging and other future id-oriented stuff. + $this->id = $preset->id; + + // We must ensure that there are settings selected. + foreach (filter_input_array(INPUT_POST) as $varname => $value) { + + unset($setting); + + if (strstr($varname, '@@') != false) { + + $settingsfound = true; + + // Avoid sensible data. + if (!empty($data->excludesensiblesettings) && !empty($this->sensiblesettings[$varname])) { + continue; + } + + $name = explode('@@', $varname); + $setting = new StdClass(); + $setting->adminpresetid = $preset->id; + $setting->plugin = $name[1]; + $setting->name = $name[0]; + $setting->value = $sitesettings[$setting->plugin][$setting->name]->get_value(); + + if (!$setting->id = $DB->insert_record('block_admin_presets_it', $setting)) { + print_error('errorinserting', 'block_admin_presets'); + } + + // Setting attributes must also be exported. + if ($attributes = $sitesettings[$setting->plugin][$setting->name]->get_attributes_values()) { + foreach ($attributes as $attributename => $value) { + + $attr = new StdClass(); + $attr->itemid = $setting->id; + $attr->name = $attributename; + $attr->value = $value; + + $DB->insert_record('block_admin_presets_it_a', $attr); + } + } + } + } + + // If there are no valid or selected settings we should delete the admin preset record. + if (empty($settingsfound)) { + $DB->delete_records('block_admin_presets', array('id' => $preset->id)); + redirect($CFG->wwwroot . '/blocks/admin_presets/index.php?action=export', + get_string('novalidsettingsselected', 'block_admin_presets'), 4); + } + } + + // Trigger the as it is usually triggered after execute finishes. + $this->log(); + + redirect($CFG->wwwroot . '/blocks/admin_presets/index.php'); + } + + /** + * To download system presets + * + * @return void preset file + * @throws dml_exception + * @throws moodle_exception + * @throws xml_output_exception + * @throws xml_writer_exception + */ + public function download_xml() { + + global $DB; + + confirm_sesskey(); + + if (!$preset = $DB->get_record('block_admin_presets', array('id' => $this->id))) { + print_error('errornopreset', 'block_admin_presets'); + } + + if (!$items = $DB->get_records('block_admin_presets_it', array('adminpresetid' => $this->id))) { + print_error('errornopreset', 'block_admin_presets'); + } + + // Start. + $xmloutput = new memory_xml_output(); + $xmlwriter = new xml_writer($xmloutput); + $xmlwriter->start(); + + // Preset data. + $xmlwriter->begin_tag('PRESET'); + foreach ($this->rel as $dbname => $xmlname) { + $xmlwriter->full_tag($xmlname, $preset->$dbname); + } + + // We ride through the settings array. + $allsettings = $this->_get_settings_from_db($items); + if ($allsettings) { + + $xmlwriter->begin_tag('ADMIN_SETTINGS'); + + foreach ($allsettings as $plugin => $settings) { + + $tagname = strtoupper($plugin); + + // To aviod xml slash problems. + if (strstr($tagname, '/') != false) { + $tagname = str_replace('/', '__', $tagname); + } + + $xmlwriter->begin_tag($tagname); + + // One tag for each plugin setting. + if (!empty($settings)) { + + $xmlwriter->begin_tag('SETTINGS'); + + foreach ($settings as $setting) { + + // Unset the tag attributes string. + $attributes = array(); + + // Getting setting attributes, if present. + $attrs = $DB->get_records('block_admin_presets_it_a', array('itemid' => $setting->itemid)); + if ($attrs) { + foreach ($attrs as $attr) { + $attributes[$attr->name] = $attr->value; + } + } + + $xmlwriter->full_tag(strtoupper($setting->name), $setting->value, $attributes); + } + + $xmlwriter->end_tag('SETTINGS'); + } + + $xmlwriter->end_tag(strtoupper($tagname)); + } + + $xmlwriter->end_tag('ADMIN_SETTINGS'); + } + + // End + $xmlwriter->end_tag('PRESET'); + $xmlwriter->stop(); + $xmlstr = $xmloutput->get_allcontents(); + + // Trigger the as it is usually triggered after execute finishes. + $this->log(); + + $filename = addcslashes($preset->name, '"') . '.xml'; + send_file($xmlstr, $filename, 0, 0, true, true); + } +} diff --git a/blocks/admin_presets/lib/admin_presets_import.class.php b/blocks/admin_presets/lib/admin_presets_import.class.php new file mode 100644 index 0000000000000000000000000000000000000000..5ef2ff2f515d9371727a41f2eed18aaa4be4e3a0 --- /dev/null +++ b/blocks/admin_presets/lib/admin_presets_import.class.php @@ -0,0 +1,180 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/blocks/admin_presets/lib/admin_presets_base.class.php'); + +class admin_presets_import extends admin_presets_base { + + /** + * Displays the import moodleform + */ + public function show() { + + global $CFG; + + $url = $CFG->wwwroot . '/blocks/admin_presets/index.php?action=import&mode=execute'; + $this->moodleform = new admin_presets_import_form($url); + } + + /** + * Imports the xmlfile into DB + */ + public function execute() { + + global $CFG, $USER, $DB; + + confirm_sesskey(); + + $sitesettings = $this->_get_site_settings(); + + $url = $CFG->wwwroot . '/blocks/admin_presets/index.php?action=import&mode=execute'; + $this->moodleform = new admin_presets_import_form($url); + + if ($data = $this->moodleform->get_data()) { + + $usercontext = context_user::instance($USER->id); + + // Getting the file. + $xmlcontent = $this->moodleform->get_file_content('xmlfile'); + $xml = simplexml_load_string($xmlcontent); + if (!$xml) { + redirect($CFG->wwwroot . '/blocks/admin_presets/index.php?action=import', + get_string('wrongfile', 'block_admin_presets'), 4); + } + + // Preset info. + $preset = new StdClass(); + foreach ($this->rel as $dbname => $xmlname) { + $preset->$dbname = (String) $xml->$xmlname; + } + $preset->userid = $USER->id; + $preset->timeimported = time(); + + // Overwrite preset name. + if ($data->name != '') { + $preset->name = $data->name; + } + + // Inserting preset. + if (!$preset->id = $DB->insert_record('block_admin_presets', $preset)) { + print_error('errorinserting', 'block_admin_presets'); + } + + // Store it here for logging and other future id-oriented stuff. + $this->id = $preset->id; + + // Plugins settings. + $xmladminsettings = $xml->ADMIN_SETTINGS[0]; + foreach ($xmladminsettings as $plugin => $settings) { + + $plugin = strtolower($plugin); + + if (strstr($plugin, '__') != false) { + $plugin = str_replace('__', '/', $plugin); + } + + $pluginsettings = $settings->SETTINGS[0]; + + if ($pluginsettings) { + foreach ($pluginsettings->children() as $name => $setting) { + + $name = strtolower($name); + + // Default to ''. + if ($setting->__toString() === false) { + $value = ''; + } else { + $value = $setting->__toString(); + } + + if (empty($sitesettings[$plugin][$name])) { + debugging('Setting ' . $plugin . '/' . $name . + ' not supported by this Moodle version', DEBUG_DEVELOPER); + continue; + } + + // Cleaning the setting value. + if (!$presetsetting = $this->_get_setting($sitesettings[$plugin][$name]->get_settingdata(), + $value)) { + debugging('Setting ' . $plugin . '/' . $name . ' not implemented', DEBUG_DEVELOPER); + continue; + } + + $settingsfound = true; + + // New item. + $item = new StdClass(); + $item->adminpresetid = $preset->id; + $item->plugin = $plugin; + $item->name = $name; + $item->value = $presetsetting->get_value(); + + // Inserting items. + if (!$item->id = $DB->insert_record('block_admin_presets_it', $item)) { + print_error('errorinserting', 'block_admin_presets'); + } + + // Adding settings attributes. + if ($setting->attributes() && ($itemattributes = $presetsetting->get_attributes())) { + + foreach ($setting->attributes() as $attrname => $attrvalue) { + + $itemattributenames = array_flip($itemattributes); + + // Check the attribute existence. + if (!isset($itemattributenames[$attrname])) { + debugging('The ' . $plugin . '/' . $name . ' attribute ' . $attrname . + ' is not supported by this Moodle version', DEBUG_DEVELOPER); + continue; + } + + $attr = new StdClass(); + $attr->itemid = $item->id; + $attr->name = $attrname; + $attr->value = $attrvalue->__toString(); + $DB->insert_record('block_admin_presets_it_a', $attr); + } + } + } + } + } + + // If there are no valid or selected settings we should delete the admin preset record. + if (empty($settingsfound)) { + $DB->delete_records('block_admin_presets', array('id' => $preset->id)); + redirect($CFG->wwwroot . '/blocks/admin_presets/index.php?action=import', + get_string('novalidsettings', 'block_admin_presets'), 4); + } + + // Trigger the as it is usually triggered after execute finishes. + $this->log(); + + redirect($CFG->wwwroot . '/blocks/admin_presets/index.php?action=load&id=' . $preset->id); + } + } +} diff --git a/blocks/admin_presets/lib/admin_presets_load.class.php b/blocks/admin_presets/lib/admin_presets_load.class.php new file mode 100644 index 0000000000000000000000000000000000000000..18369d5f3f45b638b677d28fdbe49441945c5426 --- /dev/null +++ b/blocks/admin_presets/lib/admin_presets_load.class.php @@ -0,0 +1,292 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/blocks/admin_presets/lib/admin_presets_base.class.php'); + +class admin_presets_load extends admin_presets_base { + + /** + * Executes the settings load into the system + */ + public function execute() { + + global $CFG, $DB, $OUTPUT, $USER; + + confirm_sesskey(); + + $url = $CFG->wwwroot . '/blocks/admin_presets/index.php?action=load&mode=execute'; + $this->moodleform = new admin_presets_load_form($url); + + if ($data = $this->moodleform->get_data()) { + + // Standarized format $array['plugin']['settingname'] = child class. + $siteavailablesettings = $this->_get_site_settings(); + + // Get preset settings + if (!$items = $DB->get_records('block_admin_presets_it', array('adminpresetid' => $this->id))) { + print_error('errornopreset', 'block_admin_presets'); + } + $presetdbsettings = $this->_get_settings_from_db($items); + + // Standarized format $array['plugin']['settingname'] = child class. + $presetsettings = $this->_get_settings($presetdbsettings, false, $presetsettings = array()); + + // Only for selected items. + $appliedchanges = array(); + $unnecessarychanges = array(); + foreach (filter_input_array(INPUT_POST) as $varname => $value) { + + unset($updatesetting); + + if (strstr($varname, '@@') != false) { + + // [0] => setting [1] => plugin. + $name = explode('@@', $varname); + + // Just to be sure. + if (empty($presetsettings[$name[1]][$name[0]])) { + continue; + } + if (empty($siteavailablesettings[$name[1]][$name[0]])) { + continue; + } + + // New and old values. + $presetsetting = $presetsettings[$name[1]][$name[0]]; + $sitesetting = $siteavailablesettings[$name[1]][$name[0]]; + + // Wrong setting, set_value() method has previously cleaned the value. + if ($presetsetting->get_value() === false) { + debugging($presetsetting->get_settingdata()->plugin . '/' . + $presetsetting->get_settingdata()->name . + ' setting has a wrong value!', DEBUG_DEVELOPER); + continue; + } + + // If the new value is different the setting must be updated. + if ($presetsetting->get_value() != $sitesetting->get_value()) { + $updatesetting = true; + } + + // If one of the setting attributes values is different, setting must also be updated. + if ($presetsetting->get_attributes_values()) { + + $siteattributesvalues = $sitesetting->get_attributes_values(); + foreach ($presetsetting->get_attributes_values() as $attributename => $attributevalue) { + + if ($attributevalue !== $siteattributesvalues[$attributename]) { + $updatesetting = true; + } + } + } + + // Saving data + if (!empty($updatesetting)) { + + // The preset application it's only saved when values differences are found. + if (empty($applieditem)) { + // Save the preset application and store the preset applied id. + $presetapplied = new StdClass(); + $presetapplied->adminpresetid = $this->id; + $presetapplied->userid = $USER->id; + $presetapplied->time = time(); + if (!$adminpresetapplyid = $DB->insert_record('block_admin_presets_app', + $presetapplied)) { + print_error('errorinserting', 'block_admin_presets'); + } + } + + // Implemented this way because the config_write. + // method of admin_setting class does not. + // return the config_log inserted id. + $applieditem = new StdClass(); + $applieditem->adminpresetapplyid = $adminpresetapplyid; + if ($applieditem->configlogid = $presetsetting->save_value()) { + $DB->insert_record('block_admin_presets_app_it', $applieditem); + } + + // For settings with multiple values. + if ($attributeslogids = $presetsetting->save_attributes_values()) { + foreach ($attributeslogids as $attributelogid) { + $applieditemattr = new StdClass(); + $applieditemattr->adminpresetapplyid = $applieditem->adminpresetapplyid; + $applieditemattr->configlogid = $attributelogid; + $applieditemattr->itemname = $presetsetting->get_settingdata()->name; + $DB->insert_record('block_admin_presets_app_it_a', $applieditemattr); + } + } + + // Added to changed values. + $appliedchanges[$varname] = new StdClass(); + $appliedchanges[$varname]->plugin = $presetsetting->get_settingdata()->plugin; + $appliedchanges[$varname]->visiblename = $presetsetting->get_settingdata()->visiblename; + $appliedchanges[$varname]->oldvisiblevalue = $sitesetting->get_visiblevalue(); + $appliedchanges[$varname]->visiblevalue = $presetsetting->get_visiblevalue(); + + // Unnecessary changes (actual setting value). + } else { + $unnecessarychanges[$varname] = $presetsetting; + } + } + } + } + + // Output applied changes. + if (!empty($appliedchanges)) { + $this->outputs .= '<br/>' . $OUTPUT->heading(get_string('settingsapplied', + 'block_admin_presets'), 3, 'admin_presets_success'); + $this->_output_applied_changes($appliedchanges); + } else { + $this->outputs .= '<br/>' . $OUTPUT->heading(get_string('nothingloaded', + 'block_admin_presets'), 3, 'admin_presets_error'); + } + + // Show skipped changes. + if (!empty($unnecessarychanges)) { + + $skippedtable = new html_table(); + $skippedtable->attributes['class'] = 'generaltable boxaligncenter admin_presets_skipped'; + $skippedtable->head = array(get_string('plugin'), + get_string('settingname', 'block_admin_presets'), + get_string('actualvalue', 'block_admin_presets') + ); + + $skippedtable->align = array('center', 'center'); + + $this->outputs .= '<br/>' . $OUTPUT->heading(get_string('settingsnotapplied', + 'block_admin_presets'), 3); + + foreach ($unnecessarychanges as $setting) { + $skippedtable->data[] = array($setting->get_settingdata()->plugin, + $setting->get_settingdata()->visiblename, + $setting->get_visiblevalue() + ); + } + + $this->outputs .= html_writer::table($skippedtable); + } + + // Don't display the load form. + $this->moodleform = false; + } + + /** + * Lists the preset available settings + */ + public function preview() { + $this->show(1); + } + + /** + * Displays the select preset settings to select what to import + * + * Loads the preset data and displays a settings tree + * + * It checks the Moodle version, it only allows users + * to import the preset available settings + * + * @param boolean $preview If it's a preview it only lists the preset applicable settings + * @throws coding_exception + * @throws dml_exception + * @throws moodle_exception + */ + public function show($preview = false) { + + global $CFG, $DB, $OUTPUT; + + $data = new StdClass(); + $data->id = $this->id; + + // Preset data. + if (!$preset = $DB->get_record('block_admin_presets', array('id' => $data->id))) { + print_error('errornopreset', 'block_admin_presets'); + } + + if (!$items = $DB->get_records('block_admin_presets_it', array('adminpresetid' => $data->id))) { + print_error('errornopreset', 'block_admin_presets'); + } + + // Standarized format $array['pluginname']['settingname']. + // object('name' => 'settingname', 'value' => 'settingvalue'). + $presetdbsettings = $this->_get_settings_from_db($items); + + // Load site avaible settings to ensure that the settings exists on this release. + $siteavailablesettings = $this->_get_site_settings(); + + $notapplicable = array(); + if ($presetdbsettings) { + foreach ($presetdbsettings as $plugin => $elements) { + foreach ($elements as $settingname => $element) { + + // If the setting doesn't exists in that release skip it. + if (empty($siteavailablesettings[$plugin][$settingname])) { + + // Adding setting plugin. + $presetdbsettings[$plugin][$settingname]->plugin = $plugin; + + $notapplicable[] = $presetdbsettings[$plugin][$settingname]; + } + } + } + } + // Standarized format $array['plugin']['settingname'] = child class. + $presetsettings = $this->_get_settings($presetdbsettings, false, $presetsettings = array()); + + $this->_get_settings_branches($presetsettings); + + // Print preset basic data. + $this->outputs .= $this->_html_writer_preset_info_table($preset); + + // Display not applicable settings. + if (!empty($notapplicable)) { + + $this->outputs .= '<br/>' . $OUTPUT->heading(get_string('settingsnotapplicable', + 'block_admin_presets'), 3, 'admin_presets_error'); + + $table = new html_table(); + $table->attributes['class'] = 'generaltable boxaligncenter'; + $table->head = array(get_string('plugin'), + get_string('settingname', 'block_admin_presets'), + get_string('value', 'block_admin_presets')); + + $table->align = array('center', 'center'); + + foreach ($notapplicable as $setting) { + $table->data[] = array($setting->plugin, $setting->name, $setting->value); + } + + $this->outputs .= html_writer::table($table); + + } + + $url = $CFG->wwwroot . '/blocks/admin_presets/index.php?action=load&mode=execute'; + $this->moodleform = new admin_presets_load_form($url, $preview); + $this->moodleform->set_data($data); + + } +} diff --git a/blocks/admin_presets/lib/admin_presets_rollback.class.php b/blocks/admin_presets/lib/admin_presets_rollback.class.php new file mode 100644 index 0000000000000000000000000000000000000000..a51755fb444c6c36a4d466daa27feb83d8e2e148 --- /dev/null +++ b/blocks/admin_presets/lib/admin_presets_rollback.class.php @@ -0,0 +1,230 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/blocks/admin_presets/lib/admin_presets_base.class.php'); + +class admin_presets_rollback extends admin_presets_base { + + /** + * Displays the different previous applications of the preset + */ + public function show() { + + global $CFG, $DB, $OUTPUT; + + $table = new html_table(); + $table->attributes['class'] = 'generaltable boxaligncenter'; + $table->head = array(get_string('timeapplied', + 'block_admin_presets'), get_string('user'), get_string('actions')); + $table->align = array('left', 'center', 'left'); + + // Preset data. + $preset = $DB->get_record('block_admin_presets', array('id' => $this->id)); + + // Applications data. + $applications = $DB->get_records('block_admin_presets_app', array('adminpresetid' => $this->id)); + if (!$applications) { + print_error('notpreviouslyapplied', 'block_admin_presets'); + } + + foreach ($applications as $application) { + + $format = get_string('strftimedatetime', 'langconfig'); + + $user = $DB->get_record('user', array('id' => $application->userid)); + + $rollbacklink = $CFG->wwwroot . + '/blocks/admin_presets/index.php?action=rollback&mode=execute&id=' . + $application->id . '&sesskey=' . sesskey(); + $action = html_writer::link($rollbacklink, + get_string("rollback", "block_admin_presets")); + + $table->data[] = array(strftime($format, $application->time), + $user->firstname . ' ' . $user->lastname, + '<div>' . $action . '</div>' + ); + } + + $this->outputs .= '<br/>' . $OUTPUT->heading(get_string("presetname", + "block_admin_presets") . ': ' . $preset->name, 3); + $this->outputs .= html_writer::table($table); + } + + /** + * Executes the application rollback + * + * Each setting value is checked against the config_log->value + */ + public function execute() { + + global $DB, $OUTPUT; + + confirm_sesskey(); + + // Actual settings. + $sitesettings = $this->_get_site_settings(); + + // To store rollback results. + $rollback = array(); + $failures = array(); + + if (!$DB->get_record('block_admin_presets_app', array('id' => $this->id))) { + print_error('wrongid', 'block_admin_presets'); + } + + // Items. + $itemsql = "SELECT cl.id, cl.plugin, cl.name, cl.value, cl.oldvalue, ap.adminpresetapplyid + FROM {block_admin_presets_app_it} ap + JOIN {config_log} cl ON cl.id = ap.configlogid + WHERE ap.adminpresetapplyid = {$this->id}"; + $itemchanges = $DB->get_records_sql($itemsql); + if ($itemchanges) { + + foreach ($itemchanges as $change) { + + if ($change->plugin == '') { + $change->plugin = 'none'; + } + + // Admin setting. + if (!empty($sitesettings[$change->plugin][$change->name])) { + + $actualsetting = $sitesettings[$change->plugin][$change->name]; + $oldsetting = $this->_get_setting($actualsetting->get_settingdata(), $change->oldvalue); + $oldsetting->set_text(); + $varname = $change->plugin . '_' . $change->name; + + // Check if the actual value is the same set by the preset. + if ($change->value == $actualsetting->get_value()) { + + $oldsetting->save_value(); + + // Output table. + $rollback[$varname] = new stdClass(); + $rollback[$varname]->plugin = $oldsetting->get_settingdata()->plugin; + $rollback[$varname]->visiblename = $oldsetting->get_settingdata()->visiblename; + $rollback[$varname]->oldvisiblevalue = $actualsetting->get_visiblevalue(); + $rollback[$varname]->visiblevalue = $oldsetting->get_visiblevalue(); + + // Deleting the admin_preset_apply_item instance. + $deletewhere = array('adminpresetapplyid' => $change->adminpresetapplyid, + 'configlogid' => $change->id); + $DB->delete_records('block_admin_presets_app_it', $deletewhere); + + } else { + + $failures[$varname] = new stdClass(); + $failures[$varname]->plugin = $oldsetting->get_settingdata()->plugin; + $failures[$varname]->visiblename = $oldsetting->get_settingdata()->visiblename; + $failures[$varname]->oldvisiblevalue = $actualsetting->get_visiblevalue(); + $failures[$varname]->visiblevalue = $oldsetting->get_visiblevalue(); + } + } + } + } + + // Attributes. + $attrsql = "SELECT cl.id, cl.plugin, cl.name, cl.value, cl.oldvalue, ap.itemname, ap.adminpresetapplyid + FROM {block_admin_presets_app_it_a} ap + JOIN {config_log} cl ON cl.id = ap.configlogid + WHERE ap.adminpresetapplyid = {$this->id}"; + $attrchanges = $DB->get_records_sql($attrsql); + if ($attrchanges) { + + foreach ($attrchanges as $change) { + + if ($change->plugin == '') { + $change->plugin = 'none'; + } + + // Admin setting of the attribute item. + if (!empty($sitesettings[$change->plugin][$change->itemname])) { + + // Getting the attribute item. + $actualsetting = $sitesettings[$change->plugin][$change->itemname]; + + $oldsetting = $this->_get_setting($actualsetting->get_settingdata(), $actualsetting->get_value()); + $oldsetting->set_attribute_value($change->name, $change->oldvalue); + $oldsetting->set_text(); + + $varname = $change->plugin . '_' . $change->name; + + // Check if the actual value is the same set by the preset. + $actualattributes = $actualsetting->get_attributes_values(); + if ($change->value == $actualattributes[$change->name]) { + + $oldsetting->save_attributes_values(); + + // Output table. + $rollback[$varname] = new stdClass(); + $rollback[$varname]->plugin = $oldsetting->get_settingdata()->plugin; + $rollback[$varname]->visiblename = $oldsetting->get_settingdata()->visiblename; + $rollback[$varname]->oldvisiblevalue = $actualsetting->get_visiblevalue(); + $rollback[$varname]->visiblevalue = $oldsetting->get_visiblevalue(); + + // Deleting the admin_preset_apply_item_attr instance. + $deletewhere = array('adminpresetapplyid' => $change->adminpresetapplyid, + 'configlogid' => $change->id); + $DB->delete_records('block_admin_presets_app_it_a', $deletewhere); + + } else { + + $failures[$varname] = new stdClass(); + $failures[$varname]->plugin = $oldsetting->get_settingdata()->plugin; + $failures[$varname]->visiblename = $oldsetting->get_settingdata()->visiblename; + $failures[$varname]->oldvisiblevalue = $actualsetting->get_visiblevalue(); + $failures[$varname]->visiblevalue = $oldsetting->get_visiblevalue(); + } + } + } + } + + // Delete application if no items nor attributes of the application remains. + if (!$DB->get_record('block_admin_presets_app_it', array('adminpresetapplyid' => $this->id)) && + !$DB->get_records('block_admin_presets_app_it_a', array('adminpresetapplyid' => $this->id))) { + + $DB->delete_records('block_admin_presets_app', array('id' => $this->id)); + } + + // Display the rollback changes. + if (!empty($rollback)) { + $this->outputs .= '<br/>' . $OUTPUT->heading(get_string('rollbackresults', + "block_admin_presets"), 3, 'admin_presets_success'); + $this->outputs .= '<br/>'; + $this->_output_applied_changes($rollback); + } + + // Display the rollback failures. + if (!empty($failures)) { + $this->outputs .= '<br/>' . $OUTPUT->heading(get_string('rollbackfailures', + 'block_admin_presets'), 3, 'admin_presets_error'); + $this->outputs .= '<br/>'; + $this->_output_applied_changes($failures); + } + } +} diff --git a/blocks/admin_presets/lib/admin_presets_settings_types.php b/blocks/admin_presets/lib/admin_presets_settings_types.php new file mode 100644 index 0000000000000000000000000000000000000000..cc0dc6672087931f3eb2bcbdb7afb5eaa3fd007a --- /dev/null +++ b/blocks/admin_presets/lib/admin_presets_settings_types.php @@ -0,0 +1,1201 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +abstract class admin_preset_setting { + + /** + * @var admin_setting + */ + protected $settingdata; + + /** + * @var admin_presets_delegation + */ + protected $delegation; + + /** + * The setting DB value + * + * @var mixed + */ + protected $value; + + /** + * Stores the visible value of the setting DB value + * + * @var string + */ + protected $visiblevalue; + + /** + * Text to display on the TreeView + * + * @var string + */ + protected $text; + + /** + * For multiple value settings, used to look for the other values + * + * @var string + */ + protected $attributes = false; + + /** + * To store the setting attributes + * + * @var array + */ + protected $attributesvalues; + + /** + * Stores the setting data and the selected value + * + * @param admin_setting $settingdata admin_setting subclass + * @param mixed $dbsettingvalue Actual value + */ + public function __construct(admin_setting $settingdata, $dbsettingvalue) { + + $this->settingdata = $settingdata; + $this->delegation = new admin_presets_delegation(); + + if ($this->settingdata->plugin == '') { + $this->settingdata->plugin = 'none'; + } + + // Applies specific children behaviors + $this->set_behaviors(); + $this->apply_behaviors(); + + // Cleaning value. + $this->set_value($dbsettingvalue); + } + + /** + * Each class can overwrite this method to specify extra processes + */ + protected function set_behaviors() { + } + + /** + * Applies the children class specific behaviors + * + * See admin_presets_delegation() for the available extra behaviors + */ + protected function apply_behaviors() { + + if (!empty($this->behaviors)) { + + foreach ($this->behaviors as $behavior => $arguments) { + + // The arguments of the behavior depends on the caller. + $methodname = 'extra_' . $behavior; + $this->delegation->{$methodname}($arguments); + } + } + } + + /** + * Returns the TreeView node identifier + */ + public function get_id() { + return $this->settingdata->name . '@@' . $this->settingdata->plugin; + } + + public function get_value() { + return $this->value; + } + + /** + * Sets the setting value cleaning it + * + * Child classes should overwrite method to clean more acurately + * + * @param mixed $value Setting value + * @return mixed Returns false if wrong param value + */ + protected function set_value($value) { + $this->value = $value; + } + + public function get_visiblevalue() { + return $this->visiblevalue; + } + + /** + * Sets the visible name for the setting selected value + * + * In most cases the child classes will overwrite + */ + protected function set_visiblevalue() { + $this->visiblevalue = $this->value; + } + + public function get_description() { + + // PARAM_TEXT clean because the alt attribute does not support html. + $description = clean_param($this->settingdata->description, PARAM_TEXT); + return $this->encode_string($description); + } + + /** + * Encodes a string to send it to js + * + * @param string $string + * @return string + */ + protected function encode_string($string) { + + $encoded = rawurlencode($string); + return $encoded; + } + + public function get_text() { + return $this->encode_string($this->text); + } + + /** + * Sets the text to display on the settings tree + * + * Default format: I'm a setting visible name (setting value: "VALUE") + */ + public function set_text() { + + $this->set_visiblevalue(); + + $namediv = '<div class="admin_presets_tree_name">' . $this->settingdata->visiblename . '</div>'; + $valuediv = '<div class="admin_presets_tree_value">' . $this->visiblevalue . '</div>'; + + $this->text = $namediv . $valuediv . '<br/>'; + } + + public function get_attributes() { + return $this->attributes; + } + + public function get_attributes_values() { + return $this->attributesvalues; + } + + public function get_settingdata() { + return $this->settingdata; + } + + public function set_attribute_value($name, $value) { + $this->attributesvalues[$name] = $value; + } + + /** + * Saves the setting attributes values + * + * @return array Array of inserted ids (in config_log) + */ + public function save_attributes_values() { + + // Plugin name or null. + $plugin = $this->settingdata->plugin; + if ($plugin == 'none' || $plugin == '') { + $plugin = null; + } + + if (!$this->attributesvalues) { + return false; + } + + // To store inserted ids. + $ids = array(); + foreach ($this->attributesvalues as $name => $value) { + + // Getting actual setting. + $actualsetting = get_config($plugin, $name); + + // If it's the actual setting get off. + if ($value == $actualsetting) { + return false; + } + + if ($id = $this->save_value($name, $value)) { + $ids[] = $id; + } + } + + return $ids; + } + + /** + * Stores the setting into database, logs the change and returns the config_log inserted id + * + * @param bool $name + * @param mixed $value + * @return integer config_log inserted id + * @throws dml_exception + * @throws moodle_exception + */ + public function save_value($name = false, $value = null) { + + // Object values if no arguments. + if ($value === null) { + $value = $this->value; + } + if (!$name) { + $name = $this->settingdata->name; + } + + // Plugin name or null. + $plugin = $this->settingdata->plugin; + if ($plugin == 'none' || $plugin == '') { + $plugin = null; + } + + // Getting the actual value. + $actualvalue = get_config($plugin, $name); + + // If it's the same it's not necessary. + if ($actualvalue == $value) { + return false; + } + + set_config($name, $value, $plugin); + + return $this->to_log($plugin, $name, $value, $actualvalue); + } + + /** + * Copy of config_write method of the admin_setting class + * + * @param string $plugin + * @param string $name + * @param mixed $value + * @param mixed $actualvalue + * @return integer The stored config_log id + */ + protected function to_log($plugin, $name, $value, $actualvalue) { + + global $DB, $USER; + + // Log the change (pasted from admin_setting class). + $log = new stdClass(); + $log->userid = during_initial_install() ? 0 : $USER->id; // 0 as user id during install. + $log->timemodified = time(); + $log->plugin = $plugin; + $log->name = $name; + $log->value = $value; + $log->oldvalue = $actualvalue; + + // Getting the inserted config_log id. + if (!$id = $DB->insert_record('config_log', $log)) { + print_error('errorinserting', 'block_admin_presets'); + } + + return $id; + } +} + +/** + * Cross-class methods + */ +class admin_presets_delegation { + + /** + * Adds a piece of string to the $type setting + * + * @param boolean $value + * @param string $type Indicates the "extra" setting + * @return string + */ + public function extra_set_visiblevalue($value, $type) { + + // Adding the advanced value to the text string if present. + if ($value) { + $string = get_string('markedas' . $type, 'block_admin_presets'); + } else { + $string = get_string('markedasnon' . $type, 'block_admin_presets'); + } + + // Adding the advanced state. + return ', ' . $string; + } + + public function extra_loadchoices(admin_setting &$adminsetting) { + $adminsetting->load_choices(); + } +} + +/** TEXT **/ + +/** + * Basic text setting, cleans the param using the admin_setting paramtext attribute + */ +class admin_preset_auth_ldap_admin_setting_special_contexts_configtext extends admin_preset_setting { + + /** + * Validates the value using paramtype attribute + * + * @param string $value + * @return boolean Cleaned or not, but always true + */ + protected function set_value($value) { + + $this->value = $value; + + if (empty($this->settingdata->paramtype)) { + + // For configfile, configpasswordunmask... + $this->settingdata->paramtype = 'RAW'; + } + + $paramtype = 'PARAM_' . strtoupper($this->settingdata->paramtype); + + // Regexp. + if (!defined($paramtype)) { + $this->value = preg_replace($this->settingdata->paramtype, '', $this->value); + + // Standard moodle param type. + } else { + $this->value = clean_param($this->value, constant($paramtype)); + } + + return true; + } +} + +/** + * Basic text setting, cleans the param using the admin_setting paramtext attribute + */ +class admin_preset_admin_setting_configtext extends admin_preset_setting { + + /** + * Validates the value using paramtype attribute + * + * @param string $value + * @return boolean Cleaned or not, but always true + */ + protected function set_value($value) { + + $this->value = $value; + + if (empty($this->settingdata->paramtype)) { + + // For configfile, configpasswordunmask... + $this->settingdata->paramtype = 'RAW'; + } + + $paramtype = 'PARAM_' . strtoupper($this->settingdata->paramtype); + + // Regexp. + if (!defined($paramtype)) { + $this->value = preg_replace($this->settingdata->paramtype, '', $this->value); + + // Standard moodle param type. + } else { + $this->value = clean_param($this->value, constant($paramtype)); + } + + return true; + } +} + +/** + * Adds the advanced attribute + */ +class admin_preset_admin_setting_configtext_with_advanced extends admin_preset_admin_setting_configtext { + + public function __construct(admin_setting $settingdata, $dbsettingvalue) { + + // To look for other values. + $this->attributes = array('fix' => $settingdata->name . '_adv'); + parent::__construct($settingdata, $dbsettingvalue); + } + + /** + * Delegates + */ + protected function set_visiblevalue() { + parent::set_visiblevalue(); + $this->visiblevalue .= $this->delegation->extra_set_visiblevalue( + $this->attributesvalues[$this->attributes['fix']], 'advanced'); + } +} + +class admin_preset_admin_setting_configiplist extends admin_preset_admin_setting_configtext { + + protected function set_value($value) { + + // Just in wrong format case. + $this->value = ''; + + // Check ip format. + if ($this->settingdata->validate($value) !== true) { + $this->value = false; + return false; + } + + $this->value = $value; + return true; + } +} + +/** + * Reimplementation to allow human friendly view of the selected regexps + */ +class admin_preset_admin_setting_devicedetectregex extends admin_preset_admin_setting_configtext { + + public function set_visiblevalue() { + + $values = json_decode($this->get_value()); + + if (!$values) { + parent::set_visiblevalue(); + return; + } + + $this->visiblevalue = ''; + foreach ($values as $key => $value) { + $this->visiblevalue .= $key . ' = ' . $value . ', '; + } + $this->visiblevalue = rtrim($this->visiblevalue, ', '); + } +} + +/** + * Reimplemented to store values in course table, not in config or config_plugins + */ +class admin_preset_admin_setting_sitesettext extends admin_preset_admin_setting_configtext { + + /** + * Overwritten to store the value in the course table + * + * @param bool $name + * @param mixed $value + * @return integer + */ + public function save_value($name = false, $value = false) { + + global $DB; + + // Object values if no arguments. + if ($value === null) { + $value = $this->value; + } + if (!$name) { + $name = $this->settingdata->name; + } + + $sitecourse = $DB->get_record('course', array('id' => 1)); + $actualvalue = $sitecourse->{$name}; + + // If it's the same value skip. + if ($actualvalue == $this->value) { + return false; + } + + // Plugin name or ''. + $plugin = $this->settingdata->plugin; + if ($plugin == 'none' || $plugin == '') { + $plugin = null; + } + + // Updating mdl_course. + $sitecourse->{$name} = $this->value; + $DB->update_record('course', $sitecourse); + + return $this->to_log($plugin, $name, $this->value, $actualvalue); + } +} + +class admin_preset_admin_setting_configselect extends admin_preset_setting { + + /** + * $value must be one of the setting choices + * + * @return boolean true if the value one of the setting choices + */ + protected function set_value($value) { + + // When we intantiate the class we need the choices. + if (empty($this->settindata->choices) && method_exists($this->settingdata, 'load_choices')) { + $this->settingdata->load_choices(); + } + + foreach ($this->settingdata->choices as $key => $choice) { + + if ($key == $value) { + $this->value = $value; + return true; + } + } + + $this->value = false; + return false; + } + + protected function set_visiblevalue() { + + // Just to avoid heritage problems. + if (empty($this->settingdata->choices[$this->value])) { + $this->visiblevalue = ''; + } else { + $this->visiblevalue = $this->settingdata->choices[$this->value]; + } + + } +} + +class admin_preset_admin_setting_bloglevel extends admin_preset_admin_setting_configselect { + + /** + * Extended to change the block visibility + */ + public function save_value($name = false, $value = false) { + + global $DB; + + if (!$id = parent::save_value($name, $value)) { + return false; + } + + // Pasted from admin_setting_bloglevel (can't use write_config). + if ($value == 0) { + $DB->set_field('block', 'visible', 0, array('name' => 'blog_menu')); + } else { + $DB->set_field('block', 'visible', 1, array('name' => 'blog_menu')); + } + + return $id; + } +} + +/** + * Adds support for the "advanced" attribute + */ +class admin_preset_admin_setting_configselect_with_advanced extends admin_preset_admin_setting_configselect { + + protected $advancedkey; + + public function __construct(admin_setting $settingdata, $dbsettingvalue) { + + // Getting the advanced defaultsetting attribute name. + if (is_array($settingdata->defaultsetting)) { + foreach ($settingdata->defaultsetting as $key => $defaultvalue) { + if ($key != 'value') { + $this->advancedkey = $key; + } + } + } + + // To look for other values. + $this->attributes = array($this->advancedkey => $settingdata->name . '_adv'); + parent::__construct($settingdata, $dbsettingvalue); + } + + /** + * Funcionality used by other _with_advanced settings + */ + protected function set_visiblevalue() { + parent::set_visiblevalue(); + $this->visiblevalue .= $this->delegation->extra_set_visiblevalue( + $this->attributesvalues[$this->attributes[$this->advancedkey]], 'advanced'); + } +} + +class admin_preset_mod_quiz_admin_setting_browsersecurity extends admin_preset_admin_setting_configselect_with_advanced { + + public function set_behaviors() { + $this->behaviors['loadchoices'] = &$this->settingdata; + } +} + +class admin_preset_mod_quiz_admin_setting_grademethod extends admin_preset_admin_setting_configselect_with_advanced { + + public function set_behaviors() { + $this->behaviors['loadchoices'] = &$this->settingdata; + } +} + +class admin_preset_mod_quiz_admin_setting_overduehandling extends admin_preset_admin_setting_configselect_with_advanced { + + public function set_behaviors() { + $this->behaviors['loadchoices'] = &$this->settingdata; + } +} + +class admin_preset_mod_quiz_admin_setting_user_image extends admin_preset_admin_setting_configselect_with_advanced { + + public function set_behaviors() { + $this->behaviors['loadchoices'] = &$this->settingdata; + } +} + +/** + * A select with force and advanced options + */ +class admin_preset_admin_setting_gradecat_combo extends admin_preset_admin_setting_configselect { + + /** + * One db value for two setting attributes + * + * @param admin_setting $settingdata + * @param unknown_type $dbsettingvalue + */ + public function __construct(admin_setting $settingdata, $dbsettingvalue) { + + // set_attribute_value() will mod the VARNAME_flag value. + $this->attributes = array('forced' => $settingdata->name . '_flag', + 'adv' => $settingdata->name . '_flag'); + parent::__construct($settingdata, $dbsettingvalue); + } + + /** + * Special treatment! the value be extracted from the $value argument + */ + protected function set_visiblevalue() { + parent::set_visiblevalue(); + + $flagvalue = $this->attributesvalues[$this->settingdata->name . '_flag']; + + if (isset($flagvalue)) { + + if (($flagvalue % 2) == 1) { + $forcedvalue = '1'; + } else { + $forcedvalue = '0'; + } + + if ($flagvalue >= 2) { + $advancedvalue = '1'; + } else { + $advancedvalue = '0'; + } + $this->visiblevalue .= $this->delegation->extra_set_visiblevalue($forcedvalue, 'forced'); + $this->visiblevalue .= $this->delegation->extra_set_visiblevalue($advancedvalue, 'advanced'); + } + } +} + +/** + * Extends the base class and lists the selected values separated by comma + */ +class admin_preset_admin_setting_configmultiselect extends admin_preset_setting { + + /** + * Ensure that the $value values are setting choices + */ + protected function set_value($value) { + + if ($value) { + $options = explode(',', $value); + foreach ($options as $key => $option) { + + foreach ($this->settingdata->choices as $key => $choice) { + + if ($key == $value) { + $this->value = $value; + return true; + } + } + } + + $value = implode(',', $options); + } + + $this->value = $value; + } + + protected function set_visiblevalue() { + + $values = explode(',', $this->value); + $visiblevalues = array(); + + foreach ($values as $value) { + + if (!empty($this->settingdata->choices[$value])) { + $visiblevalues[] = $this->settingdata->choices[$value]; + } + } + + if (empty($visiblevalues)) { + $this->visiblevalue = ''; + return false; + } + + $this->visiblevalue = implode(', ', $visiblevalues); + } +} + +/** + * Extends configselect to reuse set_valuevisible + */ +class admin_preset_admin_setting_users_with_capability extends admin_preset_admin_setting_configmultiselect { + + protected function set_behaviors() { + $this->behaviors['loadchoices'] = &$this->settingdata; + } + + protected function set_value($value) { + + // Dirty hack (the value stored in the DB is ''). + $this->settingdata->choices[''] = $this->settingdata->choices['$@NONE@$']; + + return parent::set_value($value); + } +} + +/** + * Generalizes a configmultipleselect with load_choices() + * + * @abstract + */ +abstract class admin_preset_admin_setting_configmultiselect_with_loader extends admin_preset_admin_setting_configmultiselect { + + public function set_behaviors() { + $this->behaviors['loadchoices'] = &$this->settingdata; + } +} + +class admin_preset_admin_setting_configtime extends admin_preset_setting { + + /** + * To check that the value is one of the options + * + * @param string $name + * @param mixed $value + */ + public function set_attribute_value($name, $value) { + + for ($i = 0; $i < 60; $i = $i + 5) { + $minutes[$i] = $i; + } + + if (!empty($minutes[$value])) { + $this->attributesvalues[$name] = $value; + } else { + $this->attributesvalues[$name] = $this->settingdata->defaultsetting['m']; + } + } + + protected function set_value($value) { + + $this->attributes = array('m' => $this->settingdata->name2); + + for ($i = 0; $i < 24; $i++) { + $hours[$i] = $i; + } + + if (empty($hours[$value])) { + $this->value = false; + } + + $this->value = $value; + } + + protected function set_visiblevalue() { + $this->visiblevalue = $this->value . ':' . $this->attributesvalues[$this->settingdata->name2]; + } +} + +/** CHECKBOXES **/ +class admin_preset_admin_setting_configcheckbox extends admin_preset_setting { + + protected function set_value($value) { + $this->value = clean_param($value, PARAM_BOOL); + return true; + } + + protected function set_visiblevalue() { + + if ($this->value) { + $str = get_string('yes'); + } else { + $str = get_string('no'); + } + + $this->visiblevalue = $str; + } +} + +class admin_preset_admin_setting_configcheckbox_with_advanced extends admin_preset_admin_setting_configcheckbox { + + public function __construct(admin_setting $settingdata, $dbsettingvalue) { + + // To look for other values. + $this->attributes = array('adv' => $settingdata->name . '_adv'); + parent::__construct($settingdata, $dbsettingvalue); + } + + /** + * Uses delegation + */ + protected function set_visiblevalue() { + parent::set_visiblevalue(); + $this->visiblevalue .= $this->delegation->extra_set_visiblevalue( + $this->attributesvalues[$this->attributes['adv']], 'advanced'); + } +} + +class admin_preset_admin_setting_configcheckbox_with_lock extends admin_preset_admin_setting_configcheckbox { + + public function __construct(admin_setting $settingdata, $dbsettingvalue) { + + // To look for other values. + $this->attributes = array('locked' => $settingdata->name . '_locked'); + parent::__construct($settingdata, $dbsettingvalue); + } + + /** + * Uses delegation + */ + protected function set_visiblevalue() { + parent::set_visiblevalue(); + $this->visiblevalue .= $this->delegation->extra_set_visiblevalue( + $this->attributesvalues[$this->attributes['locked']], 'locked'); + } +} + +/** + * Abstract class to be extended by multicheckbox settings + * + * Now it's a useless class, child classes could extend admin_preset_admin_setting_configmultiselect + * + * @abstract + */ +class admin_preset_admin_setting_configmulticheckbox extends admin_preset_admin_setting_configmultiselect { + + public function set_behaviors() { + $this->behaviors['loadchoices'] = &$this->settingdata; + } +} + +/** + * It doesn't specify loadchoices behavior because is set_visiblevalue who needs it + */ +class admin_preset_admin_setting_special_backupdays extends admin_preset_setting { + + protected function set_value($value) { + $this->value = clean_param($value, PARAM_SEQUENCE); + } + + protected function set_visiblevalue() { + + // TODO Try to use $this->behaviors. + $this->settingdata->load_choices(); + + $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'); + + $selecteddays = array(); + + $week = str_split($this->value); + foreach ($week as $key => $day) { + if ($day) { + $index = $days[$key]; + $selecteddays[] = $this->settingdata->choices[$index]; + } + } + + $this->visiblevalue = implode(', ', $selecteddays); + } +} + +/** OTHERS **/ +class admin_preset_admin_setting_special_calendar_weekend extends admin_preset_setting { + + protected function set_visiblevalue() { + + if (!$this->value) { + parent::set_visiblevalue(); + return; + } + + $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'); + for ($i = 0; $i < 7; $i++) { + if ($this->value & (1 << $i)) { + $settings[] = get_string($days[$i], 'calendar'); + } + } + + $this->visiblevalue = implode(', ', $settings); + } +} + +/** + * Backward compatibility for Moodle 2.0 + */ +class admin_preset_admin_setting_quiz_reviewoptions extends admin_preset_setting { + + // Caution VENOM! admin_setting_quiz_reviewoptions vars can't be accessed. + private static $times = array( + QUIZ_REVIEW_IMMEDIATELY => 'reviewimmediately', + QUIZ_REVIEW_OPEN => 'reviewopen', + QUIZ_REVIEW_CLOSED => 'reviewclosed'); + + private static $things = array( + QUIZ_REVIEW_RESPONSES => 'responses', + QUIZ_REVIEW_ANSWERS => 'answers', + QUIZ_REVIEW_FEEDBACK => 'feedback', + QUIZ_REVIEW_GENERALFEEDBACK => 'generalfeedback', + QUIZ_REVIEW_SCORES => 'scores', + QUIZ_REVIEW_OVERALLFEEDBACK => 'overallfeedback'); + + /** + * Stores the setting data and the selected value + * + * @param admin_setting $settingdata admin_setting subclass + * @param mixed $dbsettingvalue Actual value + */ + public function __construct(admin_setting $settingdata, $dbsettingvalue) { + $this->attributes = array('fix' => $settingdata->name . '_adv'); + parent::__construct($settingdata, $dbsettingvalue); + } + + /** + * Delegates + */ + protected function set_visiblevalue() { + + $marked = array(); + + foreach (self::$times as $timemask => $time) { + foreach (self::$things as $typemask => $type) { + if ($this->value & $timemask & $typemask) { + $marked[$time][] = get_string($type, "quiz"); + } + } + } + + foreach ($marked as $time => $types) { + $visiblevalues[] = '<strong>' . get_string($time, "quiz") . + ':</strong> ' . implode(', ', $types); + } + $this->visiblevalue = implode('<br/>', $visiblevalues); + + if ($this->attributesvalues[$this->attributes['fix']]) { + $string = get_string("markedasnonadvanced", "block_admin_presets"); + } else { + $string = get_string("markedasadvanced", "block_admin_presets"); + } + + $this->visiblevalue .= '<br/>' . ucfirst($string); + } +} + +/** + * Compatible with moodle 2.1 onwards (20120314) + */ +class admin_preset_mod_quiz_admin_review_setting extends admin_preset_setting { + + /** + * Overwrite to add the reviewoptions text + */ + public function set_text() { + + $this->set_visiblevalue(); + + $name = get_string('reviewoptionsheading', 'quiz') . + ': ' . $this->settingdata->visiblename; + $namediv = '<div class="admin_presets_tree_name">' . $name . '</div>'; + $valuediv = '<div class="admin_presets_tree_value">' . $this->visiblevalue . '</div>'; + + $this->text = $namediv . $valuediv . '<br/>'; + } + + /** + * The setting value is a sum of 'mod_quiz_admin_review_setting::times' + */ + protected function set_visiblevalue() { + + // Getting the masks descriptions (mod_quiz_admin_review_setting protected method). + $reflectiontimes = new ReflectionMethod('mod_quiz_admin_review_setting', 'times'); + $reflectiontimes->setAccessible(true); + $times = $reflectiontimes->invoke(null); + + $visiblevalue = ''; + foreach ($times as $timemask => $namestring) { + + // If the value is checked. + if ($this->value & $timemask) { + $visiblevalue .= $namestring . ', '; + } + } + $visiblevalue = rtrim($visiblevalue, ', '); + + $this->visiblevalue = $visiblevalue; + } +} + +/* We need to extend all those class */ + +class admin_preset_admin_setting_configtextarea extends admin_preset_admin_setting_configtext { +} + +class admin_preset_admin_setting_configfile extends admin_preset_admin_setting_configtext { +} + +class admin_preset_admin_setting_configexecutable extends admin_preset_admin_setting_configfile { +} + +class admin_preset_admin_setting_configdirectory extends admin_preset_admin_setting_configfile { +} + +class admin_preset_admin_setting_special_backup_auto_destination extends admin_preset_admin_setting_configdirectory { +} + +class admin_preset_admin_setting_configpasswordunmask extends admin_preset_admin_setting_configtext { +} + +class admin_preset_admin_setting_langlist extends admin_preset_admin_setting_configtext { +} + +class admin_preset_admin_setting_configcolourpicker extends admin_preset_admin_setting_configtext { +} + +class admin_preset_admin_setting_emoticons extends admin_preset_setting { +} + +class admin_preset_admin_setting_confightmleditor extends admin_preset_admin_setting_configtext { +} + +class admin_preset_admin_setting_configtext_trim_lower extends admin_preset_admin_setting_configtext { +} + +class admin_preset_admin_setting_special_gradepointmax extends admin_preset_admin_setting_configtext { +} + +class admin_preset_admin_setting_special_gradepointdefault extends admin_preset_admin_setting_configtext { +} + +class admin_preset_admin_setting_configempty extends admin_preset_admin_setting_configtext { +} + +class admin_preset_admin_setting_configtext_with_maxlength extends admin_preset_admin_setting_configtext { +} + +class admin_preset_editor_tinymce_json_setting_textarea extends admin_preset_admin_setting_configtext { +} + +/** + * I'm not overwriting set_visiblevalue() as there is a lot of logic to duplicate. + */ +class admin_preset_admin_setting_configduration extends admin_preset_admin_setting_configtext { +} + +class admin_preset_enrol_flatfile_role_setting extends admin_preset_admin_setting_configtext { +} + +/** + * I'm not overwriting set_visiblevalue() as there is a lot of logic to duplicate. + * + * @see admin_preset_admin_setting_configduration + */ +class admin_preset_admin_setting_configduration_with_advanced extends admin_preset_admin_setting_configtext_with_advanced { +} + +class admin_preset_admin_setting_special_frontpagedesc extends admin_preset_admin_setting_sitesettext { +} + +class admin_preset_admin_setting_special_selectsetup extends admin_preset_admin_setting_configselect { +} + +class admin_preset_admin_setting_sitesetselect extends admin_preset_admin_setting_configselect { +} + +class admin_preset_admin_setting_special_grademinmaxtouse extends admin_preset_admin_setting_configselect { +} + +class admin_preset_admin_setting_my_grades_report extends admin_preset_admin_setting_configselect { +} + +class admin_preset_admin_setting_servertimezone extends admin_preset_admin_setting_configselect { +} + +class admin_preset_admin_setting_forcetimezone extends admin_preset_admin_setting_configselect { +} + +class admin_preset_enrol_database_admin_setting_category extends admin_preset_admin_setting_configselect { +} + +class admin_preset_enrol_ldap_admin_setting_category extends admin_preset_admin_setting_configselect { +} + +class admin_preset_format_singleactivity_admin_setting_activitytype extends admin_preset_admin_setting_configselect { +} + +class admin_preset_admin_setting_courselist_frontpage extends admin_preset_admin_setting_configmultiselect_with_loader { +} + +class admin_preset_admin_setting_configmultiselect_modules extends admin_preset_admin_setting_configmultiselect_with_loader { +} + +class admin_preset_admin_settings_country_select extends admin_preset_admin_setting_configmultiselect_with_loader { +} + +class admin_preset_admin_setting_special_registerauth extends admin_preset_admin_setting_configmultiselect_with_loader { +} + +class admin_preset_admin_setting_special_debug extends admin_preset_admin_setting_configmultiselect_with_loader { +} + +class admin_preset_admin_settings_coursecat_select extends admin_preset_admin_setting_configmultiselect_with_loader { +} + +class admin_preset_admin_setting_grade_profilereport extends admin_preset_admin_setting_configmultiselect_with_loader { +} + +class admin_preset_admin_settings_num_course_sections extends admin_preset_admin_setting_configmultiselect_with_loader { +} + +class admin_preset_admin_setting_question_behaviour extends admin_preset_admin_setting_configmultiselect_with_loader { +} + +class admin_preset_admin_setting_sitesetcheckbox extends admin_preset_admin_setting_configcheckbox { +} + +class admin_preset_admin_setting_special_adminseesall extends admin_preset_admin_setting_configcheckbox { +} + +class admin_preset_admin_setting_regradingcheckbox extends admin_preset_admin_setting_configcheckbox { +} + +class admin_preset_admin_setting_special_gradelimiting extends admin_preset_admin_setting_configcheckbox { +} + +class admin_preset_admin_setting_enablemobileservice extends admin_preset_admin_setting_configcheckbox { +} + +class admin_preset_admin_setting_pickroles extends admin_preset_admin_setting_configmulticheckbox { +} + +class admin_preset_admin_setting_special_coursemanager extends admin_preset_admin_setting_configmulticheckbox { +} + +class admin_preset_admin_setting_special_coursecontact extends admin_preset_admin_setting_configmulticheckbox { +} + +class admin_preset_admin_setting_special_gradebookroles extends admin_preset_admin_setting_configmulticheckbox { +} + +class admin_preset_admin_setting_special_gradeexport extends admin_preset_admin_setting_configmulticheckbox { +} \ No newline at end of file diff --git a/blocks/admin_presets/module.js b/blocks/admin_presets/module.js new file mode 100644 index 0000000000000000000000000000000000000000..c41fcb4e2cb700cf3ec04ad85fed1729c4d7df7b --- /dev/null +++ b/blocks/admin_presets/module.js @@ -0,0 +1,115 @@ +M.block_admin_presets = { + + tree: null, + nodes: null, + + + /** + * Initializes the TreeView object and adds the submit listener + */ + init: function (Y) { + + Y.use('yui2-treeview', function (Y) { + + var context = M.block_admin_presets; + + context.tree = new Y.YUI2.widget.TreeView("settings_tree_div"); + + context.nodes = []; + context.nodes.root = context.tree.getRoot(); + }); + }, + + /** + * Creates a tree branch + */ + addNodes: function (Y, ids, nodeids, labels, descriptions, parents) { + + var context = M.block_admin_presets; + + var nelements = ids.length; + for (var i = 0; i < nelements; i++) { + + var settingId = ids[i]; + var nodeId = nodeids[i]; + var label = decodeURIComponent(labels[i]); + var description = decodeURIComponent(descriptions[i]); + var parent = parents[i]; + + var newNode = new Y.YUI2.widget.HTMLNode(label, context.nodes[parent]); + + newNode.settingId = settingId; + newNode.setNodesProperty('title', description); + newNode.highlightState = 1; + + context.nodes[nodeId] = newNode; + } + }, + + render: function (Y) { + + var context = M.block_admin_presets; + var categories = context.tree.getNodesByProperty('settingId', 'category'); + // Cleaning categories without children. + if (categories) { + for (var i = 0; i < categories.length; i++) { + if (!categories[i].hasChildren()) { + context.tree.popNode(categories[i]); + } + } + } + categories = context.tree.getRoot().children; + if (categories) { + for (var j = 0; j < categories.length; j++) { + if (!categories[j].hasChildren()) { + context.tree.popNode(categories[j]); + } + } + } + + // Context.tree.expandAll();. + context.tree.setNodesProperty('propagateHighlightUp', true); + context.tree.setNodesProperty('propagateHighlightDown', true); + context.tree.subscribe('clickEvent', context.tree.onEventToggleHighlight); + context.tree.render(); + + // Listener to create one node for each selected setting. + Y.YUI2.util.Event.on('id_admin_presets_submit', 'click', function () { + + // We need the moodle form to add the checked settings. + var settingsPresetsForm = document.getElementById('id_admin_presets_submit').parentNode; + + var hiLit = context.tree.getNodesByProperty('highlightState', 1); + if (Y.YUI2.lang.isNull(hiLit)) { + Y.YUI2.log("Nothing selected"); + + } else { + + // Only for debugging. + var labels = []; + + for (var i = 0; i < hiLit.length; i++) { + + var treeNode = hiLit[i]; + + // Only settings not setting categories nor settings pages. + if (treeNode.settingId !== 'category' && treeNode.settingId !== 'page') { + labels.push(treeNode.settingId); + + // If the node does not exists we add it. + if (!document.getElementById(treeNode.settingId)) { + + var settingInput = document.createElement('input'); + settingInput.setAttribute('type', 'hidden'); + settingInput.setAttribute('name', treeNode.settingId); + settingInput.setAttribute('value', '1'); + settingsPresetsForm.appendChild(settingInput); + } + } + } + + Y.YUI2.log("Checked settings:\n" + labels.join("\n"), "info"); + } + }); + } +}; diff --git a/blocks/admin_presets/pix/check0.gif b/blocks/admin_presets/pix/check0.gif new file mode 100644 index 0000000000000000000000000000000000000000..193028b99361c6527f17a9056037f3d8729fada7 Binary files /dev/null and b/blocks/admin_presets/pix/check0.gif differ diff --git a/blocks/admin_presets/pix/check1.gif b/blocks/admin_presets/pix/check1.gif new file mode 100644 index 0000000000000000000000000000000000000000..7d9ceba3847ffb41864626de755147cf2e0ccc41 Binary files /dev/null and b/blocks/admin_presets/pix/check1.gif differ diff --git a/blocks/admin_presets/pix/check2.gif b/blocks/admin_presets/pix/check2.gif new file mode 100644 index 0000000000000000000000000000000000000000..181317599bfd45f03a7a69784b232509171d98e9 Binary files /dev/null and b/blocks/admin_presets/pix/check2.gif differ diff --git a/blocks/admin_presets/settings.php b/blocks/admin_presets/settings.php new file mode 100644 index 0000000000000000000000000000000000000000..4a57c38f76bd83eb62bf9b59cb3bedef346eeb42 --- /dev/null +++ b/blocks/admin_presets/settings.php @@ -0,0 +1,40 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +if ($ADMIN->fulltree) { + + $sensiblesettingsdefault = 'recaptchapublickey@@none, recaptchaprivatekey@@none, googlemapkey@@none, '; + $sensiblesettingsdefault .= 'secretphrase@@none, cronremotepassword@@none, smtpuser@@none, '; + $sensiblesettingsdefault .= 'smtppass@none, proxypassword@@none, password@@quiz, '; + $sensiblesettingsdefault .= 'enrolpassword@@moodlecourse, allowedip@@none, blockedip@@none'; + + $settings->add(new admin_setting_configtextarea('admin_presets/sensiblesettings', + get_string('sensiblesettings', 'block_admin_presets'), + get_string('sensiblesettingstext', 'block_admin_presets'), + $sensiblesettingsdefault, PARAM_TEXT)); +} diff --git a/blocks/admin_presets/styles.css b/blocks/admin_presets/styles.css new file mode 100644 index 0000000000000000000000000000000000000000..6b86901e1fe3cc071e0dfc20710f1fdb197443be --- /dev/null +++ b/blocks/admin_presets/styles.css @@ -0,0 +1,44 @@ +.admin_presets_tree_name { + padding: 0 0 4px 2px; +} + +.admin_presets_tree_value { + border: 1px solid #ccc; + padding: 0 0 4px 2px; +} + +.admin_presets_error { + color: red; + text-align: center; +} + +.admin_presets_success { + color: green; + text-align: center; +} + +#page-blocks-admin_presets-index #settings_tree_div .catnode { + display: inline; + margin-left: 5px; +} + +#page-blocks-admin_presets-index #settings_tree_div .ygtv-checkbox .ygtv-highlight0 .ygtvcontent { + background: url([[pix:block_admin_presets|check0]]) no-repeat; + padding-left: 1em; +} + +#page-blocks-admin_presets-index #settings_tree_div .ygtv-checkbox .ygtv-highlight0 .ygtvfocus.ygtvcontent, +.ygtv-checkbox .ygtv-highlight1 .ygtvfocus.ygtvcontent, +.ygtv-checkbox .ygtv-highlight2 .ygtvfocus.ygtvcontent { + background-color: #c0e0e0; +} + +#page-blocks-admin_presets-index #settings_tree_div .ygtv-checkbox .ygtv-highlight1 .ygtvcontent { + background: url([[pix:block_admin_presets|check1]]) no-repeat; + padding-left: 1em; +} + +#page-blocks-admin_presets-index #settings_tree_div .ygtv-checkbox .ygtv-highlight2 .ygtvcontent { + background: url([[pix:block_admin_presets|check2]]) no-repeat; + padding-left: 1em; +} diff --git a/blocks/admin_presets/tabs.php b/blocks/admin_presets/tabs.php new file mode 100644 index 0000000000000000000000000000000000000000..a68783da24d64aa2ea1bdd16d8095bfc32ce4c5b --- /dev/null +++ b/blocks/admin_presets/tabs.php @@ -0,0 +1,45 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$adminpresetsurl = $CFG->wwwroot . '/blocks/admin_presets/index.php'; + +$adminpresetstabs = array('base' => 'base', + 'export' => 'export', + 'import' => 'import'); + +if (!array_key_exists($this->action, $adminpresetstabs)) { + $row[] = new tabobject($this->action, $adminpresetsurl . + '?action=' . $this->action, get_string('action' . $this->action, 'block_admin_presets')); +} + +foreach ($adminpresetstabs as $actionname) { + $row[] = new tabobject($actionname, $adminpresetsurl . + '?action=' . $actionname, get_string('action' . $actionname, 'block_admin_presets')); +} + +print_tabs(array($row), $this->action); diff --git a/blocks/admin_presets/tests/behat/import_settings.feature b/blocks/admin_presets/tests/behat/import_settings.feature new file mode 100644 index 0000000000000000000000000000000000000000..425b1d733a2b6170307f74348efceb999eecb59d --- /dev/null +++ b/blocks/admin_presets/tests/behat/import_settings.feature @@ -0,0 +1,56 @@ +@block @block_admin_presets +Feature: I can export and import site settings + In order to save time + As an admin + I need to export and import settings presets + + Background: + Given I log in as "admin" + And I am on site homepage + And I follow "Turn editing on" + And I add the "Admin presets" block + And I follow "Export settings" + And I set the following fields to these values: + | Name | My preset | + And I press "Save changes" + + @javascript + Scenario: Preset settings are applied + Given I follow "Advanced features" + And I set the field "Enable portfolios" to "1" + And I set the field "Enable badges" to "0" + And I press "Save changes" + And I navigate to "Assignment settings" node in "Site administration > Plugins > Activity modules > Assignment" + And I set the field "Feedback plugin" to "File feedback" + And I press "Save changes" + And I navigate to "Course overview" node in "Site administration > Plugins > Blocks" + And I set the field "Default maximum courses" to "5" + And I press "Save changes" + When I am on site homepage + And I follow "Presets" + And I click on "load" "link" in the "My preset" "table_row" + And I press "Load selected settings" + Then I should not see "All preset settings skipped, they are already loaded" + And I should see "Settings applied" + And I should see "Enable portfolios" in the ".admin_presets_applied" "css_element" + And I should see "Enable badges" in the ".admin_presets_applied" "css_element" + And I should see "Feedback plugin" in the ".admin_presets_applied" "css_element" + And I should see "File feedback" in the ".admin_presets_applied" "css_element" + And I should see "Default maximum courses" in the ".admin_presets_applied" "css_element" + And I should see "Enable outcomes" in the ".admin_presets_skipped" "css_element" + And I should see "Show recent submissions" in the ".admin_presets_skipped" "css_element" + And I should see "Force maximum courses" in the ".admin_presets_skipped" "css_element" + And I follow "Advanced features" + And the field "Enable portfolios" matches value "0" + And the field "Enable badges" matches value "1" + And I navigate to "Assignment settings" node in "Site administration > Plugins > Activity modules > Assignment" + And the field "Feedback plugin" matches value "Feedback comments" + And I navigate to "Course overview" node in "Site administration > Plugins > Blocks" + And the field "Default maximum courses" matches value "10" + + @javascript + Scenario: Settings don't change if you import what you just exported + When I click on "load" "link" in the "My preset" "table_row" + And I press "Load selected settings" + Then I should see "All preset settings skipped, they are already loaded" + And I should not see "Settings applied" \ No newline at end of file diff --git a/blocks/admin_presets/tests/behat/revert_changes.feature b/blocks/admin_presets/tests/behat/revert_changes.feature new file mode 100644 index 0000000000000000000000000000000000000000..9f5d9ca1221ab5cfdbf3dfbb2ecb682677e33308 --- /dev/null +++ b/blocks/admin_presets/tests/behat/revert_changes.feature @@ -0,0 +1,46 @@ +@block @block_admin_presets +Feature: I can revert changes + In order to save time + As an admin + I need to export and import settings presets + + @javascript + Scenario: Load changes and revert them + Given I log in as "admin" + And I am on site homepage + And I follow "Turn editing on" + And I add the "Admin presets" block + And I follow "Export settings" + And I set the following fields to these values: + | Name | My preset | + And I press "Save changes" + And I follow "Advanced features" + And I set the field "Enable portfolios" to "1" + And I set the field "Enable badges" to "0" + And I press "Save changes" + And I navigate to "Assignment settings" node in "Site administration > Plugins > Activity modules > Assignment" + And I set the field "Feedback plugin" to "File feedback" + And I press "Save changes" + And I navigate to "Course overview" node in "Site administration > Plugins > Blocks" + And I set the field "Default maximum courses" to "5" + And I press "Save changes" + And I am on site homepage + And I follow "Presets" + And I click on "load" "link" in the "My preset" "table_row" + And I press "Load selected settings" + And I am on site homepage + When I follow "Presets" + And I click on "revert" "link" in the "My preset" "table_row" + And I follow "revert" + Then I should see "Settings successfully restored" + And I should see "Enable portfolios" in the ".admin_presets_applied" "css_element" + And I should see "Enable badges" in the ".admin_presets_applied" "css_element" + And I should see "Feedback plugin" in the ".admin_presets_applied" "css_element" + And I should see "File feedback" in the ".admin_presets_applied" "css_element" + And I follow "Advanced features" + And the field "Enable portfolios" matches value "1" + And the field "Enable badges" matches value "0" + And I navigate to "Assignment settings" node in "Site administration > Plugins > Activity modules > Assignment" + And the field "Feedback plugin" matches value "File feedback" + And I navigate to "Course overview" node in "Site administration > Plugins > Blocks" + And the field "Default maximum courses" matches value "5" \ No newline at end of file diff --git a/blocks/admin_presets/version.php b/blocks/admin_presets/version.php new file mode 100644 index 0000000000000000000000000000000000000000..7520cae0f93fa9be35137aea9bf292156d64fc8a --- /dev/null +++ b/blocks/admin_presets/version.php @@ -0,0 +1,34 @@ +<?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/>. + +/** + * Admin presets block main controller + * + * @package blocks/admin_presets + * @copyright 2019 Pimenko <support@pimenko.com><pimenko.com> + * @author Jordan Kesraoui | DigiDago + * @orignalauthor David Monllaó <david.monllao@urv.cat> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$plugin->version = 2020062417; +$plugin->requires = 2016052300; // Requires this Moodle version +$plugin->component = 'block_admin_presets'; +$plugin->release = '3.2'; +$plugin->cron = 0; +$plugin->maturity = MATURITY_STABLE; diff --git a/blocks/attendance/.travis.yml b/blocks/attendance/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..3e9e4fe1a7c4199d2f187307d9ae63107ba72f3e --- /dev/null +++ b/blocks/attendance/.travis.yml @@ -0,0 +1,52 @@ +language: php + +addons: + postgresql: "9.5" + +services: + - mysql + - postgresql + - docker + +cache: + directories: + - $HOME/.composer/cache + - $HOME/.npm + +php: + - 7.2 + - 7.4 + +env: + global: + - MOODLE_BRANCH=master + - MUSTACHE_IGNORE_NAMES=mobile_teacher_form.mustache + matrix: + - DB=pgsql + - DB=mysqli + +before_install: + - phpenv config-rm xdebug.ini + - nvm install 14.0.0 + - nvm use 14.0.0 + - cd ../.. + - composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci dev-master + - export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH" + +install: + - moodle-plugin-ci add-plugin --branch main danmarsden/moodle-mod_attendance + - moodle-plugin-ci install + - docker run -d -p 127.0.0.1:4444:4444 --net=host --shm-size=2g -v $HOME/build/moodle:$HOME/build/moodle selenium/standalone-chrome:3 + +script: + - moodle-plugin-ci phplint + - moodle-plugin-ci phpcpd + - moodle-plugin-ci phpmd + - moodle-plugin-ci codechecker + - moodle-plugin-ci validate + - moodle-plugin-ci savepoints + - moodle-plugin-ci mustache + - moodle-plugin-ci grunt + - moodle-plugin-ci phpdoc + - moodle-plugin-ci phpunit + - moodle-plugin-ci behat --profile chrome diff --git a/blocks/attendance/README.md b/blocks/attendance/README.md new file mode 100644 index 0000000000000000000000000000000000000000..dab05bd03d5d0d5e6091ff8338c1444a5b600cf7 --- /dev/null +++ b/blocks/attendance/README.md @@ -0,0 +1,12 @@ +#Moodle Attendance Block [](https://travis-ci.org/danmarsden/moodle-block_attendance) + +The Attendance block supplements the Attendance activity and is supported and maintained by Dan Marsden http://danmarsden.com + +The Attendance block was previously developed by +* Human Logic Development Team, www.human-logic.com +* Dmitry Pupinin, Novosibirsk, Russia, + +#PURPOSE +The Attendance activity allows teachers to maintain a record of attendance, replacing or supplementing a paper-based attendance register. + +This block provides quick links to features such as reporting, taking of attendance and adding new sessions. diff --git a/blocks/attendance/block_attendance.php b/blocks/attendance/block_attendance.php new file mode 100644 index 0000000000000000000000000000000000000000..9c4f4823b407739bd8ba6f7581fe3e0a803e3082 --- /dev/null +++ b/blocks/attendance/block_attendance.php @@ -0,0 +1,160 @@ +<?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/>. + +/** + * Attendance Block + * + * @package block_attendance + * @copyright 2011 Artem Andreev <andreev.artem@gmail.com> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * Displays information about Attendance Module in this course. + * + * @copyright 2011 Artem Andreev <andreev.artem@gmail.com> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class block_attendance extends block_base { + + /** + * Set the initial properties for the block + */ + public function init() { + $this->title = get_string('blockname', 'block_attendance'); + } + + /** + * Gets the content for this block + * + * @return object $this->content + */ + public function get_content() { + global $CFG, $USER, $COURSE; + + if ($this->content !== null) { + return $this->content; + } + + $this->content = new stdClass; + $this->content->footer = ''; + $this->content->text = ''; + + $attendances = get_all_instances_in_course('attendance', $COURSE, null, true); + if (count($attendances) == 0) { + $this->content->text = get_string('needactivity', 'block_attendance');; + return $this->content; + } + + require_once($CFG->dirroot.'/mod/attendance/locallib.php'); + require_once($CFG->dirroot.'/mod/attendance/renderhelpers.php'); + + foreach ($attendances as $attinst) { + $cmid = $attinst->coursemodule; + $cm = get_coursemodule_from_id('attendance', $cmid, $COURSE->id, false, MUST_EXIST); + if (!empty($cm->deletioninprogress)) { + // Don't display if this attendance is in recycle bin. + continue; + } + $context = context_module::instance($cmid, MUST_EXIST); + $divided = $this->divide_databasetable_and_coursemodule_data($attinst); + + $att = new mod_attendance_structure($divided->atttable, $divided->cm, $COURSE, $context); + + $this->content->text .= html_writer::link($att->url_view(), html_writer::tag('b', format_string($att->name))); + $this->content->text .= html_writer::empty_tag('br'); + + // Link to attendance. + + if (has_capability('mod/attendance:takeattendances', $context) or + has_capability('mod/attendance:changeattendances', $context)) { + $this->content->text .= html_writer::link($att->url_manage(array('from' => 'block')), + get_string('takeattendance', 'attendance')); + $this->content->text .= html_writer::empty_tag('br'); + } + if (has_capability('mod/attendance:manageattendances', $context)) { + $url = $att->url_sessions(array('action' => mod_attendance_sessions_page_params::ACTION_ADD)); + $this->content->text .= html_writer::link($url, get_string('add', 'attendance')); + $this->content->text .= html_writer::empty_tag('br'); + } + if (has_capability('mod/attendance:viewreports', $context)) { + $this->content->text .= html_writer::link($att->url_report(), get_string('report', 'attendance')); + $this->content->text .= html_writer::empty_tag('br'); + } + + if (has_capability('mod/attendance:canbelisted', $context, null, false) && + has_capability('mod/attendance:view', $context)) { + $this->content->text .= construct_full_user_stat_html_table($attinst, $USER); + } + $this->content->text .= "<br />"; + } + + $categorycontext = context_coursecat::instance($COURSE->category); + if (has_capability('mod/attendance:viewsummaryreports', $categorycontext)) { + $url = new moodle_url('/mod/attendance/coursesummary.php', + array('category' => $COURSE->category, 'fromcourse' => $COURSE->id)); + $this->content->text .= html_writer::link($url, get_string('categoryreport', 'attendance')); + $this->content->text .= html_writer::empty_tag('br'); + } + + return $this->content; + } + + /** + * parses data to pass into construct. + * @param object $alldata + * @return array + */ + private function divide_databasetable_and_coursemodule_data($alldata) { + static $cmfields; + + if (!isset($cmfields)) { + $cmfields = array( + 'coursemodule' => 'id', + 'section' => 'section', + 'visible' => 'visible', + 'groupmode' => 'groupmode', + 'groupingid' => 'groupingid', + 'groupmembersonly' => 'groupmembersonly'); + } + + $atttable = new stdClass(); + $cm = new stdClass(); + foreach ($alldata as $field => $value) { + if (array_key_exists($field, $cmfields)) { + $cm->{$cmfields[$field]} = $value; + } else { + $atttable->{$field} = $value; + } + } + + $ret = new stdClass(); + $ret->atttable = $atttable; + $ret->cm = $cm; + + return $ret; + } + + /** + * Set the applicable formats for this block + * @return array + */ + public function applicable_formats() { + return array('all' => true, 'my' => false, 'admin' => false, 'tag' => false); + } +} diff --git a/blocks/attendance/classes/privacy/provider.php b/blocks/attendance/classes/privacy/provider.php new file mode 100644 index 0000000000000000000000000000000000000000..2f02482bf4f55a1d180d9ccb41d9dbdddd220d0a --- /dev/null +++ b/blocks/attendance/classes/privacy/provider.php @@ -0,0 +1,46 @@ +<?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/>. + +/** + * Privacy Subsystem implementation for block_attendance. + * + * @package block_attendance + * @copyright 2018 Dan Marsden <dan@danmarsden.com> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace block_attendance\privacy; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Privacy Subsystem for block_attendance implementing null_provider. + * + * @copyright 2018 Dan Marsden <dan@danmarsden.com> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements \core_privacy\local\metadata\null_provider { + + /** + * Get the language string identifier with the component's language + * file to explain why this plugin stores no data. + * + * @return string + */ + public static function get_reason() : string { + return 'privacy:metadata'; + } +} diff --git a/blocks/attendance/composer.json b/blocks/attendance/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..3ce5c92252c87a8165b2a1fc12fd4a46da2f90af --- /dev/null +++ b/blocks/attendance/composer.json @@ -0,0 +1,10 @@ +{ + "name": "danmarsden/moodle-block_attendance", + "type": "moodle-block", + "require": { + "composer/installers": "~1.0" + }, + "extra": { + "installer-name": "attendance" + } +} diff --git a/blocks/attendance/db/access.php b/blocks/attendance/db/access.php new file mode 100644 index 0000000000000000000000000000000000000000..54d860b7fdb284258c0c2e551422d68bec6c31b9 --- /dev/null +++ b/blocks/attendance/db/access.php @@ -0,0 +1,38 @@ +<?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/>. + +/** + * Attendance block caps. + * + * @package block_attendance + * @copyright 2011 Artem Andreev <andreev.artem@gmail.com> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$capabilities = array( + 'block/attendance:addinstance' => array( + 'riskbitmask' => RISK_XSS, + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW + ), + 'clonepermissionsfrom' => 'moodle/course:manageactivities' + ), +); diff --git a/blocks/attendance/lang/en/block_attendance.php b/blocks/attendance/lang/en/block_attendance.php new file mode 100644 index 0000000000000000000000000000000000000000..fe5c6f93c1dc5ee4f80524e00de54e4cc55359ac --- /dev/null +++ b/blocks/attendance/lang/en/block_attendance.php @@ -0,0 +1,29 @@ +<?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/>. + +/** + * Language file for block "attendance" + * + * @package block_attendance + * @copyright 2011 Artem Andreev <andreev.artem@gmail.com> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['attendance:addinstance'] = 'Add a new attendance block'; +$string['blockname'] = 'Attendance'; +$string['needactivity'] = 'This block can work only with an attendance activity. Please add the activity to this course.'; +$string['pluginname'] = 'Attendance'; +$string['privacy:metadata'] = 'The Attendance block only displays existing attendance data.'; \ No newline at end of file diff --git a/blocks/attendance/tests/behat/attendance_block.feature b/blocks/attendance/tests/behat/attendance_block.feature new file mode 100644 index 0000000000000000000000000000000000000000..4b8cdc5173b19a305374b88897f4a6969dccb47c --- /dev/null +++ b/blocks/attendance/tests/behat/attendance_block.feature @@ -0,0 +1,32 @@ +@block @block_attendance @javascript +Feature: Test that teachers can add the attendance block and students can view reports. + Background: + Given the following "courses" exist: + | fullname | shortname | + | Course 1 | C1 | + And the following "users" exist: + | username | firstname | lastname | email | + | teacher1 | Teacher | 1 | teacher1@example.com | + | student1 | Student | 1 | student1@example.com | + And the following "course enrolments" exist: + | course | user | role | + | C1 | teacher1 | editingteacher | + | C1 | student1 | student | + And the following "activities" exist: + | activity | name | intro | course | idnumber | + | attendance | AttendanceTest1 | attendance description | C1 | attendance1 | + + Scenario: Teachers can add the attendance block + When I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on + And I add the "Attendance" block + Then I should see "Take attendance" + + Scenario: Students can view their reports. + When I log in as "teacher1" + And I am on "Course 1" course homepage with editing mode on + And I add the "Attendance" block + And I log out + And I log in as "student1" + And I am on "Course 1" course homepage + Then I should see "Taken sessions" diff --git a/blocks/attendance/version.php b/blocks/attendance/version.php new file mode 100644 index 0000000000000000000000000000000000000000..052ec3007d5506307579b7f968689f0633b191af --- /dev/null +++ b/blocks/attendance/version.php @@ -0,0 +1,32 @@ +<?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_attendance + * @copyright 2011 Artem Andreev <andreev.artem@gmail.com> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$plugin->version = 2018052100; +$plugin->requires = 2017111300; // Requires 3.4. +$plugin->component = 'block_attendance'; +$plugin->dependencies = array('mod_attendance' => 2017050208); +$plugin->maturity = MATURITY_STABLE; +$plugin->release = '3.2.4'; diff --git a/blocks/course_overview_campus/.travis.yml b/blocks/course_overview_campus/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..64e1b3bafe1f0dad4efca6f6952ebd50e20c6b22 --- /dev/null +++ b/blocks/course_overview_campus/.travis.yml @@ -0,0 +1,54 @@ +language: php + +sudo: true + +services: + - mysql + +addons: + firefox: "47.0.1" + postgresql: "9.4" + apt: + packages: + - openjdk-8-jre-headless + +cache: + directories: + - $HOME/.composer/cache + - $HOME/.npm + +php: + - 7.1 + - 7.2 + - 7.3 + +env: + global: + - MOODLE_BRANCH=MOODLE_37_STABLE + matrix: + - DB=pgsql + - DB=mysqli + +before_install: + - phpenv config-rm xdebug.ini + - nvm install 8.9 + - nvm use 8.9 + - cd ../.. + - composer create-project -n --no-dev --prefer-dist blackboard-open-source/moodle-plugin-ci ci ^2 + - export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH" + +install: + - moodle-plugin-ci install + +script: + - moodle-plugin-ci phplint + - moodle-plugin-ci phpcpd || true # Output warnings but do not fail the build because of working legacy code + - moodle-plugin-ci phpmd + - moodle-plugin-ci codechecker + - moodle-plugin-ci validate + - moodle-plugin-ci savepoints + - moodle-plugin-ci mustache + - moodle-plugin-ci grunt + - moodle-plugin-ci phpdoc + - moodle-plugin-ci phpunit + - moodle-plugin-ci behat --dump diff --git a/blocks/course_overview_campus/CHANGES.md b/blocks/course_overview_campus/CHANGES.md new file mode 100644 index 0000000000000000000000000000000000000000..9cc55d9fdcd93c0cb220deecf8bbd8818154c2d8 --- /dev/null +++ b/blocks/course_overview_campus/CHANGES.md @@ -0,0 +1,149 @@ +moodle-block_course_overview_campus +=================================== + +Changes +------- + +### v3.7-r1 + +* 2019-06-12 - Remove course news functionality as it does not work anymore from Moodle 3.7 on. +* 2019-06-12 - Prepare compatibility for Moodle 3.7. + +### v3.6-r1 + +* 2019-03-28 - Remove user preferences when being uninstalled. +* 2019-03-28 - Prepare the plugin that the hooks for fetching the course news will be removed in Moodle 3.7. If installed on Moodle 3.7, this plugin will silently disable the course news feature even if it is enabled in the plugin settings. +* 2019-03-28 - Check compatibility for Moodle 3.6, no functionality change. +* 2018-12-05 - Changed travis.yml due to upstream changes. + +### v3.5-r2 + +* 2018-08-26 - Bugfix: There might be a debug message when prioritizemyteachedcourses setting is enabled. + +### v3.5-r1 + +* 2018-07-02 - Fix some visual flaws and changes which came with BS 4 stable. +* 2018-05-29 - Check compatibility for Moodle 3.5, no functionality change. + +### v3.4-r2 + +* 2018-05-16 - Implement Privacy API. + +### v3.4-r1 + +* 2018-03-30 - Check compatibility for Moodle 3.4, no functionality change. + +### v3.3-r1 + +* 2018-03-07 - Add a nice slide animation when hiding a course. +* 2018-03-06 - Add a note about the future of the course news feature to README. +* 2018-03-06 - Bugfix: Add a default title string to this plugin instead of fetching it from block_course_overview which is EOL. +* 2018-03-06 - Activity icons should be rendered with image_icon() and not with pix_icon anymore. +* 2018-03-06 - pix_url() is deprecated in Moodle 3.3, change to pix_icon() and fontawesome icons. +* 2017-12-12 - Prepare compatibility for Moodle 3.3, no functionality change. + +### v3.2-r6 + +* 2017-06-16 - Bugfix: Prevent debug notice when there are no modules supporting the print_overview() function +* 2017-05-29 - Add Travis CI support + +### v3.2-r5 + +* 2017-05-05 - Improve README.md + +### v3.2-r4 + +* 2017-03-29 - Tighten parameter filtering for user preferences saved by block_course_overview_campus +* 2017-03-16 - Bugfix: Eliminate debug message about duplicate teacher role entries - Credits to Davo Smith +* 2017-03-10 - Don't show course news when hidden courses management is active +* 2017-03-10 - Bugfix: The hidden courses management box was partly broken after the styling changes in v3.2-r3 +* 2017-03-10 - Bugfix: The fallback for browsers with JavaScript disabled was broken after the styling changes in v3.2-r3 +* 2017-03-10 - Restructure code in several areas, especially to support our companion plugin local_boostcoc; No functionality change + +### v3.2-r3 + +* 2017-03-04 - Change the styling of the block even more to Bootstrap 4 + +### v3.2-r2 + +* 2017-01-27 - Bugfix: Set filter correctly after using the browser's back functionality - Credits to Davo Smith + +### v3.2-r1 + +* 2017-01-17 - Bugfix: Top level category filter did not show lower-level courses on first page load +* 2017-01-16 - Adapt course list appearance to Bootstrap 4 (used by theme_boost) +* 2017-01-16 - Check compatibility for Moodle 3.2, no functionality change +* 2017-01-16 - Convert YUI to jQuery + AMD - Credits to Davo Smith +* 2017-01-12 - Move Changelog from README.md to CHANGES.md + +### v3.1-r2 + +* 2016-11-07 - Remove a debug message about missing name fields in the DB query if teacher names are configured to be displayed according to the fullnamedisplay setting + +### v3.1-r1 + +* 2016-07-19 - Check compatibility for Moodle 3.1, no functionality change + +### Changes before v3.1 + +* 2016-06-14 - New Feature: Hide suspended teachers +* 2016-04-05 - Split the existing long settings page into multiple settings pages +* 2016-04-01 - Add feature to show top level category name in second row; rename existing feature to show parent category name +* 2016-04-01 - Add filter for top level category; rename existing category filter to parent category filter +* 2016-03-02 - Fix missing data in second row when corresponding filters are not activated; Credits to Dimitri Vorona +* 2016-02-10 - Change plugin version and release scheme to the scheme promoted by moodle.org, no functionality change +* 2016-01-01 - Add support for Shifter in YUI files, fix several JSLint errors +* 2016-01-01 - Check compatibility for Moodle 3.0, no functionality change +* 2015-09-29 - Output introduction string in course news like it's done in block_course_overview +* 2015-08-21 - Change My Moodle to Dashboard in language pack +* 2015-08-18 - Check compatibility for Moodle 2.9, no functionality change +* 2015-03-21 - Bugfix: Block couldn't be placed on MyMoodle in some circumstances +* 2015-03-20 - New Feature: Add a setting to control if the block should, when looking for teachers with the specified teacher roles, include teachers who have their role assigned in parent contexts (course category or system level) +* 2015-02-22 - Bugfix: Teacher filter showed teachers twice or even multiple times, Thanks to Mario Wehr +* 2015-02-22 - Bugfix: Term filter might have listed terms twice; Thanks to Michael Veit +* 2015-01-29 - Check compatibility for Moodle 2.8, no functionality change +* 2014-10-20 - Bugfix: There were problems with the term filter and courses which start on the term start day and / or term starting on january 1st +* 2014-10-20 - Add multilanguage support to noteachertext string +* 2014-08-29 - Update README file +* 2014-08-22 - Added setting to hide second row in course list on mobile phones to save space +* 2014-08-22 - Bootstrapbase makes h3 headings uppercase, this is not desired for this block and was overwritten in styles_bootstrapbase.css +* 2014-08-22 - Changed HTML code to leverage Bootstrap based themes, Drop support for Non-Bootstrap based themes +* 2014-08-22 - Changed HTML code for hide course management box - please check your theme, if you have styled the block in a custom way +* 2014-08-19 - Added setting to disable hiding of courses completely +* 2014-08-19 - Added setting to control the styling of the teacher's name in the second row +* 2014-06-30 - Check compatibility for Moodle 2.7, no functionality change +* 2014-02-18 - Bugfix: Second row didn't show the configured string for "timeless courses"; Credits to Sebastian Becker +* 2014-01-31 - Improve width of filters if less than all three filters are enabled +* 2014-01-31 - Added setting to skip activities when collecting and displaying course news +* 2014-01-31 - Added setting to disable course news completely and to hide course news by default +* 2014-01-31 - Added setting to define a placeholder text for course list entries if the block is configures to display teacher names but no teacher is enrolled in the course +* 2014-01-31 - Bugfix: Second row in course list was empty if the block was configured to show only teacher names in second row +* 2014-01-31 - Check compatibility for Moodle 2.6, no functionality change +* 2013-10-29 - Bugfix: block_course_overview_campus variable names interfered with other plugin's variables +* 2013-09-04 - Bugfix: Long course lists were incomplete. Sorry for the inconvenience! +* 2013-09-03 - Added ability to fine-tune the course name and meta info which will be displayed in the course overview list entries. Please revise your settings after updating the plugin +* 2013-09-03 - Added ability to fine-tune the term names which will be displayed in the term filter dropdown. Please revise your settings after updating the plugin, especially if you are running the term filter in Academic year mode +* 2013-07-30 - Transfer Github repository from github.com/abias/... to github.com/moodleuulm/...; Please update your Git paths if necessary +* 2013-07-30 - Check compatibility for Moodle 2.5, no functionality change +* 2013-06-18 - Bugfix: Fix problem with new ability to prioritize courses in which I teach. Sorry for the inconvenience +* 2013-06-18 - Re-sorted block settings page +* 2013-06-18 - Added ability to prioritize courses in which I teach in the course overview list +* 2013-06-18 - Added ability to merge homonymous categories into one category when using the category filter +* 2013-06-18 - Added ability to set the title of the block instead of using title from block_course_overview +* 2013-06-18 - Added ability to define teacher roles in block settings instead of relying on Moodle core coursecontact setting +* 2013-06-18 - Bugfix: When show teacher names setting was enabled, but teacher filter was diabled, the teacher name's list was not populated correctly +* 2013-06-12 - When managing hidden courses, now all courses are shown regardless if of the user's filter settings +* 2013-06-12 - Bugfix: Setting page should check if the configured term dates make sense and show a warning information if not. This check didn't work up to now +* 2013-04-23 - Add support for timeless courses +* 2013-03-18 - Code cleanup according to moodle codechecker +* 2013-03-06 - Bugfix: Block failed to work when wwwroot contained a subdirectory, kudos to Michael Wuttke +* 2013-03-05 - Small code change, now PHP doesn't need to be compiled with --enable-calendar option, kudos to Carsten Biemann +* 2013-02-22 - German language has been integrated into AMOS and was removed from this plugin. Please update your language packs with http://YOURMOODLEURL/admin/tool/langimport/index.php after installing this plugin version +* 2013-02-18 - Check compatibility for Moodle 2.4, add module icons to course news, fix language string names to comply with language string name convention +* 2013-01-18 - Bugfix: Block didn't read configuration from config_plugins database table properly +* 2012-12-21 - Block now uses config_plugins database table instead of config table. You will have to set all block settings again, sorry about that! +* 2012-12-21 - Small CSS improvement +* 2012-12-18 - Code cleanup +* 2012-12-18 - New feature: Short teachers' names in course list +* 2012-12-18 - New feature: Support multilang strings in term names and filter display names +* 2012-12-17 - Initial version diff --git a/blocks/course_overview_campus/COPYING.txt b/blocks/course_overview_campus/COPYING.txt new file mode 100644 index 0000000000000000000000000000000000000000..94a9ed024d3859793618152ea559a168bbcbb5e2 --- /dev/null +++ b/blocks/course_overview_campus/COPYING.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program 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. + + This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/blocks/course_overview_campus/README.md b/blocks/course_overview_campus/README.md new file mode 100644 index 0000000000000000000000000000000000000000..2d7b2c2706ae494a312a21de1194ddb5afcaf474 --- /dev/null +++ b/blocks/course_overview_campus/README.md @@ -0,0 +1,217 @@ +moodle-block_course_overview_campus +=================================== + +[](https://travis-ci.org/moodleuulm/moodle-block_course_overview_campus) + +Moodle block which provides all functionality of block_course_overview, provides additional filters to be used on university campuses as well as the possibility to hide courses from the course list + + +Requirements +------------ + +This plugin requires Moodle 3.7+ + + +Motivation for this plugin +-------------------------- + +Moodle installations on university campuses have certain constraints which are not completely supported by Moodle core and the course overview block in Moodle core. We implemented this course overview block to accommodate these needs as much as possible while keeping the features from the original course overview block from Moodle core as much as possible as well. + + +Installation +------------ + +Install the plugin like any other plugin to folder +/blocks/course_overview_campus + +See http://docs.moodle.org/en/Installing_plugins for details on installing Moodle plugins + + +Usage & Settings +---------------- + +After installing the plugin, it can be directly used by users and can be added to the Moodle dashboard and to the Moodle frontpage. + +Initially, it behaves like block_course_overview from moodle core. Additionally, courses can be hidden from the course list. + +To make use of the advanced features of the block, please visit: +Site administration -> Plugins -> Blocks -> Course overview on campus + +There, you find multiple settings pages: + +### 1. General + +On this settings page, you can change the block's title which is shown in the block view (multilang strings are supported, see http://docs.moodle.org/en/Multi-language_content_filter for details). + +### 2. Course overview list + +On this settings page, you can change the appearance of the course overview list, especially if the course's full name or short name should be displayed in the course overview list entries. Additionally, you can enable and style the displaying of some meta data in a second row of the course overview list entry and you can define if courses in which the user has a teacher role are listed first in the course overview list. + +### 3. Hide courses + +On this settings page, you can enable (default) or disable the system for hiding courses from the course overview list. + +### 4. Teacher roles + +On this settings page, you can define which roles in a course will be displayed besides the course's name as teacher and get listed in the teacher filter. + +### 5. Parent category filter + +On this settings page, you can activate and configure a filter which enables your users to filter their courses by parent category. As soon as the filter is activated and the setting is saved, the filter appears in the block view. + +### 6. Top level category filter + +On this settings page, you can activate and configure a filter which enables your users to filter their courses by top level category. As soon as the filter is activated and the setting is saved, the filter appears in the block view. + +### 7. Teacher filter + +On this settings page, you can activate and configure a filter which enables your users to filter their courses by teacher. As soon as the filter is activated and the setting is saved, the filter appears in the block view. + +### 8. Term filter + +On this settings page, you can activate and configure a filter which enables your users to filter their courses by term. As soon as the filter is activated and the setting is saved, the filter appears in the block view. + + +Data sources +------------ + +### 1. Parent category filter + +The parent category filter is filled with the main category of each of the user's courses. + +Example: +If the course's category path is Category A -> Category B -> Category C -> Course, the filter will contain an entry with Category C. + + +### 2. Top level category filter + +The top level filter is filled with the top level category of each of the user's courses. + +Example: +If the course's category path is Category A -> Category B -> Category C -> Course, the filter will contain an entry with Category A. + +### 3. Teacher filter + +As described in the "Usage & Settings" section of this file, you should configure the teacher roles for block_course_overview_campus according to your campus needs. After that, block_course_overview_campus takes each course member with one of the configured roles. These teachers are filled into the teacher filter. + +### 4. Term filter + +As described in the "Usage & Settings" section of this file, you should configure block_course_overview_campus according to your campus course of the year. After that, block_course_overview_campus maps each course to a term by looking at the course's start date. This term is filled into the term filter. + + +Block placement +--------------- + +block_course_overview_campus is used ideally as sticky block and placed on your frontpage (and / or Dashboard page). + +See http://docs.moodle.org/en/Block_settings#Making_a_block_sticky_throughout_the_whole_site for details about sticky blocks + + +Disregarded Moodle Features +--------------------------- + +During the development of Moodle, there have been added several features added to the moodle core block_course_overview and moodle core which would conflict with block_course_overview_campus functionality. It has been decided to disregard the following Moodle features for this block: + +* In block_course_overview in Moodle 2.4+, a user is able to sort his course list by drag and drop. We decided to not adopt this feature for block_course_overview_campus because we think this would conflict with the filtering / hiding feature and confuse users. In block_course_overview_campus, the course list remains sorted by full course name. +* In block_course_overview in Moodle 2.4+, a user is able to limit the length of his course list with a block setting. We decided to not adopt this feature for block_course_overview_campus because we think this would conflict with the filtering / hiding feature and confuse users. In block_course_overview_campus, the course list always shows all courses which have passed the selected course filters. +* In block_course_overview in Moodle 2.4+, the administrator can configure the block to show Metacourse children. We decided to not adopt this feature for block_course_overview_campus because we have no need for this. If you need this feature, please let us know on https://github.com/moodleuulm/moodle-block_course_overview_campus/issues +* In block_course_overview in Moodle 2.4+, the administrator can configure the block to show a welcome message. We decided to not adopt this feature for block_course_overview_campus because we have no need for this. If you need this feature, please let us know on https://github.com/moodleuulm/moodle-block_course_overview_campus/issues +* In Moodle core since Moodle 2.2+, there is a setting "courselistshortnames" which controls the displaying of course names. This setting is also processed in block_course_overview. We decided to ignore this core setting and to stick to block_course_overview_campus's internal course display control settings. +* In contrast to the Moodle core block_course_overview, this block doesn't support MNet courses and wasn't tested with MNet Moodle installations. + + +Companion plugin local_boostcoc +------------------------------- + +Since the release of Moodle 3.2, Moodle core ships with a shiny new theme called "Boost". While Boost does many things right and better than the legacy theme Clean, it also has some fixed behaviours which don't make sense for all Moodle installations. One of these behaviours is the fact that the mycourses list in the nav drawer (the menu which appears when you click on the hamburger menu button) is non-collapsible, always contains all of my courses and can hardly be configured by administrators. + +We have created local_boostcoc as a companion plugin to block_course_overview_campus which does its best to add support for filtering and hiding courses to the mycourses list in the nav drawer. local_boostcoc is published on http://moodle.org/plugins/view/local_boostcoc and on https://github.com/moodleuulm/moodle-local_boostcoc. + + +Theme support +------------- + +This plugin is developed and tested on Moodle Core's Boost theme. +It should also work with Boost child themes, including Moodle Core's Classic theme. However, we can't support any other theme than Boost. + +This plugin also provides a fallback for browsers with JavaScript disabled. + + +Plugin repositories +------------------- + +This plugin is published and regularly updated in the Moodle plugins repository: +http://moodle.org/plugins/view/block_course_overview_campus + +The latest development version can be found on Github: +https://github.com/moodleuulm/moodle-block_course_overview_campus + + +Bug and problem reports / Support requests +------------------------------------------ + +This plugin is carefully developed and thoroughly tested, but bugs and problems can always appear. + +Please report bugs and problems on Github: +https://github.com/moodleuulm/moodle-block_course_overview_campus/issues + +We will do our best to solve your problems, but please note that due to limited resources we can't always provide per-case support. + + +Feature proposals +----------------- + +Due to limited resources, the functionality of this plugin is primarily implemented for our own local needs and published as-is to the community. We are aware that members of the community will have other needs and would love to see them solved by this plugin. + +Please issue feature proposals on Github: +https://github.com/moodleuulm/moodle-block_course_overview_campus/issues + +Please create pull requests on Github: +https://github.com/moodleuulm/moodle-block_course_overview_campus/pulls + +We are always interested to read about your feature proposals or even get a pull request from you, but please accept that we can handle your issues only as feature _proposals_ and not as feature _requests_. + + +Moodle release support +---------------------- + +Due to limited resources, this plugin is only maintained for the most recent major release of Moodle. However, previous versions of this plugin which work in legacy major releases of Moodle are still available as-is without any further updates in the Moodle Plugins repository. + +There may be several weeks after a new major release of Moodle has been published until we can do a compatibility check and fix problems if necessary. If you encounter problems with a new major release of Moodle - or can confirm that this plugin still works with a new major relase - please let us know on Github. + +If you are running a legacy version of Moodle, but want or need to run the latest version of this plugin, you can get the latest version of the plugin, remove the line starting with $plugin->requires from version.php and use this latest plugin version then on your legacy Moodle. However, please note that you will run this setup completely at your own risk. We can't support this approach in any way and there is a undeniable risk for erratic behavior. + + +Translating this plugin +----------------------- + +This Moodle plugin is shipped with an english language pack only. All translations into other languages must be managed through AMOS (https://lang.moodle.org) by what they will become part of Moodle's official language pack. + +As the plugin creator, we manage the translation into german for our own local needs on AMOS. Please contribute your translation into all other languages in AMOS where they will be reviewed by the official language pack maintainers for Moodle. + + +Right-to-left support +--------------------- + +This plugin has not been tested with Moodle's support for right-to-left (RTL) languages. +If you want to use this plugin with a RTL language and it doesn't work as-is, you are free to send us a pull request on Github with modifications. + + +PHP7 Support +------------ + +Since Moodle 3.4 core, PHP7 is mandatory. We are developing and testing this plugin for PHP7 only. + + +Copyright +--------- + +Ulm University +Communication and Information Centre (kiz) +Alexander Bias + + +Credits +------- + +This plugin is an enhanced version of Andrew James' block_course_overview_plus (https://moodle.org/plugins/view.php?plugin=block_course_overview_plus) which was enhanced to fit the needs of university campuses. diff --git a/blocks/course_overview_campus/amd/build/filter.min.js b/blocks/course_overview_campus/amd/build/filter.min.js new file mode 100644 index 0000000000000000000000000000000000000000..4c3d057495bf72e49160308de9de7d999371bab4 --- /dev/null +++ b/blocks/course_overview_campus/amd/build/filter.min.js @@ -0,0 +1 @@ +define(["jquery"],function(a){"use strict";function b(b){void 0!==b&&b.preventDefault();var c=a("#coc-filterterm").val();"all"===c?a(".termdiv").removeClass("coc-hidden"):(a(".termdiv").addClass("coc-hidden"),a(".coc-term-"+c).removeClass("coc-hidden")),M.util.set_user_preference("block_course_overview_campus-selectedterm",c)}function c(b){void 0!==b&&b.preventDefault();var c=a("#coc-filterteacher").val();"all"===c?a(".teacherdiv").removeClass("coc-hidden"):(a(".teacherdiv").addClass("coc-hidden"),a(".coc-teacher-"+c).removeClass("coc-hidden")),M.util.set_user_preference("block_course_overview_campus-selectedteacher",c)}function d(b){void 0!==b&&b.preventDefault();var c=a("#coc-filtercategory").val();"all"===c?a(".categorydiv").removeClass("coc-hidden"):(a(".categorydiv").addClass("coc-hidden"),a(".coc-category-"+c).removeClass("coc-hidden")),M.util.set_user_preference("block_course_overview_campus-selectedcategory",c)}function e(b){void 0!==b&&b.preventDefault();var c=a("#coc-filtertoplevelcategory").val();"all"===c?a(".toplevelcategorydiv").removeClass("coc-hidden"):(a(".toplevelcategorydiv").addClass("coc-hidden"),a(".coc-toplevelcategory-"+c).removeClass("coc-hidden")),M.util.set_user_preference("block_course_overview_campus-selectedtoplevelcategory",c)}function f(f){var g,h,i,j;for(g in f)if(f.hasOwnProperty(g)&&(h=f[g],i=a("#coc-filter"+g),i.length&&(j=i.val(),j!==h)))switch(g){case"term":b();break;case"teacher":c();break;case"category":d();break;case"toplevelcategory":e()}}function g(){var b=new Array;a(".coc-course").each(function(c,d){0==a(d).height()&&b.push(d.id.slice(11))});var c=JSON.stringify(b);M.util.set_user_preference("local_boostcoc-notshowncourses",c)}function h(){var b=new Array;a("#coc-filterterm, #coc-filtercategory, #coc-filtertoplevelcategory, #coc-filterteacher").each(function(c,d){"all"!==a(d).val()&&b.push(d.id.slice(4))});var c=parseInt(a("#coc-hiddencoursescount").html(),10);c>0&&b.push("hidecourses");var d=JSON.stringify(b);M.util.set_user_preference("local_boostcoc-activefilters",d)}return{initFilter:function(i){a("#coc-filterterm").on("change",b),a("#coc-filterteacher").on("change",c),a("#coc-filtercategory").on("change",d),a("#coc-filtertoplevelcategory").on("change",e),1==i.local_boostcoc&&a("#coc-filterterm, #coc-filterteacher, #coc-filtercategory, #coc-filtertoplevelcategory").on("change",g).on("change",h),f(i.initialsettings)}}}); \ No newline at end of file diff --git a/blocks/course_overview_campus/amd/build/hidecourse.min.js b/blocks/course_overview_campus/amd/build/hidecourse.min.js new file mode 100644 index 0000000000000000000000000000000000000000..7025467430e7060b9760098d0a32596023081f08 --- /dev/null +++ b/blocks/course_overview_campus/amd/build/hidecourse.min.js @@ -0,0 +1 @@ +define(["jquery"],function(a){"use strict";function b(b){var c;if(void 0!==b&&b.preventDefault(),1===b.data.manage&&(a("#coc-hidecourseicon-"+b.data.course).addClass("coc-hidden"),a("#coc-showcourseicon-"+b.data.course).removeClass("coc-hidden")),0===b.data.manage){a("#coc-hidecourseicon-"+b.data.course).addClass("coc-hidden"),a("#coc-showcourseicon-"+b.data.course).removeClass("coc-hidden");var d=b.data.course;a(".coc-hidecourse-"+b.data.course).slideUp(function(){a(".coc-hidecourse-"+d).addClass("coc-hidden"),c=parseInt(a("#coc-hiddencoursescount").html(),10),a("#coc-hiddencoursescount").html(c+1),a("#coc-hiddencoursesmanagement-bottom .row").removeClass("coc-hidden")})}M.util.set_user_preference("block_course_overview_campus-hidecourse-"+b.data.course,1)}function c(b){void 0!==b&&b.preventDefault(),1===b.data.manage&&(a("#coc-showcourseicon-"+b.data.course).addClass("coc-hidden"),a("#coc-hidecourseicon-"+b.data.course).removeClass("coc-hidden")),M.util.set_user_preference("block_course_overview_campus-hidecourse-"+b.data.course,0)}function d(){var b=new Array;a(".coc-course").each(function(c,d){0==a(d).height()&&b.push(d.id.slice(11))});var c=JSON.stringify(b);M.util.set_user_preference("local_boostcoc-notshowncourses",c)}function e(){var b=new Array;a("#coc-filterterm, #coc-filtercategory, #coc-filtertoplevelcategory, #coc-filterteacher").each(function(c,d){"all"!==a(d).val()&&b.push(d.id.slice(4))});var c=parseInt(a("#coc-hiddencoursescount").html(),10);c>0&&b.push("hidecourses");var d=JSON.stringify(b);M.util.set_user_preference("local_boostcoc-activefilters",d)}return{initHideCourse:function(f){var g,h=f.courses.split(" ");for(g=0;g<h.length;g++)a("#coc-hidecourseicon-"+h[g]).on("click",{course:h[g],manage:f.manage},b),a("#coc-showcourseicon-"+h[g]).on("click",{course:h[g],manage:f.manage},c),1==f.local_boostcoc&&0==f.manage&&a("#coc-hidecourseicon-"+h[g]).on("click",d).on("click",e)}}}); \ No newline at end of file diff --git a/blocks/course_overview_campus/amd/src/filter.js b/blocks/course_overview_campus/amd/src/filter.js new file mode 100644 index 0000000000000000000000000000000000000000..e40d0353bbfa930b4715a4da2212b127820dcf7d --- /dev/null +++ b/blocks/course_overview_campus/amd/src/filter.js @@ -0,0 +1,191 @@ +/** + * Block "course overview (campus)" - JS code for filtering courses + * + * @package block_course_overview_campus + * @copyright 2013 Alexander Bias, Ulm University <alexander.bias@uni-ulm.de> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define(['jquery'], function($) { + "use strict"; + + /** + * Function to filter the shown courses by term. + */ + function filterTerm(e) { + // Prevent the event from refreshing the page. + if (e !== undefined) { + e.preventDefault(); + } + + var value = $('#coc-filterterm').val(); + if (value === "all") { + $('.termdiv').removeClass('coc-hidden'); + } else { + $('.termdiv').addClass('coc-hidden'); + $('.coc-term-' + value).removeClass('coc-hidden'); + } + + // Store the users selection (Uses AJAX to save to the database). + M.util.set_user_preference('block_course_overview_campus-selectedterm', value); + } + + /** + * Function to filter the shown courses by term teacher. + */ + function filterTeacher(e) { + // Prevent the event from refreshing the page. + if (e !== undefined) { + e.preventDefault(); + } + + var value = $("#coc-filterteacher").val(); + if (value === "all") { + $('.teacherdiv').removeClass('coc-hidden'); + } else { + $('.teacherdiv').addClass('coc-hidden'); + $('.coc-teacher-' + value).removeClass('coc-hidden'); + } + + // Store the users selection (Uses AJAX to save to the database). + M.util.set_user_preference('block_course_overview_campus-selectedteacher', value); + } + + /** + * Function to filter the shown courses by parent category. + */ + function filterCategory(e) { + // Prevent the event from refreshing the page. + if (e !== undefined) { + e.preventDefault(); + } + + var value = $("#coc-filtercategory").val(); + if (value === "all") { + $('.categorydiv').removeClass('coc-hidden'); + } else { + $('.categorydiv').addClass('coc-hidden'); + $('.coc-category-' + value).removeClass('coc-hidden'); + } + + // Store the users selection (Uses AJAX to save to the database). + M.util.set_user_preference('block_course_overview_campus-selectedcategory', value); + } + + /** + * Function to filter the shown courses by top level category. + */ + function filterTopLevelCategory(e) { + // Prevent the event from refreshing the page. + if (e !== undefined) { + e.preventDefault(); + } + + var value = $("#coc-filtertoplevelcategory").val(); + if (value === "all") { + $('.toplevelcategorydiv').removeClass('coc-hidden'); + } else { + $('.toplevelcategorydiv').addClass('coc-hidden'); + $('.coc-toplevelcategory-' + value).removeClass('coc-hidden'); + } + + // Store the users selection (Uses AJAX to save to the database). + M.util.set_user_preference('block_course_overview_campus-selectedtoplevelcategory', value); + } + + /** + * Function to apply all filters again (used when the user has pushed the back button). + */ + function applyAllFilters(initialSettings) { + /* eslint-disable max-depth */ + var setting, value, $element, elementValue; + for (setting in initialSettings) { + if (initialSettings.hasOwnProperty(setting)) { + value = initialSettings[setting]; + $element = $('#coc-filter' + setting); + if ($element.length) { + elementValue = $element.val(); + if (elementValue !== value) { + switch (setting) { + case 'term': + filterTerm(); + break; + case 'teacher': + filterTeacher(); + break; + case 'category': + filterCategory(); + break; + case 'toplevelcategory': + filterTopLevelCategory(); + break; + } + } + } + } + } + /* eslint-enable max-depth */ + } + + /** + * Function to remember the not shown courses for local_boostcoc. + */ + function localBoostCOCRememberNotShownCourses() { + // Get all course nodes which are not shown (= invisible = their height is 0) and store their IDs in an array. + var notshowncourses = new Array(); + $('.coc-course').each(function(index, element) { + if ($(element).height() == 0) { + notshowncourses.push(element.id.slice(11)); // This will remove "coc-course-" from the id's string. + } + }); + + // Convert not shown courses array to JSON. + var jsonstring = JSON.stringify(notshowncourses); + + // Store the current status of not shown courses (Uses AJAX to save to the database). + M.util.set_user_preference('local_boostcoc-notshowncourses', jsonstring); + } + + /** + * Function to remember the active filters for local_boostcoc. + */ + function localBoostCOCRememberActiveFilters() { + // Get all active filters (value != all) and the fact that hidden courses are present and store them in an array. + var activefilters = new Array(); + $('#coc-filterterm, #coc-filtercategory, #coc-filtertoplevelcategory, #coc-filterteacher').each(function(index, element) { + if ($(element).val() !== "all") { + activefilters.push(element.id.slice(4)); // This will remove "coc-" from the id's string. + } + }); + var hiddenCount = parseInt($('#coc-hiddencoursescount').html(), 10); + if (hiddenCount > 0) { + activefilters.push('hidecourses'); + } + + // Convert not shown courses array to JSON. + var jsonstring = JSON.stringify(activefilters); + + // Store the current status of active filters (Uses AJAX to save to the database). + M.util.set_user_preference('local_boostcoc-activefilters', jsonstring); + } + + return { + initFilter: function(params) { + // Add change listener to filter widgets. + $('#coc-filterterm').on('change', filterTerm); + $('#coc-filterteacher').on('change', filterTeacher); + $('#coc-filtercategory').on('change', filterCategory); + $('#coc-filtertoplevelcategory').on('change', filterTopLevelCategory); + + // Add change listener to filter widgets for local_boostcoc. + if (params.local_boostcoc == true) { + $('#coc-filterterm, #coc-filterteacher, #coc-filtercategory, #coc-filtertoplevelcategory').on('change', + localBoostCOCRememberNotShownCourses).on('change', localBoostCOCRememberActiveFilters); + } + + // Make sure any initial filter settings are applied (may be needed if the user + // has used the browser 'back' button). + applyAllFilters(params.initialsettings); + } + }; +}); diff --git a/blocks/course_overview_campus/amd/src/hidecourse.js b/blocks/course_overview_campus/amd/src/hidecourse.js new file mode 100644 index 0000000000000000000000000000000000000000..d53da12aa07835ed8799d9887ef0e18fac4237a1 --- /dev/null +++ b/blocks/course_overview_campus/amd/src/hidecourse.js @@ -0,0 +1,132 @@ +/** + * Block "course overview (campus)" - JS code for hiding courses + * + * @package block_course_overview_campus + * @copyright 2013 Alexander Bias, Ulm University <alexander.bias@uni-ulm.de> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define(['jquery'], function($) { + "use strict"; + + /** + * Function to hide a course from the course list. + */ + function hideCourse(e) { + var hiddenCount; + // Prevent the event from refreshing the page. + if (e !== undefined) { + e.preventDefault(); + } + + // When hidden course managing is active. + if (e.data.manage === 1) { + // Change the icon. + $('#coc-hidecourseicon-' + e.data.course).addClass('coc-hidden'); + $('#coc-showcourseicon-' + e.data.course).removeClass('coc-hidden'); + } + // When hidden course managing is not active. + if (e.data.manage === 0) { + // Change the icon. + $('#coc-hidecourseicon-' + e.data.course).addClass('coc-hidden'); + $('#coc-showcourseicon-' + e.data.course).removeClass('coc-hidden'); + + // Use a nice slide animation to make clear where the course is going. + var courseId = e.data.course; + $('.coc-hidecourse-' + e.data.course).slideUp(function() { + $('.coc-hidecourse-' + courseId).addClass('coc-hidden'); + hiddenCount = parseInt($('#coc-hiddencoursescount').html(), 10); + $('#coc-hiddencoursescount').html(hiddenCount + 1); + $('#coc-hiddencoursesmanagement-bottom .row').removeClass('coc-hidden'); + }); + } + + // Store the course status (Uses AJAX to save to the database). + M.util.set_user_preference('block_course_overview_campus-hidecourse-' + e.data.course, 1); + } + + /** + * Function to show a course in the course list. + */ + function showCourse(e) { + // Prevent the event from refreshing the page. + if (e !== undefined) { + e.preventDefault(); + } + + // When hidden course managing is active. + if (e.data.manage === 1) { + // Change the icon. + $('#coc-showcourseicon-' + e.data.course).addClass('coc-hidden'); + $('#coc-hidecourseicon-' + e.data.course).removeClass('coc-hidden'); + } + + // Store the course status (Uses AJAX to save to the database). + M.util.set_user_preference('block_course_overview_campus-hidecourse-' + e.data.course, 0); + } + + /** + * Function to remember the not shown courses for local_boostcoc. + */ + function localBoostCOCRememberNotShownCourses() { + // Get all course nodes which are not shown (= invisible = their height is 0) and store their IDs in an array. + var notshowncourses = new Array(); + $('.coc-course').each(function(index, element) { + if ($(element).height() == 0) { + notshowncourses.push(element.id.slice(11)); // This will remove "coc-course-" from the id's string. + } + }); + + // Convert not shown courses array to JSON. + var jsonstring = JSON.stringify(notshowncourses); + + // Store the current status of not shown courses (Uses AJAX to save to the database). + M.util.set_user_preference('local_boostcoc-notshowncourses', jsonstring); + } + + /** + * Function to remember the active filters for local_boostcoc. + */ + function localBoostCOCRememberActiveFilters() { + // Get all active filters (value != all) and the fact that hidden courses are present and store them in an array. + var activefilters = new Array(); + $('#coc-filterterm, #coc-filtercategory, #coc-filtertoplevelcategory, #coc-filterteacher').each(function(index, element) { + if ($(element).val() !== "all") { + activefilters.push(element.id.slice(4)); // This will remove "coc-" from the id's string. + } + }); + var hiddenCount = parseInt($('#coc-hiddencoursescount').html(), 10); + if (hiddenCount > 0) { + activefilters.push('hidecourses'); + } + + // Convert not shown courses array to JSON. + var jsonstring = JSON.stringify(activefilters); + + // Store the current status of active filters (Uses AJAX to save to the database). + M.util.set_user_preference('local_boostcoc-activefilters', jsonstring); + } + + return { + initHideCourse: function(params) { + var i; + var courses = params.courses.split(" "); + for (i = 0; i < courses.length; i++) { + // Add change listener to hide courses widgets. + $('#coc-hidecourseicon-' + courses[i]).on('click', {course: courses[i], manage: params.manage}, hideCourse); + // Add change listener to show courses widgets. + $('#coc-showcourseicon-' + courses[i]).on('click', {course: courses[i], manage: params.manage}, showCourse); + // Add change listener to show / hide courses widgets for local_boostcoc. + // Do this only when hidden courses management isn't active. This way, the notshowncourses will not be remembered on + // the server until the user finishes hidden courses management. While working in hidden courses management in one + // browser tab, the nav drawer in a second browser tab would still show the old status. But we accept this because + // otherwise we would have to implement a second localBoostCOCRemember detection algorithm for hidden courses + // management. + if (params.local_boostcoc == true && params.manage == false) { + $('#coc-hidecourseicon-' + courses[i]).on('click', localBoostCOCRememberNotShownCourses).on('click', + localBoostCOCRememberActiveFilters); + } + } + } + }; +}); diff --git a/blocks/course_overview_campus/block_course_overview_campus.php b/blocks/course_overview_campus/block_course_overview_campus.php new file mode 100644 index 0000000000000000000000000000000000000000..306c63f69e69140af1c37b2e06113caa91f7f5d5 --- /dev/null +++ b/blocks/course_overview_campus/block_course_overview_campus.php @@ -0,0 +1,1408 @@ +<?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/>. + +/** + * Block "course overview (campus)" + * + * @package block_course_overview_campus + * @copyright 2013 Alexander Bias, Ulm University <alexander.bias@uni-ulm.de> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +// @codingStandardsIgnoreFile +// Let codechecker ignore this file. This legacy code is not fully compliant to Moodle coding style but working and well documented. + +/** + * Class block_course_overview_campus + * + * @package block_course_overview_campus + * @copyright 2013 Alexander Bias, Ulm University <alexander.bias@uni-ulm.de> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class block_course_overview_campus extends block_base { + + /** + * init function + * @return void + */ + public function init() { + $this->title = get_string('pluginname', 'block_course_overview_campus'); + } + + /** + * specialization function + * @return void + */ + public function specialization() { + $this->title = format_string(get_config('block_course_overview_campus', 'blocktitle')); + } + + /** + * applicable_formats function + * @return array + */ + public function applicable_formats() { + return array('my-index' => true, 'my' => true, 'site-index' => true); + } + + /** + * has_config function + * @return bool + */ + public function has_config() { + return true; + } + + /** + * instance_allow_multiple function + * @return bool + */ + public function instance_allow_multiple() { + return false; + } + + /** + * instance_can_be_hidden function + * @return bool + */ + public function instance_can_be_hidden() { + return false; + } + + /** + * get_content function + * @return string + */ + public function get_content() { + global $coc_config, $USER, $CFG, $DB, $PAGE, $OUTPUT; + + + /********************************************************************************/ + /*** PREPARE ***/ + /********************************************************************************/ + + // Don't run this function twice. + if ($this->content !== null) { + return $this->content; + } + + // Include local library. + require_once(__DIR__ . '/locallib.php'); + + // Get plugin config. + $coc_config = get_config('block_course_overview_campus'); + + + + /********************************************************************************/ + /*** PREPROCESSING ***/ + /********************************************************************************/ + + // Include local library. + require_once(__DIR__ . '/locallib.php'); + + + // Check if the configured term dates make sense, if not disable term filter. + if (!block_course_overview_campus_check_term_config()) { + $coc_config->termcoursefilter = false; + } + + + // Process GET parameters. + $param_hidecourse = optional_param('coc-hidecourse', 0, PARAM_BOOL); + $param_showcourse = optional_param('coc-showcourse', 0, PARAM_BOOL); + $param_term = optional_param('coc-term', null, PARAM_ALPHANUMEXT); + $param_category = optional_param('coc-category', null, PARAM_ALPHANUM); + $param_toplevelcategory = optional_param('coc-toplevelcategory', null, PARAM_ALPHANUM); + $param_teacher = optional_param('coc-teacher', null, PARAM_ALPHANUM); + $param_manage = optional_param('coc-manage', 0, PARAM_BOOL); + + + // Set displaying preferences when set by GET parameters. + if ($coc_config->enablehidecourses) { + if ($param_hidecourse != 0) { + set_user_preference('block_course_overview_campus-hidecourse-'.$param_hidecourse, 1); + } + if ($param_showcourse != 0) { + set_user_preference('block_course_overview_campus-hidecourse-'.$param_showcourse, 0); + } + } + + + // Set and remember term filter if GET parameter is present. + if ($coc_config->termcoursefilter == true) { + if ($param_term != null) { + $selectedterm = $param_term; + set_user_preference('block_course_overview_campus-selectedterm', $param_term); + } + // Or set term filter based on user preference with default term fallback if activated. + else if ($coc_config->defaultterm == true) { + $selectedterm = get_user_preferences('block_course_overview_campus-selectedterm', 'currentterm'); + } + // Or set term filter based on user preference with 'all' terms fallback. + else { + $selectedterm = get_user_preferences('block_course_overview_campus-selectedterm', 'all'); + } + } + + + // Set and remember parent category filter if GET parameter is present. + if ($coc_config->categorycoursefilter == true) { + if ($param_category != null) { + $selectedcategory = $param_category; + set_user_preference('block_course_overview_campus-selectedcategory', $param_category); + } + // Or set parent category filter based on user preference with 'all' categories fallback. + else { + $selectedcategory = get_user_preferences('block_course_overview_campus-selectedcategory', 'all'); + } + } + + + // Set and remember top level category filter if GET parameter is present. + if ($coc_config->toplevelcategorycoursefilter == true) { + if ($param_toplevelcategory != null) { + $selectedtoplevelcategory = $param_toplevelcategory; + set_user_preference('block_course_overview_campus-selectedtoplevelcategory', $param_toplevelcategory); + } + // Or set top level category filter based on user preference with 'all' categories fallback. + else { + $selectedtoplevelcategory = get_user_preferences('block_course_overview_campus-selectedtoplevelcategory', 'all'); + } + } + + + // Set and remember teacher filter if GET parameter is present. + if ($coc_config->teachercoursefilter == true) { + if ($param_teacher != null) { + $selectedteacher = $param_teacher; + set_user_preference('block_course_overview_campus-selectedteacher', $param_teacher); + } + // Or set teacher filter based on user preference with 'all' teachers fallback. + else { + $selectedteacher = get_user_preferences('block_course_overview_campus-selectedteacher', 'all'); + } + } + + + // Get my courses. + $courses = block_course_overview_campus_get_my_courses(); + + + + /********************************************************************************/ + /*** PROCESS MY COURSES ***/ + /********************************************************************************/ + + // No, I don't have any courses -> content is only a placeholder message. + if (empty($courses)) { + $content = get_string('nocourses', 'block_course_overview_campus'); + } + + // Yes, I have courses. + else { + // Start output buffer. + ob_start(); + + + // Get all course categories for later use. + $coursecategories = $DB->get_records('course_categories'); + + // Get teacher roles for later use. + if (!empty($coc_config->teacherroles)) { + $teacherroles = explode(',', $coc_config->teacherroles); + } + else { + $teacherroles = array(); + } + + + // Create empty filter for activated filters. + if ($coc_config->termcoursefilter == true) { + $filterterms = array(); + } + if ($coc_config->categorycoursefilter == true) { + $filtercategories = array(); + } + if ($coc_config->toplevelcategorycoursefilter == true) { + $filtertoplevelcategories = array(); + } + if ($coc_config->teachercoursefilter == true) { + $filterteachers = array(); + } + + // Create counter for hidden courses. + if ($coc_config->enablehidecourses) { + $hiddencoursescounter = 0; + } + + // Create string to remember courses for JS processing. + $js_courseslist = ' '; + + + // Now iterate over my courses and collect data about them. + foreach ($courses as $c) { + // Get course context. + $context = context_course::instance($c->id); + + // Collect information about my courses and populate filters with data about my courses. + // Term information. + if ($coc_config->termcoursefilter == true || $coc_config->secondrowshowtermname == true) { + // Create object for bufferung course term information. + $courseterm = new stdClass(); + + // If course start date is undefined, set course term to "other". + if ($c->startdate == 0) { + $courseterm->id = 'other'; + $courseterm->name = get_string('other', 'block_course_overview_campus'); + } + + // If course start date is available, if timeless courses are enabled and if course start date is before. + // timeless course threshold, set course term to "timeless". + else if ($coc_config->timelesscourses == true && date('Y', $c->startdate) < $coc_config->timelesscoursesthreshold) { + $courseterm->id = 'timeless'; + $courseterm->name = format_string($coc_config->timelesscoursesname); + } + + // If course start date is available, distinguish between term modes. + // "Academic year" mode. + else if ($coc_config->termmode == 1) { + // Prepare date information. + $coursestartyday = usergetdate($c->startdate)['yday']; + $coursestartyear = usergetdate($c->startdate)['year']; + $term1startyday = usergetdate(make_timestamp($coursestartyear, explode('-', $coc_config->term1startday)[0], explode('-', $coc_config->term1startday)[1]))['yday']; + + // If term starts on January 1st, set course term to course start date's year. + if ($coc_config->term1startday == '01-01') { + $courseterm->id = $coursestartyear; + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term1name, $coursestartyear); + } + // If term doesn't start on January 1st and course start date's day comes on or after term start day, + // set course term to course start date's year + next year. + else if ($coursestartyday >= $term1startyday) { + $courseterm->id = $coursestartyear.'-'.($coursestartyear + 1); + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term1name, $coursestartyear, ($coursestartyear + 1)); + } + // If term doesn't start on January 1st and course start date's day comes before term start day, + // set course term to course start date's year + former year. + else { + $courseterm->id = ($coursestartyear - 1).'-'.$coursestartyear; + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term1name, ($coursestartyear - 1), $coursestartyear); + } + } + // "Semester" mode. + else if ($coc_config->termmode == 2) { + // Prepare date information. + $coursestartyday = usergetdate($c->startdate)['yday']; + $coursestartyear = usergetdate($c->startdate)['year']; + $term1startyday = usergetdate(make_timestamp($coursestartyear, explode('-', $coc_config->term1startday)[0], explode('-', $coc_config->term1startday)[1]))['yday']; + $term2startyday = usergetdate(make_timestamp($coursestartyear, explode('-', $coc_config->term2startday)[0], explode('-', $coc_config->term2startday)[1]))['yday']; + + // If course start date's day comes before first term start day, + // set course term to second term of former year. + if ($coursestartyday < $term1startyday) { + $courseterm->id = ($coursestartyear - 1).'-2'; + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term2name, ($coursestartyear - 1), $coursestartyear); + } + // If course start date's day comes on or after first term start day but before second term start day, + // set course term to first term of current year. + else if ($coursestartyday >= $term1startyday && $coursestartyday < $term2startyday) { + $courseterm->id = $coursestartyear.'-1'; + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term1name, $coursestartyear); + } + // If course start date's day comes on or after second term start day, + // set course term to second term of current year. + else { + $courseterm->id = $coursestartyear.'-2'; + // If first term does start on January 1st, suffix name with single year, + // otherwise suffix name with double year. + if ($coc_config->term1startday == '01-01') { + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term2name, $coursestartyear); + } else { + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term2name, $coursestartyear, ($coursestartyear + 1)); + } + } + } + // "Tertial" mode. + else if ($coc_config->termmode == 3) { + // Prepare date information. + $coursestartyday = usergetdate($c->startdate)['yday']; + $coursestartyear = usergetdate($c->startdate)['year']; + $term1startyday = usergetdate(make_timestamp($coursestartyear, explode('-', $coc_config->term1startday)[0], explode('-', $coc_config->term1startday)[1]))['yday']; + $term2startyday = usergetdate(make_timestamp($coursestartyear, explode('-', $coc_config->term2startday)[0], explode('-', $coc_config->term2startday)[1]))['yday']; + $term3startyday = usergetdate(make_timestamp($coursestartyear, explode('-', $coc_config->term3startday)[0], explode('-', $coc_config->term3startday)[1]))['yday']; + + // If course start date's day comes before first term start day, + // set course term to third term of former year. + if ($coursestartyday < $term1startyday) { + $courseterm->id = ($coursestartyear - 1).'-3'; + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term3name, ($coursestartyear - 1), $coursestartyear); + } + // If course start date's day comes on or after first term start day but before second term start day, + // set course term to first term of current year. + else if ($coursestartyday >= $term1startyday && $coursestartyday < $term2startyday) { + $courseterm->id = $coursestartyear.'-1'; + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term1name, $coursestartyear); + } + // If course start date's day comes on or after second term start day but before third term start day, + // set course term to second term of current year. + else if ($coursestartyday >= $term2startyday && $coursestartyday < $term3startyday) { + $courseterm->id = $coursestartyear.'-2'; + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term2name, $coursestartyear); + } + // If course start date's day comes on or after third term start day, + // set course term to third term of current year. + else { + $courseterm->id = $coursestartyear.'-3'; + // If first term does start on January 1st, suffix name with single year, + // otherwise suffix name with double year. + if ($coc_config->term1startday == '01-01') { + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term3name, $coursestartyear); + } else { + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term3name, $coursestartyear, ($coursestartyear + 1)); + } + } + } + // "Trimester" mode. + else if ($coc_config->termmode == 4) { + // Prepare date information. + $coursestartyday = usergetdate($c->startdate)['yday']; + $coursestartyear = usergetdate($c->startdate)['year']; + $term1startyday = usergetdate(make_timestamp($coursestartyear, explode('-', $coc_config->term1startday)[0], explode('-', $coc_config->term1startday)[1]))['yday']; + $term2startyday = usergetdate(make_timestamp($coursestartyear, explode('-', $coc_config->term2startday)[0], explode('-', $coc_config->term2startday)[1]))['yday']; + $term3startyday = usergetdate(make_timestamp($coursestartyear, explode('-', $coc_config->term3startday)[0], explode('-', $coc_config->term3startday)[1]))['yday']; + $term4startyday = usergetdate(make_timestamp($coursestartyear, explode('-', $coc_config->term4startday)[0], explode('-', $coc_config->term4startday)[1]))['yday']; + + // If course start date's day comes before first term start day, + // set course term to fourth term of former year. + if ($coursestartyday < $term1startyday) { + $courseterm->id = ($coursestartyear - 1).'-4'; + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term4name, ($coursestartyear - 1), $coursestartyear); + } + // If course start date's day comes on or after first term start day but before second term start day, + // set course term to first term of current year. + else if ($coursestartyday >= $term1startyday && $coursestartyday < $term2startyday) { + $courseterm->id = $coursestartyear.'-1'; + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term1name, $coursestartyear); + } + // If course start date's day comes on or after second term start day but before third term start day, + // set course term to second term of current year. + else if ($coursestartyday >= $term2startyday && $coursestartyday < $term3startyday) { + $courseterm->id = $coursestartyear.'-2'; + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term2name, $coursestartyear); + } + // If course start date's day comes on or after third term start day but before fourth term start day, + // set course term to third term of current year. + else if ($coursestartyday >= $term3startyday && $coursestartyday < $term4startyday) { + $courseterm->id = $coursestartyear.'-3'; + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term3name, $coursestartyear); + } + // If course start date's day comes on or after fourth term start day, + // set course term to fourth term of current year. + else { + $courseterm->id = $coursestartyear.'-4'; + // If first term does start on January 1st, suffix name with single year, + // otherwise suffix name with double year. + if ($coc_config->term1startday == '01-01') { + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term4name, $coursestartyear); + } else { + $courseterm->name = block_course_overview_campus_get_term_displayname($coc_config->term4name, $coursestartyear, ($coursestartyear + 1)); + } + } + } + // This should never happen. + else { + print_error('error'); + } + + // Remember course term for later use. + $c->term = $courseterm->id; + $c->termname = format_string($courseterm->name); + } + // Term filter. + if ($coc_config->termcoursefilter == true) { + // Add course term to filter list. + $filterterms[$courseterm->id] = $courseterm->name; + } + + // Parent category information. + if ($coc_config->categorycoursefilter == true || + $coc_config->secondrowshowcategoryname == true || + $coc_config->toplevelcategorycoursefilter == true || + $coc_config->secondrowshowtoplevelcategoryname == true) { + // Get course parent category name from array of all category names. + $coursecategory = $coursecategories[$c->category]; + + // Remember course parent category name for later use. + $c->categoryname = format_string($coursecategory->name); + $c->categoryid = $coursecategory->id; + + // Get course top level category name from array of all category names. + $coursecategorypath = explode('/', $coursecategory->path); + $coursetoplevelcategoryid = $coursecategorypath[1]; + $coursetoplevelcategory = $coursecategories[$coursetoplevelcategoryid]; + + // Remember course top level category name for later use. + $c->toplevelcategoryname = format_string($coursetoplevelcategory->name); + $c->toplevelcategoryid = $coursetoplevelcategory->id; + } + // Parent category filter. + if ($coc_config->categorycoursefilter == true) { + // Merge homonymous categories into one category if configured. + if ($coc_config->mergehomonymouscategories == true) { + // Check if course category name is already present in the category filter array. + if ($othercategoryid = array_search($c->categoryname, $filtercategories)) { + // If yes and if course category is different than the already present category (same name, + // but different id), modify course category id to equal the already present category id + // (poor hack, but functional). + if ($othercategoryid != $c->categoryid) { + $c->categoryid = $othercategoryid; + } + } + } + + // Add course parent category name to filter list. + $filtercategories[$c->categoryid] = $c->categoryname; + } + // Top level category filter. + if ($coc_config->toplevelcategorycoursefilter == true) { + // Add course top level category name to filter list. + $filtertoplevelcategories[$c->toplevelcategoryid] = $c->toplevelcategoryname; + } + + // Teacher information. + if ($coc_config->teachercoursefilter == true || $coc_config->secondrowshowteachername == true || $coc_config->prioritizemyteachedcourses == true) { + + // Get course teachers based on global teacher roles. + if (count($teacherroles) > 0) { + + // Get all user name fields for SQL query in a proper way. + $allnames = get_all_user_name_fields(true, 'u'); + $teacherfields = 'ra.id AS raid, u.id, '.$allnames.', r.sortorder'; // Moodle would complain about two columns called id with a "Did you remember to make the first column something unique in your call to get_records? Duplicate value 'xxx' found in column 'id'." debug message. That's why we alias one column to a name different than id. + $teachersortfields = 'u.lastname, u.firstname'; + + // Check if we have to check for suspended teachers. + if ($coc_config->teacherroleshidesuspended == 1) { + // Build extra where clause for SQL query. + $now = round(time(), -2); // Improves db caching. + $extrawhere = 'ue.status = '.ENROL_USER_ACTIVE.' AND e.status = '.ENROL_INSTANCE_ENABLED.' AND ue.timestart < '.$now.' AND (ue.timeend = 0 OR ue.timeend > '.$now.')'; + } else { + $extrawhere = ''; + } + + // Check if we have to include teacher roles from parent contexts. + // If yes. + if ($coc_config->teacherrolesparent == 1) { + // If we have to check for suspended teachers. + if ($coc_config->teacherroleshidesuspended == 1) { + $courseteachers = get_role_users($teacherroles, $context, true, + $teacherfields, $teachersortfields, false, '', '', '', $extrawhere); + } else { + $courseteachers = get_role_users($teacherroles, $context, true, + $teacherfields, $teachersortfields); + } + } + // If no. + else if ($coc_config->teacherrolesparent == 2) { + // If we have to check for suspended teachers. + if ($coc_config->teacherroleshidesuspended == 1) { + $courseteachers = get_role_users($teacherroles, $context, false, + $teacherfields, $teachersortfields, false, '', '', '', $extrawhere); + } else { + $courseteachers = get_role_users($teacherroles, $context, false, + $teacherfields, $teachersortfields); + } + } + // If depending on moodle/course:reviewotherusers capability. + else if ($coc_config->teacherrolesparent == 3) { + // If we have to check for suspended teachers. + $hasreviewotherscapability = has_capability('moodle/course:reviewotherusers', $context); + if ($coc_config->teacherroleshidesuspended == 1) { + $courseteachers = get_role_users($teacherroles, $context, $hasreviewotherscapability, + $teacherfields, $teachersortfields, false, '', '', '', $extrawhere); + } else { + $courseteachers = get_role_users($teacherroles, $context, $hasreviewotherscapability, + $teacherfields, $teachersortfields); + } + } + // Should not happen. + else { + $courseteachers = get_role_users($teacherroles, $context, true, $teacherfields, + $teachersortfields); + } + } else { + $courseteachers = array(); + } + + // The way we use get_role_users(), the teachers array may now contain duplicates as a teacher might have more + // than one role in a course and is indexed by ra.id instead of u.id (which we expect later). + // We will rewrite the array in reverse order indexed by userid, this way existing teachers will be eliminated + // by their own duplicate with higher relevance. + $courseteacherstmp = $courseteachers; + $courseteachers = []; + foreach (array_reverse($courseteacherstmp) as $teacher) { + $courseteachers[$teacher->id] = $teacher; + } + + // Remember course teachers for later use. + $c->teachers = $courseteachers; + } + // Teacher filter. + if ($coc_config->teachercoursefilter == true) { + // Add all course teacher's names to filter list. + if ($coc_config->teachercoursefilter == true) { + foreach ($courseteachers as $ct) { + $filterteachers[$ct->id] = $ct->lastname.', '.$ct->firstname; + } + } + } + + + // Check if this course is hidden according to the hide courses feature. + if ($coc_config->enablehidecourses == true) { + $courses[$c->id]->hidecourse = block_course_overview_campus_course_hidden_by_hidecourses($c); + // Increase counter for hidden courses management. + if ($courses[$c->id]->hidecourse == true) { + $hiddencoursescounter++; + } + } + + // Check if this course is hidden according to the term course filter. + if ($coc_config->termcoursefilter == true) { + $courses[$c->id]->termcoursefiltered = block_course_overview_campus_course_hidden_by_termcoursefilter($c, $selectedterm); + } + + // Check if this course is hidden according to the parent category course filter. + if ($coc_config->categorycoursefilter == true) { + $courses[$c->id]->categorycoursefiltered = block_course_overview_campus_course_hidden_by_categorycoursefilter($c, $selectedcategory); + } + + // Check if this course is hidden according to the top level category course filter. + if ($coc_config->toplevelcategorycoursefilter == true) { + $courses[$c->id]->toplevelcategorycoursefiltered = block_course_overview_campus_course_hidden_by_toplevelcategorycoursefilter($c, $selectedtoplevelcategory); + } + + // Check if this course is hidden according to the teacher course filter. + if ($coc_config->teachercoursefilter == true) { + $courses[$c->id]->teachercoursefiltered = block_course_overview_campus_course_hidden_by_teachercoursefilter($c, $selectedteacher); + } + + + // Re-sort courses to list courses in which I have a teacher role first if configured: + // First step: Removing the courses. + if ($coc_config->prioritizemyteachedcourses) { + // Check if user is teacher in this course. + if (array_key_exists($USER->id, $courseteachers)) { + // Remember the course. + $myteachercourses[] = $c; + // Remove the course from the courses array. + unset($courses[$c->id]); + } + } + } + + + // Re-sort courses to list courses in which I have a teacher role first if configured: + // Last step: Adding the courses again. + if ($coc_config->prioritizemyteachedcourses && isset ($myteachercourses) && count($myteachercourses) > 0) { + // Add the courses again at the beginning of the courses array. + $courses = $myteachercourses + $courses; + } + + + // Replace and remember currentterm placeholder with precise term based on my courses. + if ($coc_config->termcoursefilter == true && $selectedterm == 'currentterm') { + // Distinguish between term modes. + // "Academic year" mode. + if ($coc_config->termmode == '1') { + // If term starts on January 1st and there are courses this year, + // set selected term to this year. + if ($coc_config->term1startday == '1' && isset($filterterms[date('Y')])) { + $selectedterm = date('Y'); + } + // If term doesn't start on January 1st and current day comes on or after term start day and there are courses + // this term, set selected term to this year + next year. + else if (intval(date('z')) >= intval(date('z', strtotime(date('Y', $c->startdate).'-'.$coc_config->term1startday))) && + isset($filterterms[date('Y').'-'.(date('Y') + 1)])) { + $selectedterm = date('Y').'-'.(date('Y') + 1); + } + // If term doesn't start on January 1st and current day comes before term start day and there are courses + // this term, set selected term to this year + former year. + else if (isset($filterterms[(date('Y') - 1).'-'.date('Y')])) { + $selectedterm = (date('Y') - 1).'-'.date('Y'); + } + // Otherwise set selected term to the latest (but not future) term possible. + else { + $selectedterm = 'all'; + arsort($filterterms); + foreach ($filterterms as $t) { + if ($t != 'other' && $t != 'timeless' && intval(substr($t, 0, 4)) <= intval(date('Y'))) { + $selectedterm = $t; + break; + } + } + } + } + // "Semester" mode. + else if ($coc_config->termmode == '2') { + // If current day comes before first term start day and there are courses this term, + // set selected term to second term of former year. + if (intval(date('z')) < intval(date('z', strtotime(date('Y', $c->startdate).'-'.$coc_config->term1startday))) && isset($filterterms[(date('Y') - 1).'-2'])) { + $selectedterm = (date('Y') - 1).'-2'; + } + // If current day comes on or after first term start day but before second term start day and there are courses + // this term, set selected term to first term of current year. + else if (intval(date('z', $c->startdate)) >= intval(date('z', strtotime(date('Y', $c->startdate).'-'.$coc_config->term1startday))) && + intval(date('z', $c->startdate)) < intval(date('z', strtotime(date('Y', $c->startdate).'-'.$coc_config->term2startday))) && + isset($filterterms[date('Y').'-1'])) { + $selectedterm = date('Y').'-1'; + } + // If course start date's day comes on or after second term start day and there are courses this term, + // set selected term to second term of current year. + else if (isset($filterterms[date('Y').'-2'])) { + $selectedterm = date('Y').'-2'; + } + // Otherwise set selected term to the latest (but not future) term possible. + else { + $selectedterm = 'all'; + krsort($filterterms); + foreach ($filterterms as $t => $n) { + if ($t != 'other' && $t != 'timeless' && intval(substr($t, 0, 4)) <= intval(date('Y'))) { + $selectedterm = $t; + break; + } + } + } + } + // "Tertial" mode. + else if ($coc_config->termmode == '3') { + // If current day comes before first term start day and there are courses this term, + // set selected term to third term of former year. + if (intval(date('z')) < intval(date('z', strtotime(date('Y', $c->startdate).'-'.$coc_config->term1startday))) && + isset($filterterms[(date('Y') - 1).'-3'])) { + $selectedterm = (date('Y') - 1).'-2'; + } + // If current day comes on or after first term start day but before second term start day and there are courses + // this term, set selected term to first term of current year. + else if (intval(date('z', $c->startdate)) >= intval(date('z', strtotime(date('Y', $c->startdate).'-'.$coc_config->term1startday))) && + intval(date('z', $c->startdate)) < intval(date('z', strtotime(date('Y', $c->startdate).'-'.$coc_config->term2startday))) && + isset($filterterms[date('Y').'-1'])) { + $selectedterm = date('Y').'-1'; + } + // If current day comes on or after second term start day but before third term start day and there are courses + // this term, set selected term to second term of current year. + else if (intval(date('z', $c->startdate)) >= intval(date('z', strtotime(date('Y', $c->startdate).'-'.$coc_config->term2startday))) && + intval(date('z', $c->startdate)) < intval(date('z', strtotime(date('Y', $c->startdate).'-'.$coc_config->term3startday))) && + isset($filterterms[date('Y').'-2'])) { + $selectedterm = date('Y').'-2'; + } + // If course start date's day comes on or after third term start day and there are courses this term, + // set selected term to third term of current year. + else if (isset($filterterms[date('Y').'-3'])) { + $selectedterm = date('Y').'-3'; + } + // Otherwise set selected term to the latest (but not future) term possible. + else { + $selectedterm = 'all'; + krsort($filterterms); + foreach ($filterterms as $t => $n) { + if ($t != 'other' && $t != 'timeless' && intval(substr($t, 0, 4)) <= intval(date('Y'))) { + $selectedterm = $t; + break; + } + } + } + } + // "Trimester" mode. + else if ($coc_config->termmode == '4') { + // If current day comes before first term start day and there are courses this term, + // set selected term to fourth term of former year. + if (intval(date('z')) < intval(date('z', strtotime(date('Y', $c->startdate).'-'.$coc_config->term1startday))) && + isset($filterterms[(date('Y') - 1).'-4'])) { + $selectedterm = (date('Y') - 1).'-2'; + } + // If current day comes on or after first term start day but before second term start day and there are courses + // this term, set selected term to first term of current year. + else if (intval(date('z', $c->startdate)) >= intval(date('z', strtotime(date('Y', $c->startdate).'-'.$coc_config->term1startday))) && + intval(date('z', $c->startdate)) < intval(date('z', strtotime(date('Y', $c->startdate).'-'.$coc_config->term2startday))) && + isset($filterterms[date('Y').'-1'])) { + $selectedterm = date('Y').'-1'; + } + // If current day comes on or after second term start day but before third term start day and there are courses + // this term, set selected term to second term of current year. + else if (intval(date('z', $c->startdate)) >= intval(date('z', strtotime(date('Y', $c->startdate).'-'.$coc_config->term2startday))) && + intval(date('z', $c->startdate)) < intval(date('z', strtotime(date('Y', $c->startdate).'-'.$coc_config->term3startday))) && + isset($filterterms[date('Y').'-2'])) { + $selectedterm = date('Y').'-2'; + } + // If current day comes on or after third term start day but before fourth term start day and there are courses + // this term, set selected term to third term of current year. + else if (intval(date('z', $c->startdate)) >= intval(date('z', strtotime(date('Y', $c->startdate).'-'.$coc_config->term3startday))) && + intval(date('z', $c->startdate)) < intval(date('z', strtotime(date('Y', $c->startdate).'-'.$coc_config->term4startday))) && + isset($filterterms[date('Y').'-3'])) { + $selectedterm = date('Y').'-3'; + } + // If course start date's day comes on or after fourth term start day and there are courses this term, + // set selected term to fourth term of current year. + else if (isset($filterterms[date('Y').'-4'])) { + $selectedterm = date('Y').'-4'; + } + // Otherwise set selected term to the latest (but not future) term possible. + else { + $selectedterm = 'all'; + krsort($filterterms); + foreach ($filterterms as $t => $n) { + if ($t != 'other' && $t != 'timeless' && intval(substr($t, 0, 4)) <= intval(date('Y'))) { + $selectedterm = $t; + break; + } + } + } + } + // This should never happen. + else { + print_error('error'); + } + + // Remember selected term. + set_user_preference('block_course_overview_campus-selectedterm', $selectedterm); + } + + + + /********************************************************************************/ + /*** GENERATE OUTPUT FOR FILTER ***/ + /********************************************************************************/ + + // Show filter form if any filter is activated and if hidden courses management isn't active. + if ((!$coc_config->enablehidecourses || $param_manage == 0) && ($coc_config->categorycoursefilter == true || $coc_config->toplevelcategorycoursefilter == true || $coc_config->termcoursefilter == true || $coc_config->teachercoursefilter == true)) { + // Calculate CSS class for filter divs. + $filtercount = 0; + if ($coc_config->termcoursefilter == true) { + $filtercount++; + } + if ($coc_config->teachercoursefilter == true) { + $filtercount++; + } + if ($coc_config->categorycoursefilter == true) { + $filtercount++; + } + if ($coc_config->toplevelcategorycoursefilter == true) { + $filtercount++; + } + if ($filtercount == 1) { + $filterwidth = 'span12 col-md-12'; // Class 'span12' is used for Bootstrapbase and will be ignored by Boost. + } else if ($filtercount == 2) { + $filterwidth = 'span6 col-md-6'; // Class 'span6' is used for Bootstrapbase and will be ignored by Boost. + } else if ($filtercount == 3) { + $filterwidth = 'span4 col-md-4'; // Class 'span4' is used for Bootstrapbase and will be ignored by Boost. + } else if ($filtercount == 4) { + $filterwidth = 'span3 col-md-6 col-lg-3'; // Class 'span3' is used for Bootstrapbase and will be ignored by Boost. + } else { + $filterwidth = 'span12 col-md-12'; // Class 'span12' is used for Bootstrapbase and will be ignored by Boost. + } + + // Start form. + echo '<form method="post" action="">'; + + // Start section. + echo '<div id="coc-filterlist" class="container-fluid"><div class="row">'; + + // Show term filter. + if ($coc_config->termcoursefilter == true) { + echo '<div class="coc-filter '.$filterwidth.' mb-3">'; + + // Show filter description. + if ($coc_config->termcoursefilterdisplayname != '') { + echo '<label for="coc-filterterm">'.format_string($coc_config->termcoursefilterdisplayname).'</label>'; + } + + // Show filter widget. + echo '<select name="coc-term" id="coc-filterterm" class="input-block-level form-control">'; // Class 'input-block-level' is used for Bootstrapbase and will be ignored by Boost. + + // Remember in this variable if selected term was displayed or not. + $selectedtermdisplayed = false; + + // Sort term filter alphabetically in reverse order. + krsort($filterterms); + + // Print "All terms" option. + if ($selectedterm == 'all') { + echo '<option value="all" selected>'.get_string('all', 'block_course_overview_campus').'</option> '; + $selectedtermdisplayed = true; + } else { + echo '<option value="all">'.get_string('all', 'block_course_overview_campus').'</option> '; + } + + // Print each term in filter as an option item and select selected term. + foreach ($filterterms as $t => $n) { + // If iterated term is selected term. + if ($selectedterm == $t) { + // Handle "other" term option. + if ($selectedterm == 'other') { + echo '<option selected value="other">'.get_string('other', 'block_course_overview_campus').'</option> '; + $selectedtermdisplayed = true; + } + // Handle "timeless" term option. + else if ($selectedterm == 'timeless') { + echo '<option selected value="timeless">'.format_string($coc_config->timelesscoursesname).'</option> '; + $selectedtermdisplayed = true; + } else { + echo '<option selected value="'.$t.'">'.format_string($n).'</option> '; + $selectedtermdisplayed = true; + } + } + // If iterated term isn't selected term. + else { + // Handle "other" term option. + if ($t == 'other') { + echo '<option value="other">'.get_string('other', 'block_course_overview_campus').'</option> '; + } + // Handle "timeless" term option. + else if ($t == 'timeless') { + echo '<option value="timeless">'.format_string($coc_config->timelesscoursesname).'</option> '; + } else { + echo '<option value="'.$t.'">'.format_string($n).'</option> '; + } + } + } + + echo '</select>'; + + // If selected term couldn't be displayed, select all terms and save the new selection. + // In this case, no option item is marked as selected, but that's ok as the "all" item is at the top. + if (!$selectedtermdisplayed) { + $selectedterm = 'all'; + set_user_preference('block_course_overview_campus-selectedterm', $selectedterm); + } + + echo '</div>'; + } + + // Show top level category filter. + if ($coc_config->toplevelcategorycoursefilter == true) { + echo '<div class="coc-filter '.$filterwidth.' mb-3">'; + + // Show filter description. + if ($coc_config->toplevelcategorycoursefilterdisplayname != '') { + echo '<label for="coc-filtertoplevelcategory">'.format_string($coc_config->toplevelcategorycoursefilterdisplayname).'</label>'; + } + + // Show filter widget. + echo '<select name="coc-toplevelcategory" id="coc-filtertoplevelcategory" class="input-block-level form-control">'; // class 'input-block-level' is used for Bootstrapbase and will be ignored by Boost. + + // Remember in this variable if selected top level category was displayed or not. + $selectedtoplevelcategorydisplayed = false; + + // Sort top level category filter by category sort order. + // Fetch full category information for each category. + foreach ($filtertoplevelcategories as $ftl_key => $ftl_value) { + $filtertoplevelcategoriesfullinfo[] = $coursecategories[$ftl_key]; + } + // Sort full category information array by sortorder. + $success = usort($filtertoplevelcategoriesfullinfo, "block_course_overview_campus_compare_categories"); + // If sorting was successful, create new array with same data structure like the old one. + // Otherwise just leave the old array as it is (should not happen). + if ($success) { + $filtertoplevelcategories = array(); + foreach ($filtertoplevelcategoriesfullinfo as $ftl) { + $filtertoplevelcategories[$ftl->id] = format_string($ftl->name); + } + } + + // Print "All categories" option. + if ($selectedtoplevelcategory == 'all') { + echo '<option value="all" selected>'.get_string('all', 'block_course_overview_campus').'</option> '; + $selectedtoplevelcategorydisplayed = true; + } else { + echo '<option value="all">'.get_string('all', 'block_course_overview_campus').'</option> '; + } + + // Print each top level category in filter as an option item and select selected top level category. + foreach ($filtertoplevelcategories as $value => $cat) { + // If iterated top level category is selected top level category. + if ($selectedtoplevelcategory == $value) { + echo '<option selected value="'.$value.'">'.$cat.'</option> '; + $selectedtoplevelcategorydisplayed = true; + } + // If iterated top level category isn't selected top level category. + else { + echo '<option value="'.$value.'">'.$cat.'</option> '; + } + } + + echo '</select>'; + + // If selected top level category couldn't be displayed, select all categories and save the new selection. + // In this case, no option item is marked as selected, but that's ok as the "all" item is at the top. + if (!$selectedtoplevelcategorydisplayed) { + $selectedtoplevelcategory = 'all'; + set_user_preference('block_course_overview_campus-selectedtoplevelcategory', $selectedtoplevelcategory); + } + + echo '</div>'; + } + + // Show parent category filter. + if ($coc_config->categorycoursefilter == true) { + echo '<div class="coc-filter '.$filterwidth.' mb-3">'; + + // Show filter description. + if ($coc_config->categorycoursefilterdisplayname != '') { + echo '<label for="coc-filtercategory">'.format_string($coc_config->categorycoursefilterdisplayname).'</label>'; + } + + // Show filter widget. + echo '<select name="coc-category" id="coc-filtercategory" class="input-block-level form-control">'; // Class 'input-block-level' is used for Bootstrapbase and will be ignored by Boost. + + // Remember in this variable if selected parent category was displayed or not. + $selectedcategorydisplayed = false; + + // Sort parent category filter alphabetically. + natcasesort($filtercategories); + + // Print "All categories" option. + if ($selectedcategory == 'all') { + echo '<option value="all" selected>'.get_string('all', 'block_course_overview_campus').'</option> '; + $selectedcategorydisplayed = true; + } else { + echo '<option value="all">'.get_string('all', 'block_course_overview_campus').'</option> '; + } + + // Print each parent category in filter as an option item and select selected parent category. + foreach ($filtercategories as $value => $cat) { + // If iterated parent category is selected parent category. + if ($selectedcategory == $value) { + echo '<option selected value="'.$value.'">'.$cat.'</option> '; + $selectedcategorydisplayed = true; + } + // If iterated parent category isn't selected parent category. + else { + echo '<option value="'.$value.'">'.$cat.'</option> '; + } + } + + echo '</select>'; + + // If selected parent category couldn't be displayed, select all categories and save the new selection. + // In this case, no option item is marked as selected, but that's ok as the "all" item is at the top. + if (!$selectedcategorydisplayed) { + $selectedcategory = 'all'; + set_user_preference('block_course_overview_campus-selectedcategory', $selectedcategory); + } + + echo '</div>'; + } + + // Show teacher filter. + if ($coc_config->teachercoursefilter == true) { + echo '<div class="coc-filter '.$filterwidth.' mb-3">'; + + // Show filter description. + if ($coc_config->teachercoursefilterdisplayname != '') { + echo '<label for="coc-filterteacher">'.format_string($coc_config->teachercoursefilterdisplayname).'</label>'; + } + + // Show filter widget. + echo '<select name="coc-teacher" id="coc-filterteacher" class="input-block-level form-control">'; // Class 'input-block-level' is used for Bootstrapbase and will be ignored by Boost. + + // Remember in this variable if selected teacher was displayed or not. + $selectedteacherdisplayed = false; + + // Sort teacher filter alphabetically. + natcasesort($filterteachers); + + // Print "All teachers" option. + if ($selectedteacher == 'all') { + echo '<option value="all" selected>'.get_string('all', 'block_course_overview_campus').'</option> '; + $selectedteacherdisplayed = true; + } else { + echo '<option value="all">'.get_string('all', 'block_course_overview_campus').'</option> '; + } + + // Print each teacher in filter as an option item and select selected teacher. + foreach ($filterteachers as $id => $t) { + // If iterated teacher is selected teacher. + if ($selectedteacher == $id) { + echo '<option selected value="'.$id.'">'.$t.'</option> '; + $selectedteacherdisplayed = true; + } else { + echo '<option value="'.$id.'">'.$t.'</option> '; + } + } + + echo '</select>'; + + // If selected teacher couldn't be displayed, select all teachers and save the new selection. + // In this case, no option item is marked as selected, but that's ok as the "all" item is at the top. + if (!$selectedteacherdisplayed) { + $selectedteacher = 'all'; + set_user_preference('block_course_overview_campus-selectedteacher', $selectedteacher); + } + + echo '</div>'; + } + + // End section. + echo '</div></div>'; + + // Show submit button for Non-JavaScript interaction. + echo '<div id="coc-filtersubmit" class="container-fluid mb-3"><div class="row"><input type="submit" value="'.get_string('submitfilter', 'block_course_overview_campus').'" class="btn btn-primary" /></div></div>'; + + // End form. + echo '</form>'; + } + + + + /********************************************************************************/ + /*** GENERATE OUTPUT FOR HIDDEN COURSES MANAGEMENT TOP BOX ***/ + /********************************************************************************/ + + // Do only if course hiding is enabled. + if ($coc_config->enablehidecourses) { + // If hidden courses managing is active, output hidden courses management top box as visible. + if ($param_manage == 1) { + echo '<div id="coc-hiddencoursesmanagement-top" class="container-fluid"><div class="row"><a href="'.$CFG->wwwroot.$PAGE->url->out_as_local_url(true, array('coc-manage' => 0)).'">'.get_string('stopmanaginghiddencourses', 'block_course_overview_campus').'</a></div></div>'; + } + } + + + + /********************************************************************************/ + /*** GENERATE OUTPUT FOR COURSELIST ***/ + /********************************************************************************/ + + // Start section. + echo '<div id="coc-courselist" class="container-fluid mb-3">'; + + // Show courses. + foreach ($courses as $c) { + // Remember course ID for JS processing. + $js_courseslist .= $c->id.' '; + + // Start course div. + echo '<div id="coc-course-'.$c->id.'" class="row coc-course">'; + + // Start hide course div - later we use this div to filter the course. + if ($coc_config->enablehidecourses == true && $param_manage == 0) { + // Show course if it is visible according to the hide courses feature. + if ($c->hidecourse == false) { + echo '<div class="hidecoursediv coc-hidecourse-'.$c->id.'">'; + } + // Otherwise hide the course with CSS. + else { + echo '<div class="hidecoursediv coc-hidecourse-'.$c->id.' coc-hidden">'; + } + } + + // Start filter by term div - later we use this div to filter the course. + if ($coc_config->termcoursefilter == true && $param_manage == 0) { + // Show course if it is visible according to the term course filter. + if ($c->termcoursefiltered == false) { + echo '<div class="termdiv coc-term-'.$c->term.'">'; + } + // Otherwise hide the course with CSS. + else { + echo '<div class="termdiv coc-term-'.$c->term.' coc-hidden">'; + } + } + + // Start filter by parent category div - later we use this div to filter the course. + if ($coc_config->categorycoursefilter == true && $param_manage == 0) { + // Show course if it is visible according to the parent category course filter. + if ($c->categorycoursefiltered == false) { + echo '<div class="categorydiv coc-category-'.$c->categoryid.'">'; + } + // Otherwise hide the course with CSS. + else { + echo '<div class="categorydiv coc-category-'.$c->categoryid.' coc-hidden">'; + } + } + + // Start filter by top level category div - later we use this div to filter the course. + if ($coc_config->toplevelcategorycoursefilter == true && $param_manage == 0) { + // Show course if it is visible according to the top level category course filter. + if ($c->toplevelcategorycoursefiltered == false) { + echo '<div class="toplevelcategorydiv coc-toplevelcategory-'.$c->toplevelcategoryid.'">'; + } + // Otherwise hide the course with CSS. + else { + echo '<div class="toplevelcategorydiv coc-toplevelcategory-'.$c->toplevelcategoryid.' coc-hidden">'; + } + } + + // Start filter by teacher div - later we use this div to filter the course. + if ($coc_config->teachercoursefilter == true && $param_manage == 0) { + // Start teacher div. + echo '<div class="teacherdiv'; + + // Add all teachers. + foreach ($c->teachers as $id => $t) { + echo ' coc-teacher-'.$id; + } + + // Show course if it is visible according to the teacher course filter. + if ($c->teachercoursefiltered == false) { + echo '">'; + } + // Otherwise hide the course with CSS. + else { + echo ' coc-hidden">'; + } + } + + + // Start standard course overview coursebox. + echo $OUTPUT->box_start('coursebox'); + + // Output course visibility control icons. + if ($coc_config->enablehidecourses) { + // If course is hidden. + if (block_course_overview_campus_course_hidden_by_hidecourses($c, 0) == false) { // We can't rely on $c->hidecourse here because otherwise the icon would always be t/show. + echo '<div class="hidecourseicon"> + <a href="'.$CFG->wwwroot.$PAGE->url->out_as_local_url(true, array('coc-manage' => $param_manage, 'coc-hidecourse' => $c->id, 'coc-showcourse' => '')).'" id="coc-hidecourseicon-'.$c->id.'" title="'.get_string('hidecourse', 'block_course_overview_campus').'">'.$OUTPUT->pix_icon('hide', get_string('hidecourse', 'block_course_overview_campus'), 'block_course_overview_campus').'</a> + <a href="'.$CFG->wwwroot.$PAGE->url->out_as_local_url(true, array('coc-manage' => $param_manage, 'coc-hidecourse' => '', 'coc-showcourse' => $c->id)).'" id="coc-showcourseicon-'.$c->id.'" class="coc-hidden" title="'.get_string('showcourse', 'block_course_overview_campus').'">'.$OUTPUT->pix_icon('show', get_string('showcourse', 'block_course_overview_campus'), 'block_course_overview_campus').'</a> + </div>'; + } + // If course is visible. + else { + echo '<div class="hidecourseicon"> + <a href="'.$CFG->wwwroot.$PAGE->url->out_as_local_url(true, array('coc-manage' => $param_manage, 'coc-hidecourse' => $c->id, 'coc-showcourse' => '')).'" id="coc-hidecourseicon-'.$c->id.'" class="coc-hidden" title="'.get_string('hidecourse', 'block_course_overview_campus').'">'.$OUTPUT->pix_icon('hide', get_string('hidecourse', 'block_course_overview_campus'), 'block_course_overview_campus').'</a> + <a href="'.$CFG->wwwroot.$PAGE->url->out_as_local_url(true, array('coc-manage' => $param_manage, 'coc-hidecourse' => '', 'coc-showcourse' => $c->id)).'" id="coc-showcourseicon-'.$c->id.'" title="'.get_string('showcourse', 'block_course_overview_campus').'">'.$OUTPUT->pix_icon('show', get_string('showcourse', 'block_course_overview_campus'), 'block_course_overview_campus').'</a> + </div>'; + } + } + + // Get course attributes for use with course link. + $attributes = array('title' => format_string($c->fullname)); + if (empty($c->visible)) { + $attributes['class'] = 'dimmed'; + } + + // Check if some meta info has to be displayed in addition to the course name. + if ($coc_config->secondrowshowshortname == true || + $coc_config->secondrowshowtermname == true || + $coc_config->secondrowshowcategoryname == true || + $coc_config->secondrowshowtoplevelcategoryname == true || + ($coc_config->secondrowshowteachername == true && count($c->teachers) > 0)) { + $meta = array(); + if ($coc_config->secondrowshowshortname == true) { + $meta[] = $c->shortname; + } + if ($coc_config->secondrowshowtermname == true) { + $meta[] = $c->termname; + } + if ($coc_config->secondrowshowcategoryname == true) { + $meta[] = $c->categoryname; + } + if ($coc_config->secondrowshowtoplevelcategoryname == true) { + $meta[] = $c->toplevelcategoryname; + } + if ($coc_config->secondrowshowteachername == true) { + // Get teachers' names for use with course link. + if (count($c->teachers) > 0) { + $teachernames = block_course_overview_campus_get_teachername_string($c->teachers); + $meta[] = $teachernames; + } else if (strlen(trim($coc_config->noteachertext)) > 0) { + $teachernames = format_string($coc_config->noteachertext); + $meta[] = $teachernames; + } + } + + // Create meta info code. + // Hide metainfo on phones if configured. + if ($coc_config->secondrowhideonphones == true) { + $metainfo = '<br /><span class="coc-metainfo hidden-phone hidden-sm-down">('.implode($meta, ' | ').')</span>'; // Class 'hidden-phone' is used for Bootstrapbase and will be ignored by Boost. + } + // Otherwise. + else { + $metainfo = '<br /><span class="coc-metainfo">('.implode($meta, ' | ').')</span>'; + } + } + else { + $metainfo = ''; + } + + // Output course link. + if ($coc_config->firstrowcoursename == 2) { + echo $OUTPUT->heading(html_writer::link(new moodle_url('/course/view.php', array('id' => $c->id)), $c->shortname.$metainfo, $attributes), 3); + } + else { + echo $OUTPUT->heading(html_writer::link(new moodle_url('/course/view.php', array('id' => $c->id)), format_string($c->fullname).$metainfo, $attributes), 3); + } + + + // End standard course overview coursebox. + echo $OUTPUT->box_end(); + + // End filter by term div. + if ($coc_config->termcoursefilter == true && $param_manage == 0) { + echo '</div>'; + } + + // End filter by parent category div. + if ($coc_config->categorycoursefilter == true && $param_manage == 0) { + echo '</div>'; + } + + // End filter by top level category div. + if ($coc_config->toplevelcategorycoursefilter == true && $param_manage == 0) { + echo '</div>'; + } + + // End filter by teacher div. + if ($coc_config->teachercoursefilter == true && $param_manage == 0) { + echo '</div>'; + } + + // End hide course div. + if ($coc_config->enablehidecourses == true && $param_manage == 0) { + echo '</div>'; + } + + // End course div. + echo '</div>'; + } + + // End section. + echo '</div>'; + + + + /********************************************************************************/ + /*** GENERATE OUTPUT FOR HIDDEN COURSES MANAGEMENT BOTTOM BOX ***/ + /********************************************************************************/ + + // Do only if course hiding is enabled. + if ($coc_config->enablehidecourses) { + // If hidden courses managing is active, output the box as visible. + if ($param_manage == 1) { + echo '<div id="coc-hiddencoursesmanagement-bottom" class="container-fluid"><div class="row"><a href="'.$CFG->wwwroot.$PAGE->url->out_as_local_url(true, array('coc-manage' => 0)).'">'.get_string('stopmanaginghiddencourses', 'block_course_overview_campus').'</a></div></div>'; + } + // If hidden courses managing is not active, but I have hidden courses, output the box as visible. + else if ($param_manage == 0 && $hiddencoursescounter > 0) { + echo '<div id="coc-hiddencoursesmanagement-bottom" class="container-fluid"><div class="row">'.get_string('youhave', 'block_course_overview_campus').' <span id="coc-hiddencoursescount">'.$hiddencoursescounter.'</span> '.get_string('hiddencourses', 'block_course_overview_campus').' | <a href="'.$CFG->wwwroot.$PAGE->url->out_as_local_url(true, array('coc-manage' => 1)).'">'.get_string('managehiddencourses', 'block_course_overview_campus').'</a></div></div>'; + } + // Otherwise output the box as hidden to appear via JS as soon as a course is hidden. + else { + echo '<div id="coc-hiddencoursesmanagement-bottom" class="container-fluid"><div class="row coc-hidden">'.get_string('youhave', 'block_course_overview_campus').' <span id="coc-hiddencoursescount">'.$hiddencoursescounter.'</span> '.get_string('hiddencourses', 'block_course_overview_campus').' | <a href="'.$CFG->wwwroot.$PAGE->url->out_as_local_url(true, array('coc-manage' => 1)).'">'.get_string('managehiddencourses', 'block_course_overview_campus').'</a></div></div>'; + } + } + + + + /********************************************************************************/ + /*** OUTPUT CONTENT ***/ + /********************************************************************************/ + + // Get and end output buffer. + $content = ob_get_contents(); + ob_end_clean(); + + + + /********************************************************************************/ + /*** AJAX MANAGEMENT ***/ + /********************************************************************************/ + + // Verify that course displaying parameters are updatable by AJAX. + foreach ($courses as $c) { + if ($coc_config->enablehidecourses) { + user_preference_allow_ajax_update('block_course_overview_campus-hidecourse-'.$c->id, PARAM_BOOL); + } + } + + // Verify that filter parameters are updatable by AJAX. + if ($coc_config->termcoursefilter == true) { + user_preference_allow_ajax_update('block_course_overview_campus-selectedterm', PARAM_ALPHANUMEXT); + } + if ($coc_config->teachercoursefilter == true) { + user_preference_allow_ajax_update('block_course_overview_campus-selectedteacher', PARAM_ALPHANUM); + } + if ($coc_config->categorycoursefilter == true) { + user_preference_allow_ajax_update('block_course_overview_campus-selectedcategory', PARAM_ALPHANUM); + } + if ($coc_config->toplevelcategorycoursefilter == true) { + user_preference_allow_ajax_update('block_course_overview_campus-selectedtoplevelcategory', PARAM_ALPHANUM); + } + + // Include JS for hiding courses with AJAX. + if ($coc_config->enablehidecourses) { + $js_hidecoursesoptions = [ + 'local_boostcoc' => block_course_overview_campus_check_local_boostcoc(), + 'courses' => trim($js_courseslist), + 'manage' => $param_manage, + ]; + $PAGE->requires->js_call_amd('block_course_overview_campus/hidecourse', 'initHideCourse', [$js_hidecoursesoptions]); + } + + // Include JS for filtering courses with AJAX. + if ($coc_config->teachercoursefilter == true || $coc_config->termcoursefilter == true || $coc_config->categorycoursefilter == true || $coc_config->toplevelcategorycoursefilter == true) { + $js_filteroptions = [ + 'local_boostcoc' => block_course_overview_campus_check_local_boostcoc(), + 'initialsettings' => [ + 'term' => (isset($selectedterm)) ? $selectedterm : '', + 'teacher' => (isset($selectedteacher)) ? $selectedteacher : '', + 'category' => (isset($selectedcategory)) ? $selectedcategory : '', + 'toplevelcategory' => (isset($selectedtoplevelcategory)) ? $selectedtoplevelcategory : '', + ], + ]; // Passing the initialsettings to the JS code is necessary for filtering the course list again when using browser 'back' button. + $PAGE->requires->js_call_amd('block_course_overview_campus/filter', 'initFilter', [$js_filteroptions]); + } + + + + /********************************************************************************/ + /*** LOCAL_BOOSTCOC ***/ + /********************************************************************************/ + + // Do only if local_boostcoc is installed. + if (block_course_overview_campus_check_local_boostcoc() == true) { + // Remember the not shown courses for local_boostcoc. + block_course_overview_campus_remember_notshowncourses_for_local_boostcoc($courses); + + // Verify that we can also remember the not shown courses for local_boostcoc by AJAX. + user_preference_allow_ajax_update('local_boostcoc-notshowncourses', PARAM_RAW); + + // Remember the active filters for local_boostcoc. + block_course_overview_campus_remember_activefilters_for_local_boostcoc($hiddencoursescounter); + + // Verify that we can also remember the active filters for local_boostcoc by AJAX. + user_preference_allow_ajax_update('local_boostcoc-activefilters', PARAM_RAW); + } + } + + + + /********************************************************************************/ + /*** OUTPUT AND RETURN ***/ + /********************************************************************************/ + + // Output content. + $this->content = new stdClass(); + + if (!empty($content)) { + $this->content->text = $content; + } else { + $this->content->text = ''; + } + + return $this->content; + } +} diff --git a/blocks/course_overview_campus/classes/privacy/provider.php b/blocks/course_overview_campus/classes/privacy/provider.php new file mode 100644 index 0000000000000000000000000000000000000000..a3ad017d2ea8c2a352fb746b753772cf608558a8 --- /dev/null +++ b/blocks/course_overview_campus/classes/privacy/provider.php @@ -0,0 +1,141 @@ +<?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/>. + +/** + * Block "course overview (campus)" - Privacy provider + * + * @package block_course_overview_campus + * @copyright 2018 Alexander Bias, Ulm University <alexander.bias@uni-ulm.de> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace block_course_overview_campus\privacy; + +use \core_privacy\local\request\writer; +use \core_privacy\local\metadata\collection; +use \core_privacy\local\request\transform; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Privacy Subsystem implementing provider. + * + * @package block_course_overview_campus + * @copyright 2018 Alexander Bias, Ulm University <alexander.bias@uni-ulm.de> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements \core_privacy\local\metadata\provider, + \core_privacy\local\request\user_preference_provider { + + /** + * Returns meta data about this system. + * + * @param collection $collection The initialised item collection to add items to. + * @return collection A listing of user data stored through this system. + */ + public static function get_metadata(collection $collection) : collection { + $collection->add_user_preference('block_course_overview_campus-selectedterm', + 'privacy:metadata:preference:selectedterm'); + $collection->add_user_preference('block_course_overview_campus-selectedteacher', + 'privacy:metadata:preference:selectedteacher'); + $collection->add_user_preference('block_course_overview_campus-selectedcategory', + 'privacy:metadata:preference:selectedcategory'); + $collection->add_user_preference('block_course_overview_campus-selectedtoplevelcategory', + 'privacy:metadata:preference:selectedtoplevelcategory'); + $collection->add_user_preference('block_course_overview_campus-hidecourse-', + 'privacy:metadata:preference:hidecourse'); + $collection->add_user_preference('local_boostcoc-notshowncourses', + 'privacy:metadata:preference:local_boostcoc-notshowncourses'); + $collection->add_user_preference('local_boostcoc-activefilters', + 'privacy:metadata:preference:local_boostcoc-activefilters'); + + return $collection; + } + + /** + * Store all user preferences for the plugin. + * + * @param int $userid The userid of the user whose data is to be exported. + */ + public static function export_user_preferences(int $userid) { + $preferences = get_user_preferences(); + foreach ($preferences as $name => $value) { + $descriptionidentifier = null; + + // User preferences for filters. + if (strpos($name, 'block_course_overview_campus-selected') === 0) { + if ($name == 'block_course_overview_campus-selectedterm') { + $descriptionidentifier = 'privacy:request:preference:selectedterm'; + } else if ($name == 'block_course_overview_campus-selectedteacher') { + $descriptionidentifier = 'privacy:request:preference:selectedteacher'; + } else if ($name == 'block_course_overview_campus-selectedcategory') { + $descriptionidentifier = 'privacy:request:preference:selectedcategory'; + } else if ($name == 'block_course_overview_campus-selectedtoplevelcategory') { + $descriptionidentifier = 'privacy:request:preference:selectedtoplevelcategory'; + } + + if ($descriptionidentifier !== null) { + writer::export_user_preference( + 'block_course_overview_campus', + $name, + $value, + get_string($descriptionidentifier, 'block_course_overview_campus', (object) [ + 'value' => $value, + ]) + ); + } + + // User preferences for hiding stuff. + } else if (strpos($name, 'block_course_overview_campus-hide') === 0) { + if (strpos($name, 'block_course_overview_campus-hidecourse-') === 0) { + $descriptionidentifier = 'privacy:request:preference:hidecourse'; + $item = substr($name, strlen('block_course_overview_campus-hidecourse-')); + } + + if ($descriptionidentifier !== null) { + writer::export_user_preference( + 'block_course_overview_campus', + $name, + $value, + get_string($descriptionidentifier, 'block_course_overview_campus', (object) [ + 'item' => $item, + 'value' => $value, + ]) + ); + } + + // User preferences for local_boostcoc. + } else if (strpos($name, 'local_boostcoc-') === 0) { + if ($name == 'local_boostcoc-notshowncourses') { + $descriptionidentifier = 'privacy:request:preference:local_boostcoc-notshowncourses'; + } else if ($name == 'local_boostcoc-activefilters') { + $descriptionidentifier = 'privacy:request:preference:local_boostcoc-activefilters'; + } + + if ($descriptionidentifier !== null) { + writer::export_user_preference( + 'block_course_overview_campus', + $name, + $value, + get_string($descriptionidentifier, 'block_course_overview_campus', (object) [ + 'value' => $value, + ]) + ); + } + } + } + } +} diff --git a/blocks/course_overview_campus/db/access.php b/blocks/course_overview_campus/db/access.php new file mode 100644 index 0000000000000000000000000000000000000000..9a464c8d8208c4933d702ebdfcf28a13df259c4d --- /dev/null +++ b/blocks/course_overview_campus/db/access.php @@ -0,0 +1,46 @@ +<?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/>. + +/** + * Block "course overview (campus)" - Capabilities + * + * @package block_course_overview_campus + * @copyright 2013 Alexander Bias, Ulm University <alexander.bias@uni-ulm.de> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$capabilities = array( + 'block/course_overview_campus:myaddinstance' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_SYSTEM, + 'archetypes' => array( + 'user' => CAP_ALLOW + ), + 'clonepermissionsfrom' => 'moodle/my:manageblocks' + ), + 'block/course_overview_campus: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/course_overview_campus/db/uninstall.php b/blocks/course_overview_campus/db/uninstall.php new file mode 100644 index 0000000000000000000000000000000000000000..3f9c93d0c34a2a16328d10be0a6bcb3f4d9c81f3 --- /dev/null +++ b/blocks/course_overview_campus/db/uninstall.php @@ -0,0 +1,48 @@ +<?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/>. + +/** + * Block "course overview (campus)" - Uninstall file + * + * @package block_course_overview_campus + * @copyright 2019 Alexander Bias, Ulm University <alexander.bias@uni-ulm.de> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * Plugin uninstall steps. + */ +function xmldb_block_course_overview_campus_uninstall() { + global $DB; + + // The plugin uninstall process in Moodle core will take care of removing the plugin configuration, but not of removing the + // user preferences which we have set for the users. We have to remove them ourselves. + // We remove them directly from the DB table and don't use unset_user_preference() as the cache is cleared anyway directly + // after the plugin has been uninstalled. + + $like = $DB->sql_like('name', '?', true, true, false, '|'); + $params = array($DB->sql_like_escape('block_course_overview_campus-', '|') . '%'); + $DB->delete_records_select('user_preferences', $like, $params); + + $like = $DB->sql_like('name', '?', true, true, false, '|'); + $params = array($DB->sql_like_escape('local_boostcoc-', '|') . '%'); + $DB->delete_records_select('user_preferences', $like, $params); + + return true; +} + diff --git a/blocks/course_overview_campus/db/upgrade.php b/blocks/course_overview_campus/db/upgrade.php new file mode 100644 index 0000000000000000000000000000000000000000..9eea2a3eb2b61ba22c6a1c43fc50891e3f69362c --- /dev/null +++ b/blocks/course_overview_campus/db/upgrade.php @@ -0,0 +1,49 @@ +<?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/>. + +/** + * Block "course overview (campus)" - Upgrade script + * + * @package block_course_overview_campus + * @copyright 2019 Alexander Bias, Ulm University <alexander.bias@uni-ulm.de> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * Function to upgrade block_course_overview_campus. + * @param int $oldversion the version we are upgrading from + * @return bool result + */ +function xmldb_block_course_overview_campus_upgrade($oldversion) { + global $DB; + + if ($oldversion < 2019061200) { + // After the course news functionality has been removed from the plugin, the user preferences have to be removed manually. + // We remove them directly from the DB table and don't use unset_user_preference() as the cache is cleared anyway directly + // after the plugin has been uninstalled. + + $like = $DB->sql_like('name', '?', true, true, false, '|'); + $params = array($DB->sql_like_escape('block_course_overview_campus-hidenews-', '|') . '%'); + $DB->delete_records_select('user_preferences', $like, $params); + + upgrade_plugin_savepoint(true, 2019061200, 'block', 'course_overview_campus'); + } + + return true; +} + diff --git a/blocks/course_overview_campus/lang/en/block_course_overview_campus.php b/blocks/course_overview_campus/lang/en/block_course_overview_campus.php new file mode 100644 index 0000000000000000000000000000000000000000..6b74ccf1150ade8d1c9221ba9b2c2fff5685e5a3 --- /dev/null +++ b/blocks/course_overview_campus/lang/en/block_course_overview_campus.php @@ -0,0 +1,181 @@ +<?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/>. + +/** + * Block "course overview (campus)" - Language pack + * + * @package block_course_overview_campus + * @copyright 2013 Alexander Bias, Ulm University <alexander.bias@uni-ulm.de> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$string['academicyear_desc'] = 'Academic year (Calendar year is not divided)'; +$string['activityoverview'] = 'You have {$a}s that need attention'; +$string['all'] = 'All'; +$string['appearancesettingheading'] = 'Appearance'; +$string['blocktitle'] = 'Block title'; +$string['blocktitle_desc'] = 'This display name is shown as the title of the block'; +$string['blocktitledefault'] = 'Course overview'; +$string['category'] = 'Parent category'; +$string['categorycoursefilter'] = 'Activate parent category filter'; +$string['categorycoursefilter_desc'] = 'Allow users to filter courses by parent category'; +$string['categorycoursefilterdisplayname'] = 'Display name for parent category filter'; +$string['categorycoursefilterdisplayname_desc'] = 'This display name is shown above the parent category filter<br /><em>This setting is only processed when the parent category filter is activated</em>'; +$string['categorycoursefiltersettingheading'] = 'Parent category filter: Filter activation'; +$string['course_overview_campus:addinstance'] = 'Add a new course overview campus block'; +$string['course_overview_campus:myaddinstance'] = 'Add a new course overview campus block to Dashboard'; +$string['defaultterm'] = 'Use default term'; +$string['defaultterm_desc'] = 'If the user has not previously selected a term for filtering terms, a term is chosen for him. The first choice is the current term. If the user is not enrolled on any courses in the current term, the most recent previous term is chosen.<br /><em>This setting is only processed when the term filter is activated</em>'; +$string['enablehidecourses'] = 'Enable course hiding'; +$string['enablehidecourses_desc'] = 'Enable course hiding, which lets users hide courses from the course overview list'; +$string['firstrowcoursename'] = 'First row: Course name style'; +$string['firstrowcoursename_desc'] = 'Show the course\'s full name or the course\'s short name in the first row of the course overview list entry'; +$string['hiddencourses'] = 'hidden courses'; +$string['hidecourse'] = 'Hide course in course overview list'; +$string['hidecoursessettingheading'] = 'Hide courses'; +$string['listentriessettingheading'] = 'Course overview list: Entries'; +$string['managehiddencourses'] = 'Manage hidden courses'; +$string['mergehomonymouscategories'] = 'Merge homonymous parent categories'; +$string['mergehomonymouscategories_desc'] = 'If there are multiple courses with different parent categories, but with the same parent category name, the parent category filter will be filled with multiple categories with the same name by default. This can be confusing to the user. If you want to merge all homonymous parent categories into one filter entry when using the parent category filter, activate this setting<br /><em>This setting is only processed when the parent category filter is activated</em>'; +$string['mergehomonymouscategoriessettingheading'] = 'Parent category filter: Merge homonymous parent categories'; +$string['nocourses'] = 'Currently, you are not enrolled in any courses'; +$string['noteacher'] = 'No teacher enrolled'; +$string['noteachertext'] = 'No teacher enrolled text'; +$string['noteachertext_desc'] = 'This text is displayed instead of the teachers\' names if there is no teacher enrolled in the course. If you don\'t want a placeholder text to appear, just delete this text here<br /><em>This setting is only processed when show teacher name is activated</em>'; +$string['ordersettingheading'] = 'Course overview list: Order'; +$string['other'] = 'Other'; +$string['pluginname'] = 'Course overview on campus'; +$string['prioritizemyteachedcourses'] = 'Prioritize courses in which I teach'; +$string['prioritizemyteachedcourses_desc'] = 'Courses in which the user has a teacher role are listed first in course overview list'; +$string['privacy:metadata:preference:selectedterm'] = 'The current selection of the term filter.'; +$string['privacy:metadata:preference:selectedteacher'] = 'The current selection of the teacher filter.'; +$string['privacy:metadata:preference:selectedcategory'] = 'The current selection of the parent category filter.'; +$string['privacy:metadata:preference:selectedtoplevelcategory'] = 'The current selection of the top level category filter.'; +$string['privacy:metadata:preference:hidecourse'] = 'The show/hide status of a course in the course overview list.'; +$string['privacy:metadata:preference:local_boostcoc-notshowncourses'] = 'The list of currently not shown courses to be used in the companion plugin \'Boost course overview campus\'.'; +$string['privacy:metadata:preference:local_boostcoc-activefilters'] = 'The list of currently active filters to be used in the companion plugin \'Boost course overview campus\'.'; +$string['privacy:request:preference:selectedterm'] = 'The current selection of the term filter is: {$a->value}.'; +$string['privacy:request:preference:selectedteacher'] = 'The current selection of the teacher filter is: {$a->value}.'; +$string['privacy:request:preference:selectedcategory'] = 'The current selection of the parent category filter is: {$a->value}.'; +$string['privacy:request:preference:selectedtoplevelcategory'] = 'The current selection of the top level category filter is: {$a->value}.'; +$string['privacy:request:preference:hidecourse'] = 'The show/hide status of the course {$a->item} in the course overview list is: {$a->value}.'; +$string['privacy:request:preference:local_boostcoc-notshowncourses'] = 'The list of currently not shown courses to be used in the companion plugin \'Boost course overview campus\' is: {$a->value}.'; +$string['privacy:request:preference:local_boostcoc-activefilters'] = 'The list of currently active filters to be used in the companion plugin \'Boost course overview campus\' is: {$a->value}.'; +$string['secondrowhideonphones'] = 'Second row: Hide on phones'; +$string['secondrowhideonphones_desc'] = 'Hide the second row on mobile phones to save space'; +$string['secondrowshowcategoryname'] = 'Second row: Show parent category name'; +$string['secondrowshowcategoryname_desc'] = 'Show the course\'s parent category name in a second row of the course overview list entry'; +$string['secondrowshowshortname'] = 'Second row: Show short name'; +$string['secondrowshowshortname_desc'] = 'Show the course\'s short name in a second row of the course overview list entry'; +$string['secondrowshowteachername'] = 'Second row: Show teacher name'; +$string['secondrowshowteachername_desc'] = 'Show the teacher\'s name(s) in a second row of the course overview list entry. If there is more then one teacher, the names will be sorted first by the <a href="/admin/roles/manage.php">global order of roles</a> and second by the teachers\' last names'; +$string['secondrowshowteachernamestyle'] = 'Second row: Style of teacher name'; +$string['secondrowshowteachernamestyle_desc'] = 'Define how the teacher\'s name should be displayed in the second row of the course overview list entry<br /><em>This setting is only processed when show teacher name is activated</em>'; +$string['secondrowshowtermname'] = 'Second row: Show term name'; +$string['secondrowshowtermname_desc'] = 'Show the course\'s term name in a second row of the course overview list entry'; +$string['secondrowshowtoplevelcategoryname'] = 'Second row: Show top level category name'; +$string['secondrowshowtoplevelcategoryname_desc'] = 'Show the course\'s top level category name in a second row of the course overview list entry'; +$string['semester_desc'] = 'Semester (Calendar year is divided into two terms)'; +$string['settingspage_general'] = 'General'; +$string['settingspage_courseoverviewlist'] = 'Course overview list'; +$string['settingspage_hidecourses'] = 'Hide courses'; +$string['settingspage_teacherroles'] = 'Teacher roles'; +$string['settingspage_categoryfilter'] = 'Parent category filter'; +$string['settingspage_toplevelcategoryfilter'] = 'Top level category filter'; +$string['settingspage_teacherfilter'] = 'Teacher filter'; +$string['settingspage_termfilter'] = 'Term filter'; +$string['showcourse'] = 'Show course'; +$string['stopmanaginghiddencourses'] = 'Stop managing hidden courses'; +$string['submitfilter'] = 'Filter my courses!'; +$string['teachercoursefilter'] = 'Activate teacher filter'; +$string['teachercoursefilter_desc'] = 'Allow users to filter courses by teacher'; +$string['teachercoursefilterdisplayname'] = 'Display name for teacher filter'; +$string['teachercoursefilterdisplayname_desc'] = 'This display name is shown above the teacher filter<br /><em>This setting is only processed when the teacher filter is activated</em>'; +$string['teachercoursefiltersettingheading'] = 'Teacher filter: Filter activation'; +$string['teachernamestylefullname'] = 'Firstname Lastname'; +$string['teachernamestylefirstname'] = 'Firstname'; +$string['teachernamestylelastname'] = 'Lastname'; +$string['teachernamestylefullnamedisplay'] = 'Teacher name style according to Moodle core setting "fullnamedisplay</em>" (Currently set to "{$a}")'; +$string['teacherrolessettingheading'] = 'Teacher roles'; +$string['teacherroles'] = 'Teacher roles'; +$string['teacherroles_desc'] = 'Define which roles are handled as teacher roles by this plugin<br /><em>This setting is only processed when show teacher name is activated or when the teacher filter is activated or when the priorization of courses in which I teach is activated</em>'; +$string['teacherroleshidesuspended'] = 'Hide suspended teachers'; +$string['teacherroleshidesuspended_desc'] = 'When looking for teachers with the specified teacher roles, do not only check if a teacher has one of the given roles in a course, but also check if his enrolment into the course is active (i.e. the teacher\'s enrolment in the course is not suspended + the current date is within the start and end dates of the teacher\'s enrolment + the enrolment method of the teacher\'s enrolment is enabled in the course). Teachers whose enrolment in a course is not active will not be considered as teacher for this course.<br /><em>This setting is only processed when show teacher name is activated or when the teacher filter is activated.</em><br /><em>Warning: If you enable this setting, the load on the database to create the list of courses will slightly increase due to the necessary additional checks. Thus, enable this setting only if you need to.</em>'; +$string['teacherrolesparent'] = 'Include parent context teacher roles'; +$string['teacherrolesparent_desc'] = 'When looking for teachers with the specified teacher roles, include teachers who have their role assigned in parent contexts (course category or system level)<br /><em>This setting is only processed when show teacher name is activated or when the teacher filter is activated.</em><br /><em>Warning: If you set this to "No" or "Depending on the user\'s moodle/course:reviewotherusers capability", the "Prioritize courses in which I teach" function will also be influenced and will not priorize courses where the user has his teacher role assigned in parent contexts.</em>'; +$string['teacherrolesparentcapability'] = 'Depending on the user\'s moodle/course:reviewotherusers capability'; +$string['term'] = 'Term'; +$string['term1'] = 'Term 1'; +$string['term1name'] = 'Term 1 name'; +$string['term1name_desc'] = 'Descriptive name for term 1, please rename it according to your campus terminology (or leave it empty if you want to use only year numbes in Academic year mode)<br /><em>This setting is only processed when the term filter is activated</em>'; +$string['term1startday'] = 'Term 1 start day'; +$string['term1startday_desc'] = 'Day and month when term 1 starts<br /><em>This setting is only processed when the term filter is activated</em>'; +$string['term2'] = 'Term 2'; +$string['term2name'] = 'Term 2 name'; +$string['term2name_desc'] = 'Descriptive name for term 2, please rename it according to your campus terminology<br /><em>This setting is only processed when the term filter is activated and when term mode is set to "Semester", "Tertial" or "Trimester"</em>'; +$string['term2startday'] = 'Term 2 start day'; +$string['term2startday_desc'] = 'Day and month when term 2 starts<br /><em>This setting is only processed when the term filter is activated and when term mode is set to "Semester", "Tertial" or "Trimester"</em>'; +$string['term3'] = 'Term 3'; +$string['term3name'] = 'Term 3 name'; +$string['term3name_desc'] = 'Descriptive name for term 3, please rename it according to your campus terminology<br /><em>This setting is only processed when the term filter is activated and when term mode is set to "Tertial" or "Trimester"</em>'; +$string['term3startday'] = 'Term 3 start day'; +$string['term3startday_desc'] = 'Day and month when term 3 starts<br /><em>This setting is only processed when the term filter is activated and when term mode is set to "Tertial" or "Trimester"</em>'; +$string['term4'] = 'Term 4'; +$string['term4name'] = 'Term 4 name'; +$string['term4name_desc'] = 'Descriptive name for term 4, please rename it according to your campus terminology<br /><em>This setting is only processed when the term filter is activated and when term mode is set to "Trimester"</em>'; +$string['term4startday'] = 'Term 4 start day'; +$string['term4startday_desc'] = 'Day and month when term 4 starts<br /><em>This setting is only processed when the term filter is activated and when term mode is set to "Trimester"</em>'; +$string['termbehavioursettingheading'] = 'Term filter: Term behaviour'; +$string['termcoursefilter'] = 'Activate term filter'; +$string['termcoursefilter_desc'] = 'Allow users to filter courses by term'; +$string['termcoursefilterdisplayname'] = 'Display name for term filter'; +$string['termcoursefilterdisplayname_desc'] = 'This display name is shown above the term filter<br /><em>This setting is only processed when the term filter is activated</em>'; +$string['termcoursefiltersettingheading'] = 'Term filter: Filter activation'; +$string['termmode'] = 'Term mode'; +$string['termmode_desc'] = 'Set the term mode for the term filter<br /><em>This setting is only processed when the term filter is activated</em>'; +$string['termnamesettingheading'] = 'Term filter: Term names'; +$string['termsettingerror'] = 'The configured term dates don\'t make sense. Please verify that term 2 starts after term 1 and so on. Term filter will not be available to users until you fix this.'; +$string['termsettingheading'] = 'Term filter: Term definition'; +$string['termyearpos'] = 'Term name year position'; +$string['termyearpos_desc'] = 'Define if the term\'s year should be added as suffix or prefix to the term name<br /><em>This setting is only processed when the term filter is activated</em>'; +$string['termyearposprefixspace_desc'] = 'Year is added as prefix to the term name with space (Example: "2013 Summer term")'; +$string['termyearposprefixnospace_desc'] = 'Year is added as prefix to the term name without space (Example: "2013S")'; +$string['termyearpossuffixspace_desc'] = 'Year is added as suffix to the term name with space (Example: "Summer term 2013")'; +$string['termyearpossuffixnospace_desc'] = 'Year is added as suffix to the term name without space (Example: "S2013")'; +$string['termyearseparation'] = 'Term name second year separation'; +$string['termyearseparation_desc'] = 'If the timespan of the term includes New Year\'s day, define how this second year should be separated from the first one<br /><em>This setting is only processed when the term filter is activated</em>'; +$string['termyearseparationhyphen_desc'] = 'Separate with a hyphen (Example: "2013-2014")'; +$string['termyearseparationslash_desc'] = 'Separate with a slash (Example: "2013/2014")'; +$string['termyearseparationunderscore_desc'] = 'Separate with a underscore (Example: "2013_2014")'; +$string['termyearseparationnosecondyear_desc'] = 'Don\'t add the second year (Example: "2013")'; +$string['tertial_desc'] = 'Tertial (Calendar year is divided into three terms)'; +$string['timelesscourses'] = 'Timeless courses'; +$string['timelesscourses_desc'] = 'Enable support for timeless courses in the term filter. Timeless courses seem to be not associated to a specific term<br /><em>This setting is only processed when the term filter is activated</em>'; +$string['timelesscoursesname'] = 'Display name for timeless courses'; +$string['timelesscoursesname_desc'] = 'This display name is shown in the term filter for courses which are timeless<br /><em>This setting is only processed when the term filter is activated and when timeless courses are activated</em>'; +$string['timelesscoursessettingheading'] = 'Term filter: Timeless courses'; +$string['timelesscoursesthreshold'] = 'Timeless courses threshold'; +$string['timelesscoursesthreshold_desc'] = 'Define courses with a start year before (and not equal to) this year as timeless courses<br /><em>This setting is only processed when the term filter is activated and when timeless courses are activated</em>'; +$string['toplevelcategory'] = 'Top level category'; +$string['toplevelcategorycoursefilter'] = 'Activate top level category filter'; +$string['toplevelcategorycoursefilter_desc'] = 'Allow users to filter courses by top level category'; +$string['toplevelcategorycoursefilterdisplayname'] = 'Display name for top level category filter'; +$string['toplevelcategorycoursefilterdisplayname_desc'] = 'This display name is shown above the top level category filter<br /><em>This setting is only processed when the top level category filter is activated</em>'; +$string['toplevelcategorycoursefiltersettingheading'] = 'Top level category filter: Filter activation'; +$string['trimester_desc'] = 'Trimester (Calendar year is divided into four terms)'; +$string['youhave'] = 'You have'; diff --git a/blocks/course_overview_campus/lib.php b/blocks/course_overview_campus/lib.php new file mode 100644 index 0000000000000000000000000000000000000000..cd4a0727635c274154a01f5cd5fafebb8a365edd --- /dev/null +++ b/blocks/course_overview_campus/lib.php @@ -0,0 +1,37 @@ +<?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/>. + +/** + * Block "course overview (campus)" - library + * + * @package block_course_overview_campus + * @copyright 2013 Alexander Bias, Ulm University <alexander.bias@uni-ulm.de> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * Get icon mapping for font-awesome. + */ +function block_course_overview_campus_get_fontawesome_icon_map() { + return [ + 'block_course_overview_campus:expanded' => 'fa-minus-square', + 'block_course_overview_campus:collapsed' => 'fa-plus-square', + 'block_course_overview_campus:hide' => 'fa-toggle-on fa-lg', + 'block_course_overview_campus:show' => 'fa-toggle-off fa-lg', + ]; +} diff --git a/blocks/course_overview_campus/locallib.php b/blocks/course_overview_campus/locallib.php new file mode 100644 index 0000000000000000000000000000000000000000..e71426550d7e507865e90b8d3f8c90c2e1e646f1 --- /dev/null +++ b/blocks/course_overview_campus/locallib.php @@ -0,0 +1,448 @@ +<?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/>. + +/** + * Block "course overview (campus)" - Local library + * + * @package block_course_overview_campus + * @copyright 2013 Alexander Bias, Ulm University <alexander.bias@uni-ulm.de> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +// @codingStandardsIgnoreFile +// Let codechecker ignore this file. This legacy code is not fully compliant to Moodle coding style but working and well documented. + +/** + * Get my courses from DB + * + * @return array + */ +function block_course_overview_campus_get_my_courses() { + // Get my courses in alphabetical order. + $courses = enrol_get_my_courses('id, shortname', 'fullname ASC'); + + // Remove frontpage course, if enrolled, from courses list. + $site = get_site(); + if (array_key_exists($site->id, $courses)) { + unset($courses[$site->id]); + } + + return $courses; +} + + +/** + * Check if course is hidden according to the hide courses feature + * + * @param course $course + * @return boolean + */ +function block_course_overview_campus_course_hidden_by_hidecourses($course) { + // Course is visible if it isn't hidden. + if (get_user_preferences('block_course_overview_campus-hidecourse-'.$course->id, 0) == 0) { + return false; + + // Otherwise it is hidden. + } else { + return true; + } +} + + +/** + * Check if course is hidden according to the term course filter + * + * @param course $course + * @param string $selectedterm + * @return boolean + */ +function block_course_overview_campus_course_hidden_by_termcoursefilter($course, $selectedterm) { + // Course is visible if it is within selected term or all terms are selected. + if ($course->term == $selectedterm || $selectedterm == 'all') { + return false; + + // Otherwise it is hidden. + } else { + return true; + } +} + + +/** + * Check if course is hidden according to the parent category course filter + * + * @param course $course + * @param string $selectedcategory + * @return boolean + */ +function block_course_overview_campus_course_hidden_by_categorycoursefilter($course, $selectedcategory) { + // Course is visible if it is within selected parent category or all categories are selected. + if ($course->categoryid == $selectedcategory || $selectedcategory == 'all') { + return false; + + // Otherwise it is hidden. + } else { + return true; + } +} + + +/** + * Check if course is hidden according to the top level category course filter + * + * @param course $course + * @param string $selectedtoplevelcategory + * @return boolean + */ +function block_course_overview_campus_course_hidden_by_toplevelcategorycoursefilter($course, $selectedtoplevelcategory) { + // Course is visible if it is within selected top level category or all categories are selected. + if ($course->toplevelcategoryid == $selectedtoplevelcategory || $selectedtoplevelcategory == 'all') { + return false; + + // Otherwise it is hidden. + } else { + return true; + } +} + + +/** + * Check if course is visible according to the teacher course filter + * + * @param course $course + * @param string $selectedteacher + * @return boolean + */ +function block_course_overview_campus_course_hidden_by_teachercoursefilter($course, $selectedteacher) { + // Course is visible if it has the selected teacher or all teachers are selected. + if (isset($course->teachers[$selectedteacher]) || $selectedteacher == 'all') { + return false; + + // Otherwise it is hidden. + } else { + return true; + } +} + + +/** + * Check if course is hidden according to any (preprocessed!) filter + * + * @param course $course + * @return boolean + */ +function block_course_overview_campus_course_hidden_by_anyfilter($course) { + // Check if there is any reason to hide the course. + $hidecourse = (isset($course->termcoursefiltered) && $course->termcoursefiltered) || + (isset($course->categorycoursefiltered) && $course->categorycoursefiltered == true) || + (isset($course->toplevelcategorycoursefiltered) && $course->toplevelcategorycoursefiltered == true) || + (isset($course->teachercoursefiltered) && $course->teachercoursefiltered == true); + + return $hidecourse; +} + + +/** + * Check if the configured term dates make sense + * + * @return bool + */ +function block_course_overview_campus_check_term_config() { + $coc_config = get_config('block_course_overview_campus'); + + if ($coc_config->termmode == 1) { + return true; + } else if ($coc_config->termmode == 2 && + intval(date('z', strtotime('2003-'.$coc_config->term1startday))) < + intval(date('z', strtotime('2003-'.$coc_config->term2startday)))) { + return true; + } else if ($coc_config->termmode == 3 && + intval(date('z', strtotime('2003-'.$coc_config->term1startday))) < + intval(date('z', strtotime('2003-'.$coc_config->term2startday))) && + intval(date('z', strtotime('2003-'.$coc_config->term2startday))) < + intval(date('z', strtotime('2003-'.$coc_config->term3startday)))) { + return true; + } else if ($coc_config->termmode == 4 && + intval(date('z', strtotime('2003-'.$coc_config->term1startday))) < + intval(date('z', strtotime('2003-'.$coc_config->term2startday))) && + intval(date('z', strtotime('2003-'.$coc_config->term2startday))) < + intval(date('z', strtotime('2003-'.$coc_config->term3startday))) && + intval(date('z', strtotime('2003-'.$coc_config->term3startday))) < + intval(date('z', strtotime('2003-'.$coc_config->term4startday)))) { + return true; + } else { + return false; + } +} + + +/** + * Take array of teacher objects and return a string of names, sorted by relevance and name + * + * @param array $teachers array of teachers + * @return string string with concatenated teacher names + */ +function block_course_overview_campus_get_teachername_string($teachers) { + $coc_config = get_config('block_course_overview_campus'); + + // If given array is empty, return empty string. + if (empty($teachers)) { + return ''; + } + + // Sort all teachers by relevance and name, return empty string when sorting fails. + $success = usort($teachers, "block_course_overview_campus_compare_teachers"); + if (!$success) { + return ''; + } + + // Get all teachers' names as an array according the teacher name style setting. + $teachernames = array_map(function($obj) { + global $coc_config; + + // Display fullname. + if ($coc_config->secondrowshowteachernamestyle == 1) { + return $obj->firstname.' '.$obj->lastname; + } + // Display lastname. + else if ($coc_config->secondrowshowteachernamestyle == 2) { + return $obj->lastname; + } + // Display firstname. + else if ($coc_config->secondrowshowteachernamestyle == 3) { + return $obj->firstname; + } + // Display fullnamedisplay. + else if ($coc_config->secondrowshowteachernamestyle == 4) { + return fullname($obj); + } + // Fallback: Display lastname. + else { + return $obj->lastname; + } + }, $teachers); + + // Implode teachers' names to a single string. + $teachernames = implode(", ", $teachernames); + + return $teachernames; +} + + +/** + * Take term name and year(s) and return displayname for term filter based on plugin configuration + * + * @param string $termname The term's name + * @param string $year The term's year + * @param string $year2 The term's second year (optional) + * @return string String with the term's displayname + */ +function block_course_overview_campus_get_term_displayname($termname, $year, $year2='') { + $coc_config = get_config('block_course_overview_campus'); + + // Build the first year - second year combination. + $displayname = $year; + if ($year2 != '') { + // Hyphen separation. + if ($coc_config->termyearseparation == 1) { + $displayname = $year.'-'.$year2; + } + // Slash separation. + else if ($coc_config->termyearseparation == 2) { + $displayname = $year.'/'.$year2; + } + // Underscore separation. + else if ($coc_config->termyearseparation == 3) { + $displayname = $year.'_'.$year2; + } + // No second year. + else if ($coc_config->termyearseparation == 4) { + $displayname = $year; + } + // This shouldn't happen. + else { + $displayname = $year.'/'.$year2; + } + } + + // Add the term name. + // Prefix with space. + if ($coc_config->termyearpos == 1) { + $displayname = $displayname.' '.$termname; + } + // Prefix without space. + else if ($coc_config->termyearpos == 2) { + $displayname = $displayname.$termname; + } + // Suffix with space. + else if ($coc_config->termyearpos == 3) { + $displayname = $termname.' '.$displayname; + } + // Suffix without space. + else if ($coc_config->termyearpos == 4) { + $displayname = $termname.$displayname; + } + // This shouldn't happen. + else { + $displayname = $termname. ' '.$termname; + } + + return $displayname; +} + + +/** + * Compare teacher by relevance helper function + * + * @param object $a Teacher A + * @param object $b Teacher B + * @return int + */ +function block_course_overview_campus_compare_teachers($a, $b) { + // Compare relevance of teachers' roles. + if ($a->sortorder < $b->sortorder) { + return -1; + } else if ($a->sortorder > $b->sortorder) { + return 1; + } else if ($a->sortorder == $b->sortorder) { + // Teachers' roles are equal, then compare lastnames. + return strcasecmp($a->lastname, $b->lastname); + } else { + // This should never happen. + return 0; + } +} + + +/** + * Compare category by sortorder helper function + * + * @param object $a Category A + * @param object $b Category B + * @return int + */ +function block_course_overview_campus_compare_categories($a, $b) { + // Compare sortorder of categories. + if ($a->sortorder < $b->sortorder) { + return -1; + } else if ($a->sortorder > $b->sortorder) { + return 1; + } else if ($a->sortorder == $b->sortorder) { + // Category sortorders are equal - this shouldn't happen, but if it does then compare category names alphabetically. + return strcasecmp(format_string($a->name), format_string($b->name)); + } else { + // This should never happen. + return 0; + } +} + + +/** + * Remember the not shown courses for local_boostcoc + * + * Basically, this is remembered by the JavaScript filters directly when they are applied in the browser, but we want a fallback + * when javascript is off + * Unfortunately, at page load local_boostcoc can only change the nav drawer _before_ this function can store its data, thus the + * fallback when javascript is off has a lag. + * + * @param array $courses + */ +function block_course_overview_campus_remember_notshowncourses_for_local_boostcoc($courses) { + // Do only if local_boostcoc is installed. + if (block_course_overview_campus_check_local_boostcoc() == true) { + // Get all courses which are not shown (because they are hidden by any filter or by the hide courses feature) + // and store their IDs in an array. + $notshowncourses = array(); + foreach ($courses as $c) { + if ((block_course_overview_campus_course_hidden_by_anyfilter($c) == true || + block_course_overview_campus_course_hidden_by_hidecourses($c)) == true) { + $notshowncourses[] = $c->id; + } + } + + // Convert not shown courses array to JSON. + $jsonstring = json_encode($notshowncourses); + + // Store the current status of not shown courses. + set_user_preference('local_boostcoc-notshowncourses', $jsonstring); + } +} + + +/** + * Remember the active filters for local_boostcoc + * + * Basically, this is remembered by the JavaScript filters directly when they are applied in the browser, but we want a fallback + * when javascript is off. + * Unfortunately, at page load local_boostcoc can only change the nav drawer _before_ this function can store its data, thus the + * fallback when javascript is off has a lag. + * + * @param int $hiddencoursescounter + */ +function block_course_overview_campus_remember_activefilters_for_local_boostcoc($hiddencoursescounter) { + // Do only if local_boostcoc is installed. + if (block_course_overview_campus_check_local_boostcoc() == true) { + $coc_config = get_config('block_course_overview_campus'); + + // Check all filters if they are enabled and active filters (value != all) and check the fact that there are hidden courses and store them in an array. + $activefilters = array(); + if ($coc_config->termcoursefilter == true && get_user_preferences('block_course_overview_campus-selectedterm') != 'all') { + $activefilters[] = 'filterterm'; + } + if ($coc_config->categorycoursefilter == true && get_user_preferences('block_course_overview_campus-selectedcategory') != 'all') { + $activefilters[] = 'filtercategory'; + } + if ($coc_config->toplevelcategorycoursefilter == true && get_user_preferences('block_course_overview_campus-selectedtoplevelcategory') != 'all') { + $activefilters[] = 'filtertoplevelcategory'; + } + if ($coc_config->teachercoursefilter == true && get_user_preferences('block_course_overview_campus-selectedteacher') != 'all') { + $activefilters[] = 'filterteacher'; + } + if ($hiddencoursescounter > 0) { + $activefilters[] = 'hidecourses'; + } + + // Convert active filters array to JSON. + $jsonstring = json_encode($activefilters); + + // Store the current status of active filters. + set_user_preference('local_boostcoc-activefilters', $jsonstring); + } +} + + +/** + * Check if our companion plugin local_boostcoc is installed + * + * @return boolean + */ +function block_course_overview_campus_check_local_boostcoc() { + global $CFG; + + static $local_boostcoc_installed; + + if (!isset($local_boostcoc_installed)) { + if (file_exists($CFG->dirroot.'/local/boostcoc/lib.php')) { + $local_boostcoc_installed = true; + } else { + $local_boostcoc_installed = false; + } + } + + return $local_boostcoc_installed; +} diff --git a/blocks/course_overview_campus/pix/collapsed.png b/blocks/course_overview_campus/pix/collapsed.png new file mode 100644 index 0000000000000000000000000000000000000000..d971d4f15af2ddada7254e9128915bbdebe7a636 Binary files /dev/null and b/blocks/course_overview_campus/pix/collapsed.png differ diff --git a/blocks/course_overview_campus/pix/collapsed.svg b/blocks/course_overview_campus/pix/collapsed.svg new file mode 100644 index 0000000000000000000000000000000000000000..77c429504e6758136f85e3e8f52d4ba8322ed84a --- /dev/null +++ b/blocks/course_overview_campus/pix/collapsed.svg @@ -0,0 +1,3 @@ +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ + <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/"> +]><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="-5 -2.1 16 16" preserveAspectRatio="xMinYMid meet" overflow="visible"><path d="M.7.2C.3-.2 0 0 0 .5v10.8c0 .5.3.7.7.3l5-5c.4-.4.4-1 0-1.4l-5-5z" fill="#999"/></svg> \ No newline at end of file diff --git a/blocks/course_overview_campus/pix/expanded.png b/blocks/course_overview_campus/pix/expanded.png new file mode 100644 index 0000000000000000000000000000000000000000..fb0550a6632d6c80e4c86edef4852d271120bd65 Binary files /dev/null and b/blocks/course_overview_campus/pix/expanded.png differ diff --git a/blocks/course_overview_campus/pix/expanded.svg b/blocks/course_overview_campus/pix/expanded.svg new file mode 100644 index 0000000000000000000000000000000000000000..2f7e463403dce21393d97034b8f0c790aed3d53f --- /dev/null +++ b/blocks/course_overview_campus/pix/expanded.svg @@ -0,0 +1,3 @@ +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ + <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/"> +]><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="-2.1 -5 16 16" preserveAspectRatio="xMinYMid meet" overflow="visible"><path d="M.5 0C0 0-.2.3.2.7l5 5c.4.4 1 .4 1.4 0l5-5c.4-.4.3-.7-.3-.7H.5z" fill="#999"/></svg> \ No newline at end of file diff --git a/blocks/course_overview_campus/pix/hide.png b/blocks/course_overview_campus/pix/hide.png new file mode 100644 index 0000000000000000000000000000000000000000..290685e8a2f0a18f3dba5e5dec7be434d97bae1e Binary files /dev/null and b/blocks/course_overview_campus/pix/hide.png differ diff --git a/blocks/course_overview_campus/pix/hide.svg b/blocks/course_overview_campus/pix/hide.svg new file mode 100644 index 0000000000000000000000000000000000000000..1b717f76b160372ee85fc018ca2f3208a797fd9e --- /dev/null +++ b/blocks/course_overview_campus/pix/hide.svg @@ -0,0 +1,3 @@ +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ + <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/"> +]><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 -1.8 12 12" preserveAspectRatio="xMinYMid meet" overflow="visible"><path d="M6 0C2.8 0 0 2.6 0 4.2s2.8 4.2 6 4.2 6-2.6 6-4.2S9.2 0 6 0zM2 4.2c.2-.4 1.4-1.6 3-2-.8.3-1.3 1.1-1.3 2 0 .9.5 1.7 1.3 2.1-1.6-.4-2.8-1.6-3-2.1zm3.1-.1c-.4 0-.8-.3-.8-.8s.3-.8.8-.8.8.3.8.8-.4.8-.8.8zM7 6.3c.8-.4 1.3-1.2 1.3-2.1 0-.9-.5-1.7-1.3-2.1 1.6.5 2.8 1.7 3 2.1-.2.5-1.4 1.7-3 2.1z" fill="#999"/></svg> \ No newline at end of file diff --git a/blocks/course_overview_campus/pix/show.png b/blocks/course_overview_campus/pix/show.png new file mode 100644 index 0000000000000000000000000000000000000000..ed3fb4bb02b3443307203bf87d73636b1207ac64 Binary files /dev/null and b/blocks/course_overview_campus/pix/show.png differ diff --git a/blocks/course_overview_campus/pix/show.svg b/blocks/course_overview_campus/pix/show.svg new file mode 100644 index 0000000000000000000000000000000000000000..c794d6715e7930ea8212f69d5d19a413f9b128d6 --- /dev/null +++ b/blocks/course_overview_campus/pix/show.svg @@ -0,0 +1,3 @@ +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ + <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/"> +]><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" preserveAspectRatio="xMinYMid meet" overflow="visible"><path d="M11.5 4.7c.3.5.5.9.5 1.3 0 1.6-2.8 4.2-6 4.2l5.5-5.5zM12 0v2.8L2.8 12H0l2.7-2.7C1.1 8.4 0 7 0 6c0-1.6 2.8-4.2 6-4.2 1.2 0 2.3.4 3.3.9L12 0zM7.1 3.9c.2.1.4.3.5.5l.2-.2c-.2-.1-.5-.2-.7-.3zm-2 .4c-.4 0-.8.3-.8.8s.3.8.8.8.8-.3.8-.8-.4-.8-.8-.8zm-.9 3.5l.2-.2c-.5-.4-.7-1-.7-1.6 0-.9.5-1.7 1.3-2.1-1.6.4-2.8 1.6-3 2.1.2.4 1 1.3 2.2 1.8z" fill="#999"/></svg> \ No newline at end of file diff --git a/blocks/course_overview_campus/settings.php b/blocks/course_overview_campus/settings.php new file mode 100644 index 0000000000000000000000000000000000000000..6a0bcd450a67317d5851782440e5dee901fe3072 --- /dev/null +++ b/blocks/course_overview_campus/settings.php @@ -0,0 +1,516 @@ +<?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/>. + +/** + * Block "course overview (campus)" - Settings + * + * @package block_course_overview_campus + * @copyright 2013 Alexander Bias, Ulm University <alexander.bias@uni-ulm.de> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +// @codingStandardsIgnoreFile +// Let codechecker ignore this file. This legacy code is not fully compliant to Moodle coding style but working and well documented. + +if ($hassiteconfig) { + // Empty $settings to prevent a single settings page from being created by lib/classes/plugininfo/block.php + // because we will create several settings pages now. + $settings = null; + + // Create admin settings category. + $ADMIN->add('blocksettings', new admin_category('block_course_overview_campus', + get_string('pluginname', 'block_course_overview_campus', null, true))); + + + + // Create empty settings page structure to make the site administration work on non-admin pages. + if (!$ADMIN->fulltree) { + // Settings page: General. + $settingspage = new admin_settingpage('block_course_overview_campus_general', + get_string('settingspage_general', 'block_course_overview_campus', null, true)); + $ADMIN->add('block_course_overview_campus', $settingspage); + + // Settings page: Course overview list. + $settingspage = new admin_settingpage('block_course_overview_campus_courseoverviewlist', + get_string('settingspage_courseoverviewlist', 'block_course_overview_campus', null, true)); + $ADMIN->add('block_course_overview_campus', $settingspage); + + // Settings page: Hide courses. + $settingspage = new admin_settingpage('block_course_overview_campus_hidecourses', + get_string('settingspage_hidecourses', 'block_course_overview_campus', null, true)); + $ADMIN->add('block_course_overview_campus', $settingspage); + + // Settings page: Teacher roles. + $settingspage = new admin_settingpage('block_course_overview_campus_teacherroles', + get_string('settingspage_teacherroles', 'block_course_overview_campus', null, true)); + $ADMIN->add('block_course_overview_campus', $settingspage); + + // Settings page: Parent category filter. + $settingspage = new admin_settingpage('block_course_overview_campus_categoryfilter', + get_string('settingspage_categoryfilter', 'block_course_overview_campus', null, true)); + $ADMIN->add('block_course_overview_campus', $settingspage); + + // Settings page: Top level category filter. + $settingspage = new admin_settingpage('block_course_overview_campus_toplevelcategoryfilter', + get_string('settingspage_toplevelcategoryfilter', 'block_course_overview_campus', null, true)); + $ADMIN->add('block_course_overview_campus', $settingspage); + + // Settings page: Teacher filter. + $settingspage = new admin_settingpage('block_course_overview_campus_teacherfilter', + get_string('settingspage_teacherfilter', 'block_course_overview_campus', null, true)); + $ADMIN->add('block_course_overview_campus', $settingspage); + + // Settings page: Term filter. + $settingspage = new admin_settingpage('block_course_overview_campus_termfilter', + get_string('settingspage_termfilter', 'block_course_overview_campus', null, true)); + $ADMIN->add('block_course_overview_campus', $settingspage); + } + + + // Create full settings page structure. + else if ($ADMIN->fulltree) { + // Include local library. + require_once(__DIR__ . '/locallib.php'); + + + // Settings page: General. + $settingspage = new admin_settingpage('block_course_overview_campus_general', + get_string('settingspage_general', 'block_course_overview_campus', null, true)); + + // Appearance. + $settingspage->add(new admin_setting_heading('block_course_overview_campus/appearancesettingheading', + get_string('appearancesettingheading', 'block_course_overview_campus', null, true), + '')); + + $settingspage->add(new admin_setting_configtext('block_course_overview_campus/blocktitle', + get_string('blocktitle', 'block_course_overview_campus', null, true), + get_string('blocktitle_desc', 'block_course_overview_campus', null, true), + get_string('blocktitledefault', 'block_course_overview_campus', null, true), + PARAM_TEXT)); + + // Add settings page to the admin settings category. + $ADMIN->add('block_course_overview_campus', $settingspage); + + + + // Settings page: Course overview list. + $settingspage = new admin_settingpage('block_course_overview_campus_courseoverviewlist', + get_string('settingspage_courseoverviewlist', 'block_course_overview_campus', null, true)); + + // Course overview list entries. + $settingspage->add(new admin_setting_heading('block_course_overview_campus/listentriessettingheading', + get_string('listentriessettingheading', 'block_course_overview_campus', null, true), + '')); + + // Possible course name modes. + $coursenamemodes[1] = get_string('fullnamecourse', 'core', null, false); // Don't use string lazy loading here because the string will be directly used and would produce a PHP warning otherwise. + $coursenamemodes[2] = get_string('shortnamecourse', 'core', null, true); + + $settingspage->add(new admin_setting_configselect('block_course_overview_campus/firstrowcoursename', + get_string('firstrowcoursename', 'block_course_overview_campus', null, true), + get_string('firstrowcoursename_desc', 'block_course_overview_campus', null, true), + $coursenamemodes[1], + $coursenamemodes)); + + $settingspage->add(new admin_setting_configcheckbox('block_course_overview_campus/secondrowshowshortname', + get_string('secondrowshowshortname', 'block_course_overview_campus', null, true), + get_string('secondrowshowshortname_desc', 'block_course_overview_campus', null, true), + 0)); + + $settingspage->add(new admin_setting_configcheckbox('block_course_overview_campus/secondrowshowtermname', + get_string('secondrowshowtermname', 'block_course_overview_campus', null, true), + get_string('secondrowshowtermname_desc', 'block_course_overview_campus', null, true), + 0)); + + $settingspage->add(new admin_setting_configcheckbox('block_course_overview_campus/secondrowshowcategoryname', + get_string('secondrowshowcategoryname', 'block_course_overview_campus', null, true), + get_string('secondrowshowcategoryname_desc', 'block_course_overview_campus', null, true), + 0)); + + $settingspage->add(new admin_setting_configcheckbox('block_course_overview_campus/secondrowshowtoplevelcategoryname', + get_string('secondrowshowtoplevelcategoryname', 'block_course_overview_campus', null, true), + get_string('secondrowshowtoplevelcategoryname_desc', 'block_course_overview_campus', null, true), + 0)); + + $settingspage->add(new admin_setting_configcheckbox('block_course_overview_campus/secondrowshowteachername', + get_string('secondrowshowteachername', 'block_course_overview_campus', null, true), + get_string('secondrowshowteachername_desc', 'block_course_overview_campus', null, true), + 0)); + + // Possible teacher name styles. + $teachernamestylemodes[1] = get_string('teachernamestylefullname', 'block_course_overview_campus', null, true); + $teachernamestylemodes[2] = get_string('teachernamestylelastname', 'block_course_overview_campus', null, false); // Don't use string lazy loading here because the string will be directly used and would produce a PHP warning otherwise. + $teachernamestylemodes[3] = get_string('teachernamestylefirstname', 'block_course_overview_campus', null, true); + $teachernamestylemodes[4] = get_string('teachernamestylefullnamedisplay', 'block_course_overview_campus', get_config('core', 'fullnamedisplay'), true); + + $settingspage->add(new admin_setting_configselect('block_course_overview_campus/secondrowshowteachernamestyle', + get_string('secondrowshowteachernamestyle', 'block_course_overview_campus', null, true), + get_string('secondrowshowteachernamestyle_desc', 'block_course_overview_campus', null, true), + $teachernamestylemodes[2], + $teachernamestylemodes)); + + $settingspage->add(new admin_setting_configcheckbox('block_course_overview_campus/secondrowhideonphones', + get_string('secondrowhideonphones', 'block_course_overview_campus', null, true), + get_string('secondrowhideonphones_desc', 'block_course_overview_campus', null, true), + 0)); + + + // Course order. + $settingspage->add(new admin_setting_heading('block_course_overview_campus/ordersettingheading', + get_string('ordersettingheading', 'block_course_overview_campus', null, true), + '')); + + $settingspage->add(new admin_setting_configcheckbox('block_course_overview_campus/prioritizemyteachedcourses', + get_string('prioritizemyteachedcourses', 'block_course_overview_campus', null, true), + get_string('prioritizemyteachedcourses_desc', 'block_course_overview_campus', null, true), + 0)); + + // Add settings page to the admin settings category. + $ADMIN->add('block_course_overview_campus', $settingspage); + + + + // Settings page: Hide courses. + $settingspage = new admin_settingpage('block_course_overview_campus_hidecourses', + get_string('settingspage_hidecourses', 'block_course_overview_campus', null, true)); + + // Course overview list hidden courses management. + $settingspage->add(new admin_setting_heading('block_course_overview_campus/hidecoursessettingheading', + get_string('hidecoursessettingheading', 'block_course_overview_campus', null, true), + '')); + + $settingspage->add(new admin_setting_configcheckbox('block_course_overview_campus/enablehidecourses', + get_string('enablehidecourses', 'block_course_overview_campus', null, true), + get_string('enablehidecourses_desc', 'block_course_overview_campus', null, true), + 1)); + + // Add settings page to the admin settings category. + $ADMIN->add('block_course_overview_campus', $settingspage); + + + + // Settings page: Teacher roles. + $settingspage = new admin_settingpage('block_course_overview_campus_teacherroles', + get_string('settingspage_teacherroles', 'block_course_overview_campus', null, true)); + + // Teacher roles. + $settingspage->add(new admin_setting_heading('block_course_overview_campus/teacherrolessettingheading', + get_string('teacherrolessettingheading', 'block_course_overview_campus', null, true), + '')); + + $settingspage->add(new admin_setting_pickroles('block_course_overview_campus/teacherroles', + get_string('teacherroles', 'block_course_overview_campus', null, true), + get_string('teacherroles_desc', 'block_course_overview_campus', null, true), + array('editingteacher'))); + + $settingspage->add(new admin_setting_configtext('block_course_overview_campus/noteachertext', + get_string('noteachertext', 'block_course_overview_campus', null, true), + get_string('noteachertext_desc', 'block_course_overview_campus', null, true), + get_string('noteacher', 'block_course_overview_campus', null, true), + PARAM_TEXT)); + + // Possible settings for parent teacher roles. + $teacherrolesparentmodes[1] = get_string('yes', 'core', null, false); // Don't use string lazy loading here because the string will be directly used and would produce a PHP warning otherwise. + $teacherrolesparentmodes[2] = get_string('no', 'core', null, true); + $teacherrolesparentmodes[3] = get_string('teacherrolesparentcapability', 'block_course_overview_campus', null, true); + + $settingspage->add(new admin_setting_configselect('block_course_overview_campus/teacherrolesparent', + get_string('teacherrolesparent', 'block_course_overview_campus', null, true), + get_string('teacherrolesparent_desc', 'block_course_overview_campus', null, true), + $teacherrolesparentmodes[1], + $teacherrolesparentmodes)); + + $settingspage->add(new admin_setting_configcheckbox('block_course_overview_campus/teacherroleshidesuspended', + get_string('teacherroleshidesuspended', 'block_course_overview_campus', null, true), + get_string('teacherroleshidesuspended_desc', 'block_course_overview_campus', null, true), + 0)); + + // Add settings page to the admin settings category. + $ADMIN->add('block_course_overview_campus', $settingspage); + + + + // Settings page: Parent category filter. + $settingspage = new admin_settingpage('block_course_overview_campus_categoryfilter', + get_string('settingspage_categoryfilter', 'block_course_overview_campus', null, true)); + + // Parent category filter: Activation. + $settingspage->add(new admin_setting_heading('block_course_overview_campus/categorycoursefiltersettingheading', + get_string('categorycoursefiltersettingheading', 'block_course_overview_campus', null, true), + '')); + + $settingspage->add(new admin_setting_configcheckbox('block_course_overview_campus/categorycoursefilter', + get_string('categorycoursefilter', 'block_course_overview_campus', null, true), + get_string('categorycoursefilter_desc', 'block_course_overview_campus', null, true), + 0)); + + $settingspage->add(new admin_setting_configtext('block_course_overview_campus/categorycoursefilterdisplayname', + get_string('categorycoursefilterdisplayname', 'block_course_overview_campus', null, true), + get_string('categorycoursefilterdisplayname_desc', 'block_course_overview_campus', null, true), + get_string('category', 'block_course_overview_campus', null, true), + PARAM_TEXT)); + + + // Parent category filter: Merge homonymous categories. + $settingspage->add(new admin_setting_heading('block_course_overview_campus/mergehomonymouscategoriessettingheading', + get_string('mergehomonymouscategoriessettingheading', 'block_course_overview_campus', null, true), + '')); + + $settingspage->add(new admin_setting_configcheckbox('block_course_overview_campus/mergehomonymouscategories', + get_string('mergehomonymouscategories', 'block_course_overview_campus', null, true), + get_string('mergehomonymouscategories_desc', 'block_course_overview_campus', null, true), + 0)); + + // Add settings page to the admin settings category. + $ADMIN->add('block_course_overview_campus', $settingspage); + + + + // Settings page: Top level category filter. + $settingspage = new admin_settingpage('block_course_overview_campus_toplevelcategoryfilter', + get_string('settingspage_toplevelcategoryfilter', 'block_course_overview_campus', null, true)); + + // Top level category filter: Activation. + $settingspage->add(new admin_setting_heading('block_course_overview_campus/toplevelcategorycoursefiltersettingheading', + get_string('toplevelcategorycoursefiltersettingheading', 'block_course_overview_campus', null, true), + '')); + + $settingspage->add(new admin_setting_configcheckbox('block_course_overview_campus/toplevelcategorycoursefilter', + get_string('toplevelcategorycoursefilter', 'block_course_overview_campus', null, true), + get_string('toplevelcategorycoursefilter_desc', 'block_course_overview_campus', null, true), + 0)); + + $settingspage->add(new admin_setting_configtext('block_course_overview_campus/toplevelcategorycoursefilterdisplayname', + get_string('toplevelcategorycoursefilterdisplayname', 'block_course_overview_campus', null, true), + get_string('toplevelcategorycoursefilterdisplayname_desc', 'block_course_overview_campus', null, true), + get_string('toplevelcategory', 'block_course_overview_campus', null, true), + PARAM_TEXT)); + + // Add settings page to the admin settings category. + $ADMIN->add('block_course_overview_campus', $settingspage); + + + + // Settings page: Teacher filter. + $settingspage = new admin_settingpage('block_course_overview_campus_teacherfilter', + get_string('settingspage_teacherfilter', 'block_course_overview_campus', null, true)); + + // Teacher filter: Activation. + $settingspage->add(new admin_setting_heading('block_course_overview_campus/teachercoursefiltersettingheading', + get_string('teachercoursefiltersettingheading', 'block_course_overview_campus', null, true), + '')); + + $settingspage->add(new admin_setting_configcheckbox('block_course_overview_campus/teachercoursefilter', + get_string('teachercoursefilter', 'block_course_overview_campus', null, true), + get_string('teachercoursefilter_desc', 'block_course_overview_campus', null, true), + 0)); + + $settingspage->add(new admin_setting_configtext('block_course_overview_campus/teachercoursefilterdisplayname', + get_string('teachercoursefilterdisplayname', 'block_course_overview_campus', null, true), + get_string('teachercoursefilterdisplayname_desc', 'block_course_overview_campus', null, true), + get_string('defaultcourseteacher'), + PARAM_TEXT)); + + // Add settings page to the admin settings category. + $ADMIN->add('block_course_overview_campus', $settingspage); + + + + // Settings page: Term filter. + $settingspage = new admin_settingpage('block_course_overview_campus_termfilter', + get_string('settingspage_termfilter', 'block_course_overview_campus', null, true)); + + // Term filter: Activation. + $settingspage->add(new admin_setting_heading('block_course_overview_campus/termcoursefiltersettingheading', + get_string('termcoursefiltersettingheading', 'block_course_overview_campus', null, true), + '')); + + $settingspage->add(new admin_setting_configcheckbox('block_course_overview_campus/termcoursefilter', + get_string('termcoursefilter', 'block_course_overview_campus', null, true), + get_string('termcoursefilter_desc', 'block_course_overview_campus', null, true), + 0)); + + $settingspage->add(new admin_setting_configtext('block_course_overview_campus/termcoursefilterdisplayname', + get_string('termcoursefilterdisplayname', 'block_course_overview_campus', null, true), + get_string('termcoursefilterdisplayname_desc', 'block_course_overview_campus', null, true), + get_string('term', 'block_course_overview_campus', null, true), + PARAM_TEXT)); + + + // Term filter: Term definition. + // Check if the configured term dates make sense, if not show warning information. + $coc_config = get_config('block_course_overview_campus'); + if (isset($coc_config->termcoursefilter) && + $coc_config->termcoursefilter == true && + !block_course_overview_campus_check_term_config($coc_config)) { + $settingspage->add(new admin_setting_heading('block_course_overview_campus/termsettingheading', + get_string('termsettingheading', 'block_course_overview_campus'), + '<span class="errormessage">'.get_string('termsettingerror', 'block_course_overview_campus', null, true).'</span>')); + } else { + $settingspage->add(new admin_setting_heading('block_course_overview_campus/termsettingheading', + get_string('termsettingheading', 'block_course_overview_campus', null, true), '')); + } + + // Possible term modes. + $termmodes[1] = get_string('academicyear_desc', 'block_course_overview_campus', null, false); // Don't use string lazy loading here because the string will be directly used and would produce a PHP warning otherwise. + $termmodes[2] = get_string('semester_desc', 'block_course_overview_campus', null, true); + $termmodes[3] = get_string('tertial_desc', 'block_course_overview_campus', null, true); + $termmodes[4] = get_string('trimester_desc', 'block_course_overview_campus', null, true); + + $settingspage->add(new admin_setting_configselect('block_course_overview_campus/termmode', + get_string('termmode', 'block_course_overview_campus', null, true), + get_string('termmode_desc', 'block_course_overview_campus', null, true), + $termmodes[1], + $termmodes)); + + + // Get all calendar days for later use. + $format = get_string('strftimedateshort', 'langconfig'); + for ($i = 1; $i <= 12; $i++) { + for ($j = 1; $j <= date('t', mktime(0, 0, 0, $i, 1, 2003)); $j++) { // Use no leap year to calculate days in month to avoid providing 29th february as an option. + // Create an intermediate timestamp with each day-month-combination and format it + // according to local date format for displaying purpose. + $daystring = userdate(gmmktime(12, 0, 0, $i, $j, 2003), $format); + + // Add the day as an option. + $days[sprintf('%02d', $i).'-'.sprintf('%02d', $j)] = $daystring; + } + } + + $settingspage->add(new admin_setting_configselect('block_course_overview_campus/term1startday', + get_string('term1startday', 'block_course_overview_campus', null, true), + get_string('term1startday_desc', 'block_course_overview_campus', null, true), + $days['01-01'], + $days)); + + $settingspage->add(new admin_setting_configselect('block_course_overview_campus/term2startday', + get_string('term2startday', 'block_course_overview_campus', null, true), + get_string('term2startday_desc', 'block_course_overview_campus', null, true), + $days['01-01'], + $days)); + + $settingspage->add(new admin_setting_configselect('block_course_overview_campus/term3startday', + get_string('term3startday', 'block_course_overview_campus', null, true), + get_string('term3startday_desc', 'block_course_overview_campus', null, true), + $days['01-01'], + $days)); + + $settingspage->add(new admin_setting_configselect('block_course_overview_campus/term4startday', + get_string('term4startday', 'block_course_overview_campus', null, true), + get_string('term4startday_desc', 'block_course_overview_campus', null, true), + $days['01-01'], + $days)); + + + // Term filter: Term names. + $settingspage->add(new admin_setting_heading('block_course_overview_campus/termnamesettingheading', + get_string('termnamesettingheading', 'block_course_overview_campus', null, true), + '')); + + $settingspage->add(new admin_setting_configtext('block_course_overview_campus/term1name', + get_string('term1name', 'block_course_overview_campus', null, true), + get_string('term1name_desc', 'block_course_overview_campus', null, true), + get_string('term1', 'block_course_overview_campus'), + PARAM_TEXT)); + + $settingspage->add(new admin_setting_configtext('block_course_overview_campus/term2name', + get_string('term2name', 'block_course_overview_campus', null, true), + get_string('term2name_desc', 'block_course_overview_campus', null, true), + get_string('term2', 'block_course_overview_campus'), + PARAM_TEXT)); + + $settingspage->add(new admin_setting_configtext('block_course_overview_campus/term3name', + get_string('term3name', 'block_course_overview_campus', null, true), + get_string('term3name_desc', 'block_course_overview_campus', null, true), + get_string('term3', 'block_course_overview_campus'), + PARAM_TEXT)); + + $settingspage->add(new admin_setting_configtext('block_course_overview_campus/term4name', + get_string('term4name', 'block_course_overview_campus', null, true), + get_string('term4name_desc', 'block_course_overview_campus', null, true), + get_string('term4', 'block_course_overview_campus'), + PARAM_TEXT)); + + // Possible year positions for later use. + $termyearpos[1] = get_string('termyearposprefixspace_desc', 'block_course_overview_campus', null, true); + $termyearpos[2] = get_string('termyearposprefixnospace_desc', 'block_course_overview_campus', null, true); + $termyearpos[3] = get_string('termyearpossuffixspace_desc', 'block_course_overview_campus', null, false); // Don't use string lazy loading here because the string will be directly used and would produce a PHP warning otherwise. + $termyearpos[4] = get_string('termyearpossuffixnospace_desc', 'block_course_overview_campus', null, true); + + $settingspage->add(new admin_setting_configselect('block_course_overview_campus/termyearpos', + get_string('termyearpos', 'block_course_overview_campus', null, true), + get_string('termyearpos_desc', 'block_course_overview_campus', null, true), + $termyearpos[3], + $termyearpos)); + + // Possible year separators for later use. + $termyearseparation[1] = get_string('termyearseparationhyphen_desc', 'block_course_overview_campus', null, true); + $termyearseparation[2] = get_string('termyearseparationslash_desc', 'block_course_overview_campus', null, false); // Don't use string lazy loading here because the string will be directly used and would produce a PHP warning otherwise. + $termyearseparation[3] = get_string('termyearseparationunderscore_desc', 'block_course_overview_campus', null, true); + $termyearseparation[4] = get_string('termyearseparationnosecondyear_desc', 'block_course_overview_campus', null, true); + + $settingspage->add(new admin_setting_configselect('block_course_overview_campus/termyearseparation', + get_string('termyearseparation', 'block_course_overview_campus', null, true), + get_string('termyearseparation_desc', 'block_course_overview_campus', null, true), + $termyearseparation[2], + $termyearseparation)); + + + // Term filter: Term behaviour. + $settingspage->add(new admin_setting_heading('block_course_overview_campus/termbehavioursettingheading', + get_string('termbehavioursettingheading', 'block_course_overview_campus', null, true), + '')); + + $settingspage->add(new admin_setting_configcheckbox('block_course_overview_campus/defaultterm', + get_string('defaultterm', 'block_course_overview_campus', null, true), + get_string('defaultterm_desc', 'block_course_overview_campus', null, true), + 1)); + + + // Term filter: Timeless courses. + $settingspage->add(new admin_setting_heading('block_course_overview_campus/timelesscoursessettingheading', + get_string('timelesscoursessettingheading', 'block_course_overview_campus', null, true), + '')); + + $settingspage->add(new admin_setting_configcheckbox('block_course_overview_campus/timelesscourses', + get_string('timelesscourses', 'block_course_overview_campus', null, true), + get_string('timelesscourses_desc', 'block_course_overview_campus', null, true), + 1)); + + $settingspage->add(new admin_setting_configtext('block_course_overview_campus/timelesscoursesname', + get_string('timelesscoursesname', 'block_course_overview_campus', null, true), + get_string('timelesscoursesname_desc', 'block_course_overview_campus', null, true), + get_string('timelesscourses', 'block_course_overview_campus', null, true), + PARAM_TEXT)); + + // Get all years from 1970. + for ($i = 1971; $i <= date('Y'); $i++) { + // Add the year as an option. + $years[$i] = $i; + } + + $settingspage->add(new admin_setting_configselect('block_course_overview_campus/timelesscoursesthreshold', + get_string('timelesscoursesthreshold', 'block_course_overview_campus', null, true), + get_string('timelesscoursesthreshold_desc', 'block_course_overview_campus', null, true), + $years[date('Y') - 1], + $years)); + + // Add settings page to the admin settings category. + $ADMIN->add('block_course_overview_campus', $settingspage); + } +} diff --git a/blocks/course_overview_campus/styles.css b/blocks/course_overview_campus/styles.css new file mode 100644 index 0000000000000000000000000000000000000000..a71c9e046d43c472c2e5ad4fa1cca188e4dee806 --- /dev/null +++ b/blocks/course_overview_campus/styles.css @@ -0,0 +1,50 @@ +/* Positioning of icons */ +.block_course_overview_campus .hidecourseicon { + float: right; + margin-left: 20px; +} + +.block_course_overview_campus a:first-of-type > .icon { + margin-left: inherit; /* Get rid of a unneeded Moodle core behaviour here */ +} + + +/* Used for hiding courses in courselist */ +.coc-hidden { + display: none; +} + + +/* Hidden courses management */ +#coc-hiddencoursesmanagement-bottom, +#coc-hiddencoursesmanagement-top { + font-size: 90%; + text-align: center; /* For some reason, the Bootstrap class text-center does not work here yet */ +} + +#coc-hiddencoursescount { + color: darkred; +} + + +/* Filter submit appearance */ +#coc-filtersubmit { + text-align: center; /* For some reason, the Bootstrap class justify-content-center does not work here yet */ +} + +.jsenabled #coc-filtersubmit { + display: none; /* Hide submit button when JS is enabled */ +} + + +/* Course list appearance */ +#coc-courselist .coursebox h3 { + margin: 0; /* Remove standard margin from h3 heading*/ + padding: 0 0 0 .5rem; /* Keep some of the left padding where the course news icon was previously */ +} + +#coc-courselist .coc-metainfo { + font-size: 85%; + font-weight: normal; /* To prevent the text from being shown in bold as it's still a h3 heading*/ + white-space: pre-wrap; /* To support multiple whitespaces before and after pipe */ +} diff --git a/blocks/course_overview_campus/styles_boost.css b/blocks/course_overview_campus/styles_boost.css new file mode 100644 index 0000000000000000000000000000000000000000..cfdb208f4fda4c515cba0b7da2e7c2cb8e125975 --- /dev/null +++ b/blocks/course_overview_campus/styles_boost.css @@ -0,0 +1,25 @@ +/* Below are styles which are only needed for Boost, but are not needed for Bootstrapbase */ + +/* Boost makes h3 headings quite big, this is not desired for this block. */ +.block_course_overview_campus.block .coursebox h3 { + font-size: 1.0rem; +} + + +/* Below are styles which are needed because Boost (BS 4) makes things different from Bootstrapbase (BS 2) */ + +#coc-courselist .row, +#coc-hiddencoursesmanagement-top .row, +#coc-hiddencoursesmanagement-bottom .row { + display: block; /* Revert the flex model from BS 4 stable for the course list items and controls to circumvent redesign + of this block. This isn't nice but ok for the time being. */ +} + +.path-my .block_course_overview_campus .coursebox { + margin: 0; +} + +#coc-filterlist { + padding-left: 0; + padding-right: 0; +} diff --git a/blocks/course_overview_campus/styles_bootstrapbase.css b/blocks/course_overview_campus/styles_bootstrapbase.css new file mode 100644 index 0000000000000000000000000000000000000000..79d00a3a5f34e7091f4fafd77a210d11ae4482bc --- /dev/null +++ b/blocks/course_overview_campus/styles_bootstrapbase.css @@ -0,0 +1,18 @@ +/* Below are styles which are only needed for Bootstrapbase, but are not needed for Boost */ + +/* Bootstrapbase makes h3 headings uppercase, this is not desired for this block. */ +.block_course_overview_campus.block .coursebox h3 { + text-transform: none; +} + + +/* Below are styles which are needed because Boost (BS 4) makes things different from Bootstrapbase (BS 2) */ + +.block_course_overview_campus .row { + margin-left: 0; +} + +.block_course_overview_campus .container-fluid { + padding-left: 0; + padding-right: 0; +} diff --git a/blocks/course_overview_campus/version.php b/blocks/course_overview_campus/version.php new file mode 100644 index 0000000000000000000000000000000000000000..324b8269ebac2473c1c907b3f3742557ef7ccd6c --- /dev/null +++ b/blocks/course_overview_campus/version.php @@ -0,0 +1,31 @@ +<?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/>. + +/** + * Block "course overview (campus)" - Version file + * + * @package block_course_overview_campus + * @copyright 2013 Alexander Bias, Ulm University <alexander.bias@uni-ulm.de> + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$plugin->component = 'block_course_overview_campus'; +$plugin->version = 2019061200; +$plugin->release = 'v3.7-r1'; +$plugin->requires = 2019052000; +$plugin->maturity = MATURITY_STABLE;