div.append(label).append(this.input);
this.select.insert(div, 'before');
- this.select.one('option').setStyle('display', 'none');
this.input.on('keyup', this.typed, this);
this.select.on('change', this.validate, this);
if (($_SERVER['REQUEST_METHOD'] === 'GET' // Only on initial GET of loginpage
|| ($_SERVER['REQUEST_METHOD'] === 'POST'
- && (get_referer() != strip_querystring(qualified_me()))))
+ && (get_local_referer() != strip_querystring(qualified_me()))))
// Or when POSTed from another place
// See MDL-14071
&& !empty($this->config->ntlmsso_enabled) // SSO enabled
// First, let's remember where we were trying to get to before we got here
if (empty($SESSION->wantsurl)) {
- $SESSION->wantsurl = (array_key_exists('HTTP_REFERER', $_SERVER) &&
- $_SERVER['HTTP_REFERER'] != $CFG->wwwroot &&
- $_SERVER['HTTP_REFERER'] != $CFG->wwwroot.'/' &&
- $_SERVER['HTTP_REFERER'] != $CFG->httpswwwroot.'/login/' &&
- $_SERVER['HTTP_REFERER'] != $CFG->httpswwwroot.'/login/index.php' &&
- clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL) != '')
- ? $_SERVER['HTTP_REFERER'] : NULL;
+ $SESSION->wantsurl = null;
+ $referer = get_local_referer(false);
+ if ($referer &&
+ $referer != $CFG->wwwroot &&
+ $referer != $CFG->wwwroot . '/' &&
+ $referer != $CFG->httpswwwroot . '/login/' &&
+ $referer != $CFG->httpswwwroot . '/login/index.php') {
+ $SESSION->wantsurl = $referer;
+ }
}
// Now start the whole NTLM machinery.
// Support for WAYFless URLs.
$target = optional_param('target', '', PARAM_LOCALURL);
- if (!empty($target)) {
+ if (!empty($target) && empty($SESSION->wantsurl)) {
$SESSION->wantsurl = $target;
}
* that we can guarantee does not happen from within building the modinfo
* object.
*
- * @param string $info Info string
+ * @param \renderable|string $inforenderable Info string or renderable
* @param int|\stdClass $courseorid
* @return string Correctly formatted info string
*/
- public static function format_info($info, $courseorid) {
+ public static function format_info($inforenderable, $courseorid) {
+ global $PAGE;
+
+ // Use renderer if required.
+ if (is_string($inforenderable)) {
+ $info = $inforenderable;
+ } else {
+ $renderer = $PAGE->get_renderer('core', 'availability');
+ $info = $renderer->render($inforenderable);
+ }
+
// Don't waste time if there are no special tags.
if (strpos($info, '<AVAILABILITY_') === false) {
return $info;
--- /dev/null
+<?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/>.
+
+/**
+ * Represents multiple availability messages.
+ *
+ * These are messages like 'Not available until <date>'. This class includes
+ * multiple messages so that they can be rendered into a combined display, e.g.
+ * using bulleted lists.
+ *
+ * The tree structure of this object matches that of the availability
+ * restrictions.
+ *
+ * @package core_availability
+ * @copyright 2015 Andrew Nicols <andrew@nicols.co.uk>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Represents multiple availability messages.
+ *
+ * These are messages like 'Not available until <date>'. This class includes
+ * multiple messages so that they can be rendered into a combined display, e.g.
+ * using bulleted lists.
+ *
+ * The tree structure of this object matches that of the availability
+ * restrictions.
+ *
+ * @package core_availability
+ * @copyright 2015 Andrew Nicols <andrew@nicols.co.uk>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class core_availability_multiple_messages implements renderable {
+ /** @var bool True if this object represents the root of the tree */
+ public $root;
+ /** @var bool True if items use the AND operator (false = OR) */
+ public $andoperator;
+ /** @var bool True if this part of the tree is marked 'hide entirely' for non-matching users */
+ public $treehidden;
+ /** @var array Array of child items (may be string or this type) */
+ public $items;
+
+ /**
+ * Constructor.
+ *
+ * @param bool $root True if this object represents the root of the tree
+ * @param bool $andoperator True if items use the AND operator (false = OR)
+ * @param bool $treehidden True if this part of the tree is marked 'hide entirely' for non-matching users
+ * @param array $items Array of items (may be string or this type)
+ */
+ public function __construct($root, $andoperator, $treehidden, array $items) {
+ $this->root = $root;
+ $this->andoperator = $andoperator;
+ $this->treehidden = $treehidden;
+ $this->items = $items;
+ }
+}
* @param result $result Result object if this is a student display, else null
* @param bool $root True if this is the root item
* @param bool $hidden Staff display; true if this tree has show=false (from parent)
+ * @return string|renderable Information to render
*/
protected function get_full_information_recursive(
$not, info $info, result $result = null, $root, $hidden = false) {
- global $PAGE;
-
// Get list of children - either full list, or those which are shown.
$children = $this->children;
$staff = true;
}
// Format output for display.
- $renderer = $PAGE->get_renderer('core', 'availability');
- return $renderer->multiple_messages($root, $andoperator, $treehidden, $items);
+ return new \core_availability_multiple_messages($root, $andoperator, $treehidden, $items);
}
/**
--- /dev/null
+@availability @availability_completion
+Feature: Confirm that conditions on completion no longer cause a bug
+ In order to use completion conditions
+ As a teacher
+ I need it to not break when I set up certain conditions on some modules
+
+ Background:
+ Given the following "courses" exist:
+ | fullname | shortname | format |
+ | Course 1 | C1 | topics |
+ And the following "users" exist:
+ | username |
+ | teacher1 |
+ And the following "course enrolments" exist:
+ | user | course | role |
+ | teacher1 | C1 | editingteacher |
+ And the following config values are set as admin:
+ | enableavailability | 1 |
+ | enablecompletion | 1 |
+
+ @javascript
+ Scenario: Multiple completion conditions on glossary
+ # Set up course.
+ Given I log in as "teacher1"
+ And I follow "Course 1"
+ And I navigate to "Edit settings" node in "Course administration"
+ And I expand all fieldsets
+ And I set the field "Enable completion tracking" to "Yes"
+ And I press "Save and display"
+ And I turn editing mode on
+
+ # Add a couple of Pages with manual completion.
+ And I add a "Page" to section "1" and I fill the form with:
+ | Name | Page1 |
+ | Page content | x |
+ And I add a "Page" to section "1" and I fill the form with:
+ | Name | Page2 |
+ | Page content | x |
+
+ # Add a Glossary.
+ When I add a "Glossary" to section "1"
+ And I set the following fields to these values:
+ | Name | TestGlossary |
+ And I expand all fieldsets
+
+ # Add restrictions to the previous Pages being complete.
+ And I press "Add restriction..."
+ And I click on "Activity completion" "button" in the "Add restriction..." "dialogue"
+ And I set the field "Activity or resource" to "Page1"
+ And I press "Add restriction..."
+ And I click on "Activity completion" "button" in the "Add restriction..." "dialogue"
+ And I set the field with xpath "//div[@class='availability-item'][preceding-sibling::div]//select[@name='cm']" to "Page2"
+ And I press "Save and return to course"
+ And I should see "Not available unless:" in the ".activity.glossary" "css_element"
+ And I should see "The activity Page1 is marked complete" in the ".activity.glossary" "css_element"
+ And I should see "The activity Page2 is marked complete" in the ".activity.glossary" "css_element"
+ And I follow "TestGlossary"
+
+ # Behat will automatically check there is no error on this page.
+ Then I should see "TestGlossary"
*
* This function will not be called unless there are at least two messages.
*
- * @param bool $root True if this is a root-level list for an activity
- * @param bool $andoperator True if the messages are being combined as AND
- * @param bool $roothidden True if the root level should use 'hidden' message
- * @param array $messages Messages to render
+ * @param core_availability_multiple_messages $renderable Multiple messages
* @return string Combined HTML
*/
- public function multiple_messages($root, $andoperator, $roothidden, array $messages) {
+ public function render_core_availability_multiple_messages(
+ core_availability_multiple_messages $renderable) {
// Get initial message.
- $out = get_string('list_' . ($root ? 'root_' : '') .
- ($andoperator ? 'and' : 'or') . ($roothidden ? '_hidden' : ''),
+ $out = get_string('list_' . ($renderable->root ? 'root_' : '') .
+ ($renderable->andoperator ? 'and' : 'or') . ($renderable->treehidden ? '_hidden' : ''),
'availability');
// Make the list.
$out .= html_writer::start_tag('ul');
- foreach ($messages as $message) {
- $out .= html_writer::tag('li', $message);
+ foreach ($renderable->items as $item) {
+ if (is_string($item)) {
+ $str = $item;
+ } else {
+ $str = $this->render($item);
+ }
+ $out .= html_writer::tag('li', $str);
}
$out .= html_writer::end_tag('ul');
return $out;
* @param int $userid User id
*/
protected function get_available_results($structure, \core_availability\info $info, $userid) {
+ global $PAGE;
$tree = new tree($structure);
$result = $tree->check_available(false, $info, true, $userid);
- return array($result->is_available(), $tree->get_result_information($info, $result));
+ $information = $tree->get_result_information($info, $result);
+ if (!is_string($information)) {
+ $renderer = $PAGE->get_renderer('core', 'availability');
+ $information = $renderer->render($information);
+ }
+ return array($result->is_available(), $information);
}
/**
* Tests the get_full_information() function.
*/
public function test_get_full_information() {
+ global $PAGE;
+ $renderer = $PAGE->get_renderer('core', 'availability');
// Setup.
$info = new \core_availability\mock_info();
self::mock(array('m' => 3)));
$tree = new tree($structure);
$this->assertRegExp('~<ul.*<ul.*<li.*1.*<li.*2.*</ul>.*<li.*3~',
- $tree->get_full_information($info));
+ $renderer->render($tree->get_full_information($info)));
// Test intro messages before list. First, OR message.
$structure->c = array(
);
$tree = new tree($structure);
$this->assertRegExp('~Not available unless any of:.*<ul>~',
- $tree->get_full_information($info));
+ $renderer->render($tree->get_full_information($info)));
// Now, OR message when not shown.
$structure->show = false;
$tree = new tree($structure);
$this->assertRegExp('~hidden.*<ul>~',
- $tree->get_full_information($info));
+ $renderer->render($tree->get_full_information($info)));
// AND message.
$structure->op = '&';
$structure->showc = array(false, false);
$tree = new tree($structure);
$this->assertRegExp('~Not available unless:.*<ul>~',
- $tree->get_full_information($info));
+ $renderer->render($tree->get_full_information($info)));
// Hidden markers on items.
$this->assertRegExp('~1.*hidden.*2.*hidden~',
- $tree->get_full_information($info));
+ $renderer->render($tree->get_full_information($info)));
// Hidden markers on child tree and items.
$structure->c[1] = tree::get_nested_json(array(
self::mock(array('m' => '3'))), tree::OP_AND);
$tree = new tree($structure);
$this->assertRegExp('~1.*hidden.*All of \(hidden.*2.*3~',
- $tree->get_full_information($info));
+ $renderer->render($tree->get_full_information($info)));
$structure->c[1]->op = '|';
$tree = new tree($structure);
$this->assertRegExp('~1.*hidden.*Any of \(hidden.*2.*3~',
- $tree->get_full_information($info));
+ $renderer->render($tree->get_full_information($info)));
// Hidden markers on single-item display, AND and OR.
$structure->showc = array(false);
self::mock(array('m' => '2'))), tree::OP_AND);
$tree = new tree($structure);
$this->assertRegExp('~Not available \(hidden.*1.*2~',
- $tree->get_full_information($info));
+ $renderer->render($tree->get_full_information($info)));
// Single item tree containing single item.
unset($structure->c[0]->c[1]);
--- /dev/null
+@block @block_blog_tag @core_blog @core_tag
+Feature: Adding blog tag block
+ In order to search blog post by tag
+ As a user
+ I need to be able to use block blog tag
+
+ Scenario: Adding block blog tag to the course
+ Given the following "users" exist:
+ | username | firstname | lastname | email |
+ | teacher1 | Teacher | 1 | teacher1@example.com |
+ | student1 | Student | 1 | student1@example.com |
+ And the following "courses" exist:
+ | fullname | shortname |
+ | Course 1 | c1 |
+ And the following "tags" exist:
+ | name | tagtype |
+ | Neverusedtag | official |
+ And the following "course enrolments" exist:
+ | user | course | role |
+ | teacher1 | c1 | editingteacher |
+ | student1 | c1 | student |
+ When I log in as "teacher1"
+ And I follow "Course 1"
+ And I turn editing mode on
+ And I add the "Blog tags" block
+
+ And I navigate to "Course blogs" node in "Current course > c1 > Participants"
+ And I follow "Blog about this Course"
+ And I set the following fields to these values:
+ | Entry title | Blog post from teacher |
+ | Blog entry body | Teacher blog post content |
+ | Other tags (enter tags separated by commas) | Cats, dogs |
+ And I press "Save changes"
+ And I log out
+ And I log in as "student1"
+ And I follow "Course 1"
+ And I navigate to "Course blogs" node in "Current course > c1 > Participants"
+ And I follow "Blog about this Course"
+ And I set the following fields to these values:
+ | Entry title | Blog post from student |
+ | Blog entry body | Student blog post content |
+ | Other tags (enter tags separated by commas) | DOGS, mice |
+ And I press "Save changes"
+ And I follow "c1"
+ Then I should see "Cats" in the "Blog tags" "block"
+ And I should see "dogs" in the "Blog tags" "block"
+ And I should see "mice" in the "Blog tags" "block"
+ And I click on "Cats" "link" in the "Blog tags" "block"
+ And I should see "Blog post from teacher"
+ And I should see "Teacher blog post content"
+ And I log out
} else if ($item->action instanceof action_link) {
//TODO: to be replaced with something else
$link = $item->action;
- $link->text = $icon.$link->text;
+ $link->text = $icon.html_writer::span($link->text, 'item-content-wrap');
$link->attributes = array_merge($link->attributes, $attributes);
$content = $this->output->render($link);
} else if ($item->action instanceof moodle_url) {
--- /dev/null
+@block @block_tags @core_tag
+Feature: Block tags displaying course tags
+ In order to tag courses
+ As a user
+ I need to be able to use the block tags
+
+ Background:
+ Given the following "users" exist:
+ | username | firstname | lastname | email |
+ | teacher1 | Teacher | 1 | teacher1@example.com |
+ | student1 | Student | 1 | student1@example.com |
+ | student2 | Student | 2 | student2@example.com |
+ And the following "courses" exist:
+ | fullname | shortname |
+ | Course 1 | c1 |
+ And the following "tags" exist:
+ | name | tagtype |
+ | Neverusedtag | official |
+ And the following "course enrolments" exist:
+ | user | course | role |
+ | teacher1 | c1 | editingteacher |
+ | student1 | c1 | student |
+ | student2 | c1 | student |
+ And I log in as "admin"
+ And I set the following administration settings values:
+ | Show course tags | 1 |
+ And I log out
+
+ Scenario: Add Tags block to tag courses in a course
+ When I log in as "teacher1"
+ And I follow "Course 1"
+ And I turn editing mode on
+ And I add the "Tags" block
+ And I log out
+ And I log in as "student1"
+ And I follow "Course 1"
+ And I should not see "Neverusedtag" in the "Tags" "block"
+ And I click on "more..." "link" in the "Tags" "block"
+ And I should not see "Neverusedtag"
+ And I follow "c1"
+ And I set the field "coursetag_new_tag" to "Dogs, Mice"
+ And I press "Add"
+ And I should see "Dogs" in the "Tags" "block"
+ And I should see "Mice" in the "Tags" "block"
+ And I log out
+ And I log in as "student2"
+ And I follow "Course 1"
+ And I should see "Dogs" in the "Tags" "block"
+ And I set the field "coursetag_new_tag" to "Cats, Dogs"
+ And I press "Add"
+ And I should see "Dogs" in the "Tags" "block"
+ And I should see "Cats" in the "Tags" "block"
+ And I click on "more..." "link" in the "Tags" "block"
+ And "Cats" "link" should appear before "Dogs" "link"
+ And "Dogs" "link" should appear before "Mice" "link"
+ And I follow "My tags"
+ And I should see "Dogs"
+ And I should see "Cats"
+ And I should not see "Mice"
+ And I follow "All tags"
+ And I follow "Popularity"
+ And "Mice" "link" should appear before "Dogs" "link"
+ And I should not see "Neverusedtag"
+ And I log out
--- /dev/null
+@block @block_tags @core_tag
+Feature: Block tags displaying tag cloud
+ In order to view system tags
+ As a user
+ I need to be able to use the block tags
+
+ Background:
+ Given the following "users" exist:
+ | username | firstname | lastname | email |
+ | teacher1 | Teacher | 1 | teacher1@example.com |
+ | student1 | Student | 1 | student1@example.com |
+ And the following "courses" exist:
+ | fullname | shortname |
+ | Course 1 | c1 |
+ And the following "tags" exist:
+ | name | tagtype |
+ | Neverusedtag | official |
+ And the following "course enrolments" exist:
+ | user | course | role |
+ | teacher1 | c1 | editingteacher |
+ | student1 | c1 | student |
+ And I log in as "teacher1"
+ And I follow "Preferences" in the user menu
+ And I follow "Edit profile"
+ And I expand all fieldsets
+ And I set the field "Enter tags separated by commas" to "Dogs, Cats"
+ And I press "Update profile"
+ And I log out
+
+ @javascript
+ Scenario: Add Tags block on a front page
+ When I log in as "admin"
+ And I am on site homepage
+ And I follow "Turn editing on"
+ And I add the "Tags" block
+ And I log out
+ And I am on site homepage
+ Then I should see "Dogs" in the "Tags" "block"
+ And I should see "Cats" in the "Tags" "block"
+ And I should not see "Neverusedtag" in the "Tags" "block"
+ And I click on "Dogs" "link" in the "Tags" "block"
+ And I should see "Log in to the site" in the ".breadcrumb" "css_element"
+
+ @javascript
+ Scenario: Add Tags block in a course
+ When I log in as "teacher1"
+ And I follow "Course 1"
+ And I turn editing mode on
+ And I add the "Tags" block
+ And I log out
+ And I log in as "student1"
+ And I follow "Course 1"
+ Then I should see "Dogs" in the "Tags" "block"
+ And I should see "Cats" in the "Tags" "block"
+ And I should not see "Neverusedtag" in the "Tags" "block"
+ And I click on "Dogs" "link" in the "Tags" "block"
+ And I should see "Users tagged with \"Dogs\": 1"
+ And I should see "Teacher 1"
+ And I log out
}
}
+ $hasgradeitems = false;
$items = grade_item::fetch_all(array('itemtype'=>'mod', 'itemmodule'=>$modulename,'iteminstance'=>$instance, 'courseid'=>$COURSE->id));
//will be no items if, for example, this activity supports ratings but rating aggregate type == no ratings
if (!empty($items)) {
if ($mform->elementExists($elname)) {
$mform->hardFreeze($elname); // prevent removing of existing outcomes
}
+ } else {
+ $hasgradeitems = true;
}
}
}
}
+ if (!$hasgradeitems && $mform->elementExists('gradepass')) {
+ // Remove form element 'Grade to pass' since there are no grade items (when rating not selected).
+ $mform->removeElement('gradepass');
+ }
+
if ($gradecat === false) {
// items and outcomes in different categories - remove the option
// TODO: add a "Mixed categories" text instead of removing elements with no explanation
if ($mform->elementExists('gradecat')) {
$mform->removeElement('gradecat');
- if ($this->_features->rating) {
+ if ($this->_features->rating && !$mform->elementExists('gradepass')) {
//if supports ratings then the max grade dropdown wasnt added so the grade box can be removed entirely
$mform->removeElement('modstandardgrade');
}
}
// Return to previous page
- $referer = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+ $referer = get_local_referer(false);
if (!empty($referer)) {
redirect($referer);
} else {
$returnurl = optional_param('returnurl', 0, PARAM_LOCALURL);
if (!isloggedin()) {
- $referer = clean_param(get_referer(), PARAM_LOCALURL);
+ $referer = get_local_referer();
if (empty($referer)) {
// A user that is not logged in has arrived directly on this page,
// they should be redirected to the course page they are trying to enrol on after logging in.
} else if ($returnurl) {
notice(get_string('notenrollable', 'enrol'), $returnurl);
} else {
- $url = clean_param(get_referer(false), PARAM_LOCALURL);
+ $url = get_local_referer(false);
if (empty($url)) {
$url = new moodle_url('/index.php');
}
$site = get_site();
$redirecturl = empty($_SERVER['REDIRECT_URL']) ? '' : $_SERVER['REDIRECT_URL'];
- $httpreferer = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER'];
+ $httpreferer = get_local_referer(false);
$requesturi = empty($_SERVER['REQUEST_URI']) ? '' : $_SERVER['REQUEST_URI'];
header("HTTP/1.0 404 Not Found");
value = M.util.get_string('clicktoedit', 'gradingform_guide')
taplain.addClass('empty')
}
- taplain.one('.textvalue').set('innerHTML', Y.Escape.html(value))
+ // Replace newlines with <br> tags, when displaying in the page.
+ taplain.one('.textvalue').set('innerHTML', Y.Escape.html(value).replace(/(?:\r\n|\r|\n)/g, '<br>'))
if (tb) {
tbplain.one('.textvalue').set('innerHTML', Y.Escape.html(tb.get('value')))
}
'name' => '{NAME}[criteria][{CRITERION-id}][descriptionmarkers]'));
$maxscore = html_writer::tag('div', s($criterion['maxscore']),
array('class'=>'criteriondescriptionscore', 'name' => '{NAME}[criteria][{CRITERION-id}][maxscore]'));
+
+ // Retain newlines as <br> tags when displaying the marking guide.
+ $description = nl2br($description);
+ $descriptionmarkers = nl2br($descriptionmarkers);
}
if (isset($criterion['error_description'])) {
} else {
$description = s($comment['description']);
}
+ // Retain newlines as <br> tags when displaying 'frequently used comments'.
+ $description = nl2br($description);
}
$descriptionclass = 'description';
if (isset($comment['error_description'])) {
$string['clianswerno'] = 'Не';
$string['cliansweryes'] = 'Да';
+$string['cliincorrectvalueerror'] = 'Грешка, некоректна стойност "{$a->value}" за "{$a->option}"';
$string['cliincorrectvalueretry'] = 'Неправилна стойност. Моля опитайте отново';
$string['clitypevalue'] = 'Тип стойност';
+$string['cliyesnoprompt'] = 'Въведете y (означава да) или n (означава не)';
$string['environmentrequireinstall'] = 'Трябва да бъде инсталиран и разрешен';
$string['environmentrequireversion'] = 'Необходима е версия {$a->needed} а Вие имате {$a->current}';
defined('MOODLE_INTERNAL') || die();
$string['parentlanguage'] = '';
-$string['thisdirection'] = 'ltr';
+$string['thisdirection'] = 'izq-a-der';
$string['thislanguage'] = 'Español - México';
$string['clialreadyconfigured'] = 'Конфигурациската датотека config.php веќе постои. Ве молиме користете ја admin/cli/install_database.php за да го инсталирате Moodle на овој сајт.';
$string['clialreadyinstalled'] = 'Конфигурациската датотека config.php веќе постои. Ве молиме користете ја admin/cli/install_database.php за да го надградите Moodle за овој сајт.';
$string['cliinstallheader'] = 'Програма за инсталирање на Moodle {$a} командна линија';
+$string['databasehost'] = 'Домаќин на базата на податоци';
+$string['databasename'] = 'Име на базата на податоци';
+$string['databasetypehead'] = 'Одбери го двигателот на базата за податоци';
$string['dataroot'] = 'Директориум';
+$string['datarootpermission'] = 'Дозвола за директориумот за податоци';
$string['dbprefix'] = 'Префикс на табели';
$string['dirroot'] = 'Moodle директориум';
$string['environmenthead'] = 'Ја проверувам околината...';
<p><blockquote>php_value memory_limit 40M</blockquote></p>
<p>Како и да е, на некои компјутери, ова може да ги спречи <b>сите </b> PHP страници да работат (ќе забележите грешки на страниците) па ќе треба да ја преместите датотеката .htaccess.</p></li>
</ol>';
+$string['pathswrongadmindir'] = 'Администраторскиот директориум не постои';
$string['phpversion'] = 'Верзија на PHP';
$string['phpversionhelp'] = '<p>На Moodle му е потребна верзија на PHP, и тоа најмалку 4.1.0. </p>
<p>Моментално работите на верзијата {$a} </p>
$string['cachedef_locking'] = 'Locking';
$string['cachedef_navigation_expandcourse'] = 'Navigation expandable courses';
$string['cachedef_observers'] = 'Event observers';
+$string['cachedef_plugin_functions'] = 'Plugins available callbacks';
$string['cachedef_plugin_manager'] = 'Plugin info manager';
$string['cachedef_questiondata'] = 'Question definitions';
$string['cachedef_repositories'] = 'Repositories instances data';
$string['resetrecordexpired'] = 'The password reset link you used is more than {$a} minutes old and has expired. Please initiate a new password reset.';
$string['resetstartdate'] = 'Reset start date';
$string['resetstatus'] = 'Status';
+$string['resettable'] = 'Reset table preferences';
$string['resettask'] = 'Task';
$string['resettodefaults'] = 'Reset to defaults';
$string['resortsubcategoriesby'] = 'Sort subcategories by {$a} ascending';
require_once(dirname(__FILE__) . '/../../config.php');
// This should be accessed by only valid logged in user.
-if (!isloggedin() or isguestuser()) {
- die('Invalid access.');
-}
+require_login(null, false);
// This identifies the type of the branch we want to get. Make sure it's SITE_ADMIN.
$branchtype = required_param('type', PARAM_INT);
if ($branchtype !== navigation_node::TYPE_SITE_ADMIN) {
- die('Wrong node type passed.');
+ throw new coding_exception('Incorrect node type passed');
}
// Start capturing output in case of broken plugins.
}
$context = $this->page->context;
- $contexttest = 'bi.parentcontextid = :contextid2';
+ $contexttest = 'bi.parentcontextid IN (:contextid2, :contextid3)';
$parentcontextparams = array();
$parentcontextids = $context->get_parent_context_ids();
if ($parentcontextids) {
$ccselect = ', ' . context_helper::get_preload_record_columns_sql('ctx');
$ccjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = bi.id AND ctx.contextlevel = :contextlevel)";
+ $systemcontext = context_system::instance();
$params = array(
'contextlevel' => CONTEXT_BLOCK,
'subpage1' => $this->page->subpage,
'subpage2' => $this->page->subpage,
'contextid1' => $context->id,
'contextid2' => $context->id,
+ 'contextid3' => $systemcontext->id,
'pagetype' => $this->page->pagetype,
);
if ($this->page->subpage === '') {
if (is_web_crawler()) {
$user = guest_user();
}
- if (!empty($CFG->guestloginbutton) and !$user and !empty($_SERVER['HTTP_REFERER'])) {
+ $referer = get_local_referer(false);
+ if (!empty($CFG->guestloginbutton) and !$user and !empty($referer)) {
// Automatically log in users coming from search engine results.
- if (strpos($_SERVER['HTTP_REFERER'], 'google') !== false ) {
+ if (strpos($referer, 'google') !== false ) {
$user = guest_user();
- } else if (strpos($_SERVER['HTTP_REFERER'], 'altavista') !== false ) {
+ } else if (strpos($referer, 'altavista') !== false ) {
$user = guest_user();
}
}
'simplekeys' => true,
'simpledata' => true,
),
+
+ // Caches plugins existing functions by function name and file.
+ // Set static acceleration size to 5 to load a few functions.
+ 'plugin_functions' => array(
+ 'mode' => cache_store::MODE_APPLICATION,
+ 'simplekeys' => true,
+ 'simpledata' => true,
+ 'staticacceleration' => true,
+ 'staticaccelerationsize' => 5
+ )
+
);
'core_user_get_users_by_field',
'core_user_add_user_private_files',
'mod_assign_view_grading_table',
+ 'mod_scorm_view_scorm',
),
'enabled' => 0,
'restrictedusers' => 0,
}
/* === Apis deprecated since Moodle 3.0 === */
+/**
+ * Returns the URL of the HTTP_REFERER, less the querystring portion if required.
+ *
+ * @deprecated since Moodle 3.0 MDL-49360 - please do not use this function any more.
+ * @todo Remove this function in Moodle 3.2
+ * @param boolean $stripquery if true, also removes the query part of the url.
+ * @return string The resulting referer or empty string.
+ */
+function get_referer($stripquery = true) {
+ debugging('get_referer() is deprecated. Please use get_local_referer() instead.', DEBUG_DEVELOPER);
+ if (isset($_SERVER['HTTP_REFERER'])) {
+ if ($stripquery) {
+ return strip_querystring($_SERVER['HTTP_REFERER']);
+ } else {
+ return $_SERVER['HTTP_REFERER'];
+ }
+ } else {
+ return '';
+ }
+}
\ No newline at end of file
width: "300px",
showPrevMonth: true,
showNextMonth: true,
- firstdayofweek: config.firstdayofweek,
+ firstdayofweek: parseInt(config.firstdayofweek, 10),
WEEKDAYS_MEDIUM: [
config.sun,
config.mon,
}
public function get_rank() {
- return 50;
+ return 10;
}
}
}
public function get_rank() {
- return 20;
+ return 50;
}
}
}
public function get_rank() {
- return 10;
+ return 20;
}
}
$preventredirect = true;
}
+ if (AJAX_SCRIPT) {
+ // We cannot redirect for AJAX scripts either.
+ $preventredirect = true;
+ }
+
// Setup global $COURSE, themes, language and locale.
if (!empty($courseorid)) {
if (is_object($courseorid)) {
}
// Redirect to the login page if session has expired, only with dbsessions enabled (MDL-35029) to maintain current behaviour.
- if ((!isloggedin() or isguestuser()) && !empty($SESSION->has_timed_out) && !$preventredirect && !empty($CFG->dbsessions)) {
- if ($setwantsurltome) {
- $SESSION->wantsurl = qualified_me();
+ if ((!isloggedin() or isguestuser()) && !empty($SESSION->has_timed_out) && !empty($CFG->dbsessions)) {
+ if ($preventredirect) {
+ throw new require_login_session_timeout_exception();
+ } else {
+ if ($setwantsurltome) {
+ $SESSION->wantsurl = qualified_me();
+ }
+ redirect(get_login_url());
}
- redirect(get_login_url());
}
// If the user is not even logged in yet then make sure they are.
if ($setwantsurltome) {
$SESSION->wantsurl = qualified_me();
}
- if (!empty($_SERVER['HTTP_REFERER'])) {
- $SESSION->fromurl = $_SERVER['HTTP_REFERER'];
+
+ $referer = get_local_referer(false);
+ if (!empty($referer)) {
+ $SESSION->fromurl = $referer;
}
// Give auth plugins an opportunity to authenticate or redirect to an external login page
}
}
- // Set the global $COURSE.
- // TODO MDL-49434: setting current course/cm should be after the check $cm->uservisible .
- if ($cm) {
- $PAGE->set_cm($cm, $course);
- $PAGE->set_pagelayout('incourse');
- } else if (!empty($courseorid)) {
- $PAGE->set_course($course);
- }
-
// Check visibility of activity to current user; includes visible flag, conditional availability, etc.
if ($cm && !$cm->uservisible) {
if ($preventredirect) {
redirect($url, get_string('activityiscurrentlyhidden'));
}
+ // Set the global $COURSE.
+ if ($cm) {
+ $PAGE->set_cm($cm, $course);
+ $PAGE->set_pagelayout('incourse');
+ } else if (!empty($courseorid)) {
+ $PAGE->set_course($course);
+ }
+
// Finally access granted, update lastaccess times.
user_accesstime_log($course->id);
}
// Force logout - may fail if file based sessions used, sorry.
\core\session\manager::kill_user_sessions($user->id);
+ // Generate username from email address, or a fake email.
+ $delemail = !empty($user->email) ? $user->email : $user->username . '.' . $user->id . '@unknownemail.invalid';
+ $delname = clean_param($delemail . "." . time(), PARAM_USERNAME);
+
// Workaround for bulk deletes of users with the same email address.
- $delname = clean_param($user->email . "." . time(), PARAM_USERNAME);
while ($DB->record_exists('user', array('username' => $delname))) { // No need to use mnethostid here.
$delname++;
}
// Cleanup the rest of plugins.
$cleanuplugintypes = array('report', 'coursereport', 'format');
+ $callbacks = get_plugins_with_function('delete_course', 'lib.php');
foreach ($cleanuplugintypes as $type) {
- $plugins = get_plugin_list_with_function($type, 'delete_course', 'lib.php');
- foreach ($plugins as $plugin => $pluginfunction) {
- $pluginfunction($course->id, $showfeedback);
+ if (!empty($callbacks[$type])) {
+ foreach ($callbacks[$type] as $pluginfunction) {
+ $pluginfunction($course->id, $showfeedback);
+ }
}
if ($showfeedback) {
echo $OUTPUT->notification($strdeleted.get_string('type_'.$type.'_plural', 'plugin'), 'notifysuccess');
* and the function names as values (e.g. 'report_courselist_hook', 'forum_hook').
*/
function get_plugin_list_with_function($plugintype, $function, $file = 'lib.php') {
+ global $CFG;
+
+ // We don't include here as all plugin types files would be included.
+ $plugins = get_plugins_with_function($function, $file, false);
+
+ if (empty($plugins[$plugintype])) {
+ return array();
+ }
+
+ $allplugins = core_component::get_plugin_list($plugintype);
+
+ // Reformat the array and include the files.
$pluginfunctions = array();
- $pluginswithfile = core_component::get_plugin_list_with_file($plugintype, $file, true);
- foreach ($pluginswithfile as $plugin => $notused) {
- $fullfunction = $plugintype . '_' . $plugin . '_' . $function;
+ foreach ($plugins[$plugintype] as $pluginname => $functionname) {
- if (function_exists($fullfunction)) {
- // Function exists with standard name. Store, indexed by frankenstyle name of plugin.
- $pluginfunctions[$plugintype . '_' . $plugin] = $fullfunction;
+ // Check that it has not been removed and the file is still available.
+ if (!empty($allplugins[$pluginname])) {
- } else if ($plugintype === 'mod') {
- // For modules, we also allow plugin without full frankenstyle but just starting with the module name.
- $shortfunction = $plugin . '_' . $function;
- if (function_exists($shortfunction)) {
- $pluginfunctions[$plugintype . '_' . $plugin] = $shortfunction;
+ $filepath = $allplugins[$pluginname] . DIRECTORY_SEPARATOR . $file;
+ if (file_exists($filepath)) {
+ include_once($filepath);
+ $pluginfunctions[$plugintype . '_' . $pluginname] = $functionname;
}
}
}
+
return $pluginfunctions;
}
+/**
+ * Get a list of all the plugins that define a certain API function in a certain file.
+ *
+ * @param string $function the part of the name of the function after the
+ * frankenstyle prefix. e.g 'hook' if you are looking for functions with
+ * names like report_courselist_hook.
+ * @param string $file the name of file within the plugin that defines the
+ * function. Defaults to lib.php.
+ * @param bool $include Whether to include the files that contain the functions or not.
+ * @return array with [plugintype][plugin] = functionname
+ */
+function get_plugins_with_function($function, $file = 'lib.php', $include = true) {
+ global $CFG;
+
+ $cache = \cache::make('core', 'plugin_functions');
+
+ // Including both although I doubt that we will find two functions definitions with the same name.
+ // Clearning the filename as cache_helper::hash_key only allows a-zA-Z0-9_.
+ $key = $function . '_' . clean_param($file, PARAM_ALPHA);
+
+ if ($pluginfunctions = $cache->get($key)) {
+
+ // Checking that the files are still available.
+ foreach ($pluginfunctions as $plugintype => $plugins) {
+
+ $allplugins = \core_component::get_plugin_list($plugintype);
+ foreach ($plugins as $plugin => $fullpath) {
+
+ // Cache might be out of sync with the codebase, skip the plugin if it is not available.
+ if (empty($allplugins[$plugin])) {
+ unset($pluginfunctions[$plugintype][$plugin]);
+ continue;
+ }
+
+ $fileexists = file_exists($allplugins[$plugin] . DIRECTORY_SEPARATOR . $file);
+ if ($include && $fileexists) {
+ // Include the files if it was requested.
+ include_once($allplugins[$plugin] . DIRECTORY_SEPARATOR . $file);
+ } else if (!$fileexists) {
+ // If the file is not available any more it should not be returned.
+ unset($pluginfunctions[$plugintype][$plugin]);
+ }
+ }
+ }
+ return $pluginfunctions;
+ }
+
+ $pluginfunctions = array();
+
+ // To fill the cached. Also, everything should continue working with cache disabled.
+ $plugintypes = \core_component::get_plugin_types();
+ foreach ($plugintypes as $plugintype => $unused) {
+
+ // We need to include files here.
+ $pluginswithfile = \core_component::get_plugin_list_with_file($plugintype, $file, true);
+ foreach ($pluginswithfile as $plugin => $notused) {
+
+ $fullfunction = $plugintype . '_' . $plugin . '_' . $function;
+
+ $pluginfunction = false;
+ if (function_exists($fullfunction)) {
+ // Function exists with standard name. Store, indexed by frankenstyle name of plugin.
+ $pluginfunction = $fullfunction;
+
+ } else if ($plugintype === 'mod') {
+ // For modules, we also allow plugin without full frankenstyle but just starting with the module name.
+ $shortfunction = $plugin . '_' . $function;
+ if (function_exists($shortfunction)) {
+ $pluginfunction = $shortfunction;
+ }
+ }
+
+ if ($pluginfunction) {
+ if (empty($pluginfunctions[$plugintype])) {
+ $pluginfunctions[$plugintype] = array();
+ }
+ $pluginfunctions[$plugintype][$plugin] = $pluginfunction;
+ }
+
+ }
+ }
+ $cache->set($key, $pluginfunctions);
+
+ return $pluginfunctions;
+
+}
+
/**
* Lists plugin-like directories within specified directory
*
}
}
- // Let admin tools hook into course navigation.
- $tools = get_plugin_list_with_function('tool', 'extend_navigation_course', 'lib.php');
- foreach ($tools as $toolfunction) {
- $toolfunction($coursenode, $course, $coursecontext);
+ // Let plugins hook into course navigation.
+ $pluginsfunction = get_plugins_with_function('extend_navigation_course', 'lib.php');
+ foreach ($pluginsfunction as $plugintype => $plugins) {
+ foreach ($plugins as $pluginfunction) {
+ $pluginfunction($coursenode, $course, $coursecontext);
+ }
}
// Return we are done
}
}
- // Let admin tools hook into user settings navigation.
- $tools = get_plugin_list_with_function('tool', 'extend_navigation_user_settings', 'lib.php');
- foreach ($tools as $toolfunction) {
- $toolfunction($usersetting, $user, $usercontext, $course, $coursecontext);
+ // Let plugins hook into user settings navigation.
+ $pluginsfunction = get_plugins_with_function('extend_navigation_user_settings', 'lib.php');
+ foreach ($pluginsfunction as $plugintype => $plugins) {
+ foreach ($plugins as $pluginfunction) {
+ $pluginfunction($usersetting, $user, $usercontext, $course, $coursecontext);
+ }
}
return $usersetting;
$frontpage->add(get_string('sitelegacyfiles'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/folder', ''));
}
- // Let admin tools hook into frontpage navigation.
- $tools = get_plugin_list_with_function('tool', 'extend_navigation_frontpage', 'lib.php');
- foreach ($tools as $toolfunction) {
- $toolfunction($frontpage, $course, $coursecontext);
+ // Let plugins hook into frontpage navigation.
+ $pluginsfunction = get_plugins_with_function('extend_navigation_frontpage', 'lib.php');
+ foreach ($pluginsfunction as $plugintype => $plugins) {
+ foreach ($plugins as $pluginfunction) {
+ $pluginfunction($frontpage, $course, $coursecontext);
+ }
}
return $frontpage;
|| false !== strpos($uagent, 'Mac')) {
// Looks good in Win XP/Mac/Opera 8/9, Mac/Firefox 2, Camino, Safari.
// Not broken in Mac/IE 5, Mac/Netscape 7 (?).
- $this->rarrow = '▶';
- $this->larrow = '◀';
+ $this->rarrow = '▶︎';
+ $this->larrow = '◀︎';
}
elseif ((false !== strpos($uagent, 'Konqueror'))
|| (false !== strpos($uagent, 'Android'))) {
}
}
+ $devicetheme = core_useragent::get_device_type_theme($this->devicetypeinuse);
+
+ // The user is using another device than default, and we have a theme for that, we should use it.
+ $hascustomdevicetheme = core_useragent::DEVICETYPE_DEFAULT != $this->devicetypeinuse && !empty($devicetheme);
+
foreach ($themeorder as $themetype) {
+
switch ($themetype) {
case 'course':
- if (!empty($CFG->allowcoursethemes) && !empty($this->_course->theme) && $this->devicetypeinuse == 'default') {
+ if (!empty($CFG->allowcoursethemes) && !empty($this->_course->theme) && !$hascustomdevicetheme) {
return $this->_course->theme;
}
break;
case 'category':
- if (!empty($CFG->allowcategorythemes) && $this->devicetypeinuse == 'default') {
+ if (!empty($CFG->allowcategorythemes) && !$hascustomdevicetheme) {
$categories = $this->categories;
foreach ($categories as $category) {
if (!empty($category->theme)) {
break;
case 'user':
- if (!empty($CFG->allowuserthemes) && !empty($USER->theme) && $this->devicetypeinuse == 'default') {
+ if (!empty($CFG->allowuserthemes) && !empty($USER->theme) && !$hascustomdevicetheme) {
if ($mnetpeertheme) {
return $mnetpeertheme;
} else {
return $mnetpeertheme;
}
// First try for the device the user is using.
- $devicetheme = core_useragent::get_device_type_theme($this->devicetypeinuse);
if (!empty($devicetheme)) {
return $devicetheme;
}
// Next try for the default device (as a fallback).
- $devicetheme = core_useragent::get_device_type_theme('default');
+ $devicetheme = core_useragent::get_device_type_theme(core_useragent::DEVICETYPE_DEFAULT);
if (!empty($devicetheme)) {
return $devicetheme;
}
}
}
+/**
+ * Session timeout exception.
+ *
+ * This exception is thrown from require_login()
+ *
+ * @package core_access
+ * @copyright 2015 Andrew Nicols <andrew@nicols.co.uk>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class require_login_session_timeout_exception extends require_login_exception {
+ /**
+ * Constructor
+ */
+ public function __construct() {
+ moodle_exception::__construct('sessionerroruser', 'error');
+ }
+}
+
/**
* Web service parameter exception class
* @deprecated since Moodle 2.2 - use moodle exception instead
define('TABLE_VAR_IFIRST', 4);
define('TABLE_VAR_ILAST', 5);
define('TABLE_VAR_PAGE', 6);
+define('TABLE_VAR_RESET', 7);
/**#@-*/
/**#@+
TABLE_VAR_IFIRST => 'tifirst',
TABLE_VAR_ILAST => 'tilast',
TABLE_VAR_PAGE => 'page',
+ TABLE_VAR_RESET => 'treset'
);
}
$this->prefs['i_first'] = $ifirst;
}
+ // Allow user to reset table preferences.
+ if (optional_param($this->request[TABLE_VAR_RESET], 0, PARAM_BOOL) === 1) {
+ $this->prefs = array(
+ 'collapse' => array(),
+ 'sortby' => array(),
+ 'i_first' => '',
+ 'i_last' => '',
+ 'textsort' => $this->column_textsort,
+ );
+ }
+
// Save user preferences if they have changed.
if ($this->prefs != $oldprefs) {
if ($this->persistent) {
*/
function print_nothing_to_display() {
global $OUTPUT;
+
+ // Render button to allow user to reset table preferences.
+ echo $this->render_reset_button();
+
$this->print_initials_bar();
echo $OUTPUT->heading(get_string('nothingtodisplay'));
*/
function start_html() {
global $OUTPUT;
+
+ // Render button to allow user to reset table preferences.
+ echo $this->render_reset_button();
+
// Do we need to print initial bars?
$this->print_initials_bar();
}
return $string;
}
+
+ /**
+ * Generate the HTML for the table preferences reset button.
+ *
+ * @return string HTML fragment.
+ */
+ private function render_reset_button() {
+ $url = $this->baseurl->out(false, array($this->request[TABLE_VAR_RESET] => 1));
+
+ $html = html_writer::start_div('mdl-right');
+ $html .= html_writer::link($url, get_string('resettable'));
+ $html .= html_writer::end_div();
+
+ return $html;
+ }
}
$record['userid'] = $USER->id;
}
- if (!isset($record['name'])) {
- $record['name'] = 'Tag name ' . $i;
+ if (!isset($record['rawname'])) {
+ if (isset($record['name'])) {
+ $record['rawname'] = $record['name'];
+ } else {
+ $record['rawname'] = 'Tag name ' . $i;
+ }
}
- if (!isset($record['rawname'])) {
- $record['rawname'] = 'Raw tag name ' . $i;
+ // Attribute 'name' should be a lowercase version of 'rawname', if not set.
+ if (!isset($record['name'])) {
+ $record['name'] = core_text::strtolower($record['rawname']);
+ } else {
+ $record['name'] = core_text::strtolower($record['name']);
}
if (!isset($record['tagtype'])) {
'required' => array('qtype', 'questioncategory', 'name'),
'switchids' => array('questioncategory' => 'category', 'user' => 'createdby')
),
+ 'tags' => array(
+ 'datagenerator' => 'tag',
+ 'required' => array('name')
+ ),
);
/**
$CFG->core_media_enable_mp3 = true;
$renderer = new core_media_renderer_test($PAGE, '');
$this->assertSame('mp3, html5audio, link', $renderer->get_players_test());
+
+ // Test QT and HTML5 media order.
+ $CFG->core_media_enable_mp3 = false;
+ $CFG->core_media_enable_html5video = true;
+ $CFG->core_media_enable_qt = true;
+ $renderer = new core_media_renderer_test($PAGE, '');
+ $this->assertSame('html5video, html5audio, qt, link', $renderer->get_players_test());
}
/**
public function test_embed_url_fallbacks() {
global $CFG, $PAGE;
+ // Key strings in the embed code that identify with the media formats being tested.
+ $qt = 'qtplugin.cab';
+ $html5video = '</video>';
+ $html5audio = '</audio>';
+ $link = 'mediafallbacklink';
+ $mp3 = 'mediaplugin_mp3';
+
$url = new moodle_url('http://example.org/test.mp4');
// All plugins disabled, NOLINK option.
// All plugins disabled but not NOLINK.
$renderer = new core_media_renderer_test($PAGE, '');
$t = $renderer->embed_url($url);
- $this->assert_contents(false, false, true, $t);
+ $this->assertContains($link, $t);
- // HTML5 plugin enabled.
+ // Enable media players that can play the same media formats. (ie. qt & html5video for mp4 files, etc.)
$CFG->core_media_enable_html5video = true;
- $renderer = new core_media_renderer_test($PAGE, '');
- $t = $renderer->embed_url($url);
- $this->assert_contents(false, true, true, $t);
-
- // QT plugin enabled as well.
+ $CFG->core_media_enable_html5audio = true;
+ $CFG->core_media_enable_mp3 = true;
$CFG->core_media_enable_qt = true;
- $renderer = new core_media_renderer_test($PAGE, '');
- $t = $renderer->embed_url($url);
- $this->assert_contents(true, true, true, $t);
- // Nolink turned off, plugins still enabled.
- $t = $renderer->embed_url($url, 0, 0, '',
- array(core_media::OPTION_NO_LINK => true));
- $this->assert_contents(true, true, false, $t);
- }
-
- /**
- * Checks the contents of the resulting HTML code to ensure it used the
- * correct embed method(s).
- *
- * @param bool $hasqt True if it should have QT embed code
- * @param bool $hashtml5 True if it should have HTML5 embed code
- * @param bool $haslink True if it should have a fallback link
- * @param string $text HTML content
- */
- private function assert_contents($hasqt, $hashtml5, $haslink, $text) {
- // I tried to avoid making it specific to the exact details of the html
- // code, picking out only single key strings that would let it check
- // whether final code contains the right things.
- $qt = 'qtplugin.cab';
- $html5 = '</video>';
- $link = 'mediafallbacklink';
-
- if ($hasqt) {
- $this->assertContains($qt, $text);
- } else {
- $this->assertNotContains($qt, $text);
- }
-
- if ($hashtml5) {
- $this->assertContains($html5, $text);
- } else {
- $this->assertNotContains($html5, $text);
- }
-
- if ($haslink) {
- $this->assertContains($link, $text);
- } else {
- $this->assertNotContains($link, $text);
+ // Test media formats that can be played by 2 or more players.
+ $mediaformats = array('mp3', 'm4a', 'mp4', 'm4v');
+
+ foreach ($mediaformats as $format) {
+ $url = new moodle_url('http://example.org/test.' . $format);
+ $renderer = new core_media_renderer_test($PAGE, '');
+ $textwithlink = $renderer->embed_url($url);
+ $textwithoutlink = $renderer->embed_url($url, 0, 0, '', array(core_media::OPTION_NO_LINK => true));
+
+ switch ($format) {
+ case 'mp3':
+ $this->assertContains($mp3, $textwithlink);
+ $this->assertContains($html5audio, $textwithlink);
+ $this->assertContains($link, $textwithlink);
+
+ $this->assertContains($mp3, $textwithoutlink);
+ $this->assertContains($html5audio, $textwithoutlink);
+ $this->assertNotContains($link, $textwithoutlink);
+ break;
+
+ case 'm4a':
+ $this->assertContains($qt, $textwithlink);
+ $this->assertContains($html5audio, $textwithlink);
+ $this->assertContains($link, $textwithlink);
+
+ $this->assertContains($qt, $textwithoutlink);
+ $this->assertContains($html5audio, $textwithoutlink);
+ $this->assertNotContains($link, $textwithoutlink);
+ break;
+
+ case 'mp4':
+ case 'm4v':
+ $this->assertContains($qt, $textwithlink);
+ $this->assertContains($html5video, $textwithlink);
+ $this->assertContains($link, $textwithlink);
+
+ $this->assertContains($qt, $textwithoutlink);
+ $this->assertContains($html5video, $textwithoutlink);
+ $this->assertNotContains($link, $textwithoutlink);
+ break;
+
+ default:
+ break;
+ }
}
}
$user = $this->getDataGenerator()->create_user(array('idnumber'=>'abc'));
$user2 = $this->getDataGenerator()->create_user(array('idnumber'=>'xyz'));
+ $usersharedemail1 = $this->getDataGenerator()->create_user(array('email' => 'sharedemail@example.invalid'));
+ $usersharedemail2 = $this->getDataGenerator()->create_user(array('email' => 'sharedemail@example.invalid'));
+ $useremptyemail1 = $this->getDataGenerator()->create_user(array('email' => ''));
+ $useremptyemail2 = $this->getDataGenerator()->create_user(array('email' => ''));
// Delete user and capture event.
$sink = $this->redirectEvents();
$result = delete_user($admin);
$this->assertFalse($result);
+ // Simultaneously deleting users with identical email addresses.
+ $result1 = delete_user($usersharedemail1);
+ $result2 = delete_user($usersharedemail2);
+
+ $usersharedemail1after = $DB->get_record('user', array('id' => $usersharedemail1->id));
+ $usersharedemail2after = $DB->get_record('user', array('id' => $usersharedemail2->id));
+ $this->assertTrue($result1);
+ $this->assertTrue($result2);
+ $this->assertStringStartsWith($usersharedemail1->email . '.', $usersharedemail1after->username);
+ $this->assertStringStartsWith($usersharedemail2->email . '.', $usersharedemail2after->username);
+
+ // Simultaneously deleting users without email addresses.
+ $result1 = delete_user($useremptyemail1);
+ $result2 = delete_user($useremptyemail2);
+
+ $useremptyemail1after = $DB->get_record('user', array('id' => $useremptyemail1->id));
+ $useremptyemail2after = $DB->get_record('user', array('id' => $useremptyemail2->id));
+ $this->assertTrue($result1);
+ $this->assertTrue($result2);
+ $this->assertStringStartsWith($useremptyemail1->username . '.' . $useremptyemail1->id . '@unknownemail.invalid.',
+ $useremptyemail1after->username);
+ $this->assertStringStartsWith($useremptyemail2->username . '.' . $useremptyemail2->id . '@unknownemail.invalid.',
+ $useremptyemail2after->username);
+
$this->resetDebugging();
}
=== 3.0 ===
+* get_referer() has been deprecated, please use the get_local_referer function instead.
* \core\progress\null is renamed to \core\progress\none for improved PHP7 compatibility as null is a reserved word (see MDL-50453).
* \webservice_xmlrpc_client now respects proxy server settings. If your XMLRPC server is available on your local network and not via your proxy server, you may need to add it to the list of proxy
server exceptions in $CFG->proxybypass. See MDL-39353 for details.
}
}
-/**
- * Returns the URL of the HTTP_REFERER, less the querystring portion if required.
- *
- * @param boolean $stripquery if true, also removes the query part of the url.
- * @return string The resulting referer or empty string.
- */
-function get_referer($stripquery=true) {
- if (isset($_SERVER['HTTP_REFERER'])) {
- if ($stripquery) {
- return strip_querystring($_SERVER['HTTP_REFERER']);
- } else {
- return $_SERVER['HTTP_REFERER'];
- }
- } else {
- return '';
- }
-}
-
/**
* Returns the name of the current script, WITH the querystring portion.
*
return (strpos($CFG->httpswwwroot, 'https://') === 0);
}
+/**
+ * Returns the cleaned local URL of the HTTP_REFERER less the URL query string parameters if required.
+ *
+ * @param bool $stripquery if true, also removes the query part of the url.
+ * @return string The resulting referer or empty string.
+ */
+function get_local_referer($stripquery = true) {
+ if (isset($_SERVER['HTTP_REFERER'])) {
+ $referer = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+ if ($stripquery) {
+ return strip_querystring($referer);
+ } else {
+ return $referer;
+ }
+ } else {
+ return '';
+ }
+}
+
/**
* Class for creating and manipulating urls.
*
if (!this.in_group(drag)) {
return;
}
+ // Store the nodes current style, so we can restore it later.
+ this.originalstyle = drag.get('node').getAttribute('style');
// Set some general styles here
drag.get('node').setStyle('opacity', '.25');
drag.get('dragNode').setStyles({
return;
}
//Put our general styles back
- drag.get('node').setStyles({
- visibility: '',
- opacity: '1'
- });
+ drag.get('node').setAttribute('style', this.originalstyle);
this.drag_end(e);
},
/// First, let's remember where the user was trying to get to before they got here
if (empty($SESSION->wantsurl)) {
- $SESSION->wantsurl = (array_key_exists('HTTP_REFERER',$_SERVER) &&
- $_SERVER["HTTP_REFERER"] != $CFG->wwwroot &&
- $_SERVER["HTTP_REFERER"] != $CFG->wwwroot.'/' &&
- $_SERVER["HTTP_REFERER"] != $CFG->httpswwwroot.'/login/' &&
- strpos($_SERVER["HTTP_REFERER"], $CFG->httpswwwroot.'/login/?') !== 0 &&
- strpos($_SERVER["HTTP_REFERER"], $CFG->httpswwwroot.'/login/index.php') !== 0 &&
- clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL) != '')
- // There might be some extra params such as ?lang=.
- ? $_SERVER["HTTP_REFERER"] : NULL;
+ $SESSION->wantsurl = null;
+ $referer = get_local_referer(false);
+ if ($referer &&
+ $referer != $CFG->wwwroot &&
+ $referer != $CFG->wwwroot . '/' &&
+ $referer != $CFG->httpswwwroot . '/login/' &&
+ strpos($referer, $CFG->httpswwwroot . '/login/?') !== 0 &&
+ strpos($referer, $CFG->httpswwwroot . '/login/index.php') !== 0) { // There might be some extra params such as ?lang=.
+ $SESSION->wantsurl = $referer;
+ }
}
/// Redirect to alternative login URL if needed
'preventsubmissionnotingroup',
'assign');
$mform->setType('preventsubmissionnotingroup', PARAM_BOOL);
+ $mform->disabledIf('preventsubmissionnotingroup', 'teamsubmission', 'eq', 0);
$name = get_string('requireallteammemberssubmit', 'assign');
$mform->addElement('selectyesno', 'requireallteammemberssubmit', $name);
$setting->set_locked_flag_options(admin_setting_flag::ENABLED, false);
$settings->add($setting);
+ $name = new lang_string('preventsubmissionnotingroup', 'mod_assign');
+ $description = new lang_string('preventsubmissionnotingroup_help', 'mod_assign');
+ $setting = new admin_setting_configcheckbox('assign/preventsubmissionnotingroup',
+ $name,
+ $description,
+ 0);
+ $setting->set_advanced_flag_options(admin_setting_flag::ENABLED, false);
+ $setting->set_locked_flag_options(admin_setting_flag::ENABLED, false);
+ $settings->add($setting);
+
$name = new lang_string('requireallteammemberssubmit', 'mod_assign');
$description = new lang_string('requireallteammemberssubmit_help', 'mod_assign');
$setting = new admin_setting_configcheckbox('assign/requireallteammemberssubmit',
$setting->set_advanced_flag_options(admin_setting_flag::ENABLED, false);
$setting->set_locked_flag_options(admin_setting_flag::ENABLED, false);
$settings->add($setting);
-
- $name = new lang_string('preventsubmissionnotingroup', 'mod_assign');
- $description = new lang_string('preventsubmissionnotingroup_help', 'mod_assign');
- $setting = new admin_setting_configcheckbox('assign/preventsubmissionnotingroup',
- $name,
- $description,
- 0);
- $setting->set_advanced_flag_options(admin_setting_flag::ENABLED, false);
- $setting->set_locked_flag_options(admin_setting_flag::ENABLED, false);
- $settings->add($setting);
}
$ADMIN->add('modassignfolder', $settings);
}
/* toc style NONE */
-.path-mod-book .book_toc_none {
- font-size: 0.8em;
-}
.path-mod-book .book_toc_none ul ul,
.dir-rtl.path-mod-book .book_toc_none ul ul {
margin-left: 0;
}
/*toc style BULLETS */
-.path-mod-book .book_toc_bullets {
- font-size: 0.8em;
-}
.path-mod-book .book_toc_bullets ul ul {
margin-left: 20px;
}
list-style: circle;
}
-/* toc style INDENTED*/
-.path-mod-book .book_toc_indented {
- font-size: 0.8em;
+.path-mod-book .book_toc_bullets li li:before {
+ display: none;
}
+
+/* toc style INDENTED*/
.path-mod-book .book_toc_indented ul {
margin-left: 5px;
}
} else if (!is_enrolled($context)) {
// Only people enrolled can make a choice
$SESSION->wantsurl = qualified_me();
- $SESSION->enrolcancel = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+ $SESSION->enrolcancel = get_local_referer(false);
$coursecontext = context_course::instance($course->id);
$courseshortname = format_string($course->shortname, true, array('context' => $coursecontext));
global $CFG, $SESSION;
if (! isset($SESSION->fromdiscussion)) {
- $referer = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+ $referer = get_local_referer(false);
// If the referer is NOT a login screen then save it.
if (! strncasecmp("$CFG->wwwroot/login", $referer, 300)) {
$SESSION->fromdiscussion = $referer;
// if (forum_tp_start_tracking($forum->id, $user->id)) {
// redirect($returnto, get_string("nowtracking", "forum", $info), 1);
// } else {
-// print_error("Could not start tracking that forum", $_SERVER["HTTP_REFERER"]);
+// print_error("Could not start tracking that forum", get_local_referer());
// }
}
if (!isloggedin() or isguestuser()) {
- if (!isloggedin() and !get_referer()) {
+ if (!isloggedin() and !get_local_referer()) {
// No referer+not logged in - probably coming in via email See MDL-9052
require_login();
}
$PAGE->set_context($modcontext);
$PAGE->set_title($course->shortname);
$PAGE->set_heading($course->fullname);
- $referer = clean_param(get_referer(false), PARAM_LOCALURL);
+ $referer = get_local_referer(false);
echo $OUTPUT->header();
echo $OUTPUT->confirm(get_string('noguestpost', 'forum').'<br /><br />'.get_string('liketologin'), get_login_url(), $referer);
if (!is_enrolled($coursecontext)) {
if (enrol_selfenrol_available($course->id)) {
$SESSION->wantsurl = qualified_me();
- $SESSION->enrolcancel = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+ $SESSION->enrolcancel = get_local_referer(false);
redirect(new moodle_url('/enrol/index.php', array('id' => $course->id,
'returnurl' => '/mod/forum/view.php?f=' . $forum->id)),
get_string('youneedtoenrol'));
print_error("activityiscurrentlyhidden");
}
- if (isset($_SERVER["HTTP_REFERER"])) {
- $SESSION->fromurl = $_SERVER["HTTP_REFERER"];
- } else {
- $SESSION->fromurl = '';
- }
+ $SESSION->fromurl = get_local_referer(false);
// Load up the $post variable.
if (!isguestuser()) {
if (!is_enrolled($coursecontext)) { // User is a guest here!
$SESSION->wantsurl = qualified_me();
- $SESSION->enrolcancel = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+ $SESSION->enrolcancel = get_local_referer(false);
redirect(new moodle_url('/enrol/index.php', array('id' => $course->id,
'returnurl' => '/mod/forum/view.php?f=' . $forum->id)),
get_string('youneedtoenrol'));
if ($prev) {
$url = new moodle_url('/mod/forum/discuss.php', array('d' => $prev->id));
$html .= html_writer::start_tag('li', array('class' => 'prev-discussion'));
- $html .= html_writer::link($url, $prev->name,
- array('aria-label' => get_string('prevdiscussiona', 'mod_forum', $prev->name)));
+ $html .= html_writer::link($url, format_string($prev->name),
+ array('aria-label' => get_string('prevdiscussiona', 'mod_forum', format_string($prev->name))));
$html .= html_writer::end_tag('li');
}
if ($next) {
$url = new moodle_url('/mod/forum/discuss.php', array('d' => $next->id));
$html .= html_writer::start_tag('li', array('class' => 'next-discussion'));
- $html .= html_writer::link($url, $next->name,
- array('aria-label' => get_string('nextdiscussiona', 'mod_forum', $next->name)));
+ $html .= html_writer::link($url, format_string($next->name),
+ array('aria-label' => get_string('nextdiscussiona', 'mod_forum', format_string($next->name))));
$html .= html_writer::end_tag('li');
}
$html .= html_writer::end_tag('ul');
$event->trigger();
redirect($returnto, get_string("nownottracking", "forum", $info), 1);
} else {
- print_error('cannottrack', '', $_SERVER["HTTP_REFERER"]);
+ print_error('cannottrack', '', get_local_referer(false));
}
} else { // subscribe
$event->trigger();
redirect($returnto, get_string("nowtracking", "forum", $info), 1);
} else {
- print_error('cannottrack', '', $_SERVER["HTTP_REFERER"]);
+ print_error('cannottrack', '', get_local_referer(false));
}
}
if (\mod_forum\subscriptions::unsubscribe_user($user->id, $forum, $context, true)) {
redirect($returnto, get_string("nownotsubscribed", "forum", $info), 1);
} else {
- print_error('cannotunsubscribe', 'forum', $_SERVER["HTTP_REFERER"]);
+ print_error('cannotunsubscribe', 'forum', get_local_referer(false));
}
} else {
if (\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion, $context)) {
$info->discussion = $discussion->name;
redirect($returnto, get_string("discussionnownotsubscribed", "forum", $info), 1);
} else {
- print_error('cannotunsubscribe', 'forum', $_SERVER["HTTP_REFERER"]);
+ print_error('cannotunsubscribe', 'forum', get_local_referer(false));
}
}
} else { // subscribe
if (\mod_forum\subscriptions::subscription_disabled($forum) && !has_capability('mod/forum:managesubscriptions', $context)) {
- print_error('disallowsubscribe', 'forum', $_SERVER["HTTP_REFERER"]);
+ print_error('disallowsubscribe', 'forum', get_local_referer(false));
}
if (!has_capability('mod/forum:viewdiscussion', $context)) {
- print_error('noviewdiscussionspermission', 'forum', $_SERVER["HTTP_REFERER"]);
+ print_error('noviewdiscussionspermission', 'forum', get_local_referer(false));
}
if (is_null($sesskey)) {
// We came here via link in email.
$hook = $show;
$show = '';
}
-/// Processing standard security processes
-if ($course->id != SITEID) {
- require_login($course);
-}
-if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $context)) {
- echo $OUTPUT->header();
- notice(get_string("activityiscurrentlyhidden"));
-}
/// stablishing flag variables
if ( $sortorder = strtolower($sortorder) ) {
if ($mods = get_course_mods($COURSE->id)) {
$modinstances = array();
foreach ($mods as $mod) {
-
- // get the module name and then store it in a new array
+ // Get the module name and then store it in a new array.
if ($module = get_coursemodule_from_instance($mod->modname, $mod->instance, $COURSE->id)) {
- if (isset($this->_cm->id) and $this->_cm->id != $mod->id){
+ // Exclude this lesson, if it's already been saved.
+ if (!isset($this->_cm->id) || $this->_cm->id != $mod->id) {
$modinstances[$mod->id] = $mod->modname.' - '.$module->name;
}
}
}
- asort($modinstances); // sort by module name
+ asort($modinstances); // Sort by module name.
$modinstances=array(0=>get_string('none'))+$modinstances;
$mform->addElement('select', 'activitylink', get_string('activitylink', 'lesson'), $modinstances);
$output .= $this->view_information($quiz, $cm, $context, $messages);
$guestno = html_writer::tag('p', get_string('guestsno', 'quiz'));
$liketologin = html_writer::tag('p', get_string('liketologin'));
- $referer = clean_param(get_referer(false), PARAM_LOCALURL);
+ $referer = get_local_referer(false);
$output .= $this->confirm($guestno."\n\n".$liketologin."\n", get_login_url(), $referer);
return $output;
}
// For 'open' and 'download' links, we always redirect to the content - except
// if the user just chose 'save and display' from the form then that would be
// confusing
- if (!isset($_SERVER['HTTP_REFERER']) || strpos($_SERVER['HTTP_REFERER'], 'modedit.php') === false) {
+ if (strpos(get_local_referer(false), 'modedit.php') === false) {
$redirect = true;
}
}
--- /dev/null
+<?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/>.
+
+/**
+ * SCORM module external API
+ *
+ * @package mod_scorm
+ * @category external
+ * @copyright 2015 Juan Leyva <juan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since Moodle 3.0
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+require_once($CFG->libdir . '/externallib.php');
+require_once($CFG->dirroot . '/mod/scorm/lib.php');
+
+/**
+ * SCORM module external functions
+ *
+ * @package mod_scorm
+ * @category external
+ * @copyright 2015 Juan Leyva <juan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since Moodle 3.0
+ */
+class mod_scorm_external extends external_api {
+
+ /**
+ * Returns description of method parameters
+ *
+ * @return external_function_parameters
+ * @since Moodle 3.0
+ */
+ public static function view_scorm_parameters() {
+ return new external_function_parameters(
+ array(
+ 'scormid' => new external_value(PARAM_INT, 'scorm instance id')
+ )
+ );
+ }
+
+ /**
+ * Trigger the course module viewed event.
+ *
+ * @param int $scormid the scorm instance id
+ * @return array of warnings and status result
+ * @since Moodle 3.0
+ * @throws moodle_exception
+ */
+ public static function view_scorm($scormid) {
+ global $DB, $CFG;
+ require_once($CFG->dirroot . '/mod/scorm/lib.php');
+
+ $params = self::validate_parameters(self::view_scorm_parameters(),
+ array(
+ 'scormid' => $scormid
+ ));
+ $warnings = array();
+
+ // Request and permission validation.
+ $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST);
+ list($course, $cm) = get_course_and_cm_from_instance($scorm, 'scorm');
+
+ $context = context_module::instance($cm->id);
+ self::validate_context($context);
+
+ // Call the scorm/lib API.
+ scorm_view($scorm, $course, $cm, $context);
+
+ $result = array();
+ $result['status'] = true;
+ $result['warnings'] = $warnings;
+ return $result;
+ }
+
+ /**
+ * Returns description of method result value
+ *
+ * @return external_description
+ * @since Moodle 3.0
+ */
+ public static function view_scorm_returns() {
+ return new external_single_structure(
+ array(
+ 'status' => new external_value(PARAM_BOOL, 'status: true if success'),
+ 'warnings' => new external_warnings()
+ )
+ );
+ }
+}
--- /dev/null
+<?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/>.
+
+/**
+ * SCORM external functions and service definitions.
+ *
+ * @package mod_scorm
+ * @category external
+ * @copyright 2015 Juan Leyva <juan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since Moodle 3.0
+ */
+
+$functions = array(
+
+ 'mod_scorm_view_scorm' => array(
+ 'classname' => 'mod_scorm_external',
+ 'methodname' => 'view_scorm',
+ 'description' => 'Trigger the course module viewed event.',
+ 'type' => 'write',
+ 'capabilities' => ''
+ ),
+);
}
}
}
+
+/**
+ * Trigger the course_module_viewed event.
+ *
+ * @param stdClass $scorm scorm object
+ * @param stdClass $course course object
+ * @param stdClass $cm course module object
+ * @param stdClass $context context object
+ * @since Moodle 3.0
+ */
+function scorm_view($scorm, $course, $cm, $context) {
+
+ // Trigger course_module_viewed event.
+ $params = array(
+ 'context' => $context,
+ 'objectid' => $scorm->id
+ );
+
+ $event = \mod_scorm\event\course_module_viewed::create($params);
+ $event->add_record_snapshot('course_modules', $cm);
+ $event->add_record_snapshot('course', $course);
+ $event->add_record_snapshot('scorm', $scorm);
+ $event->trigger();
+}
return $attemptids;
}
-function scorm_view_display ($user, $scorm, $action, $cm) {
+/**
+ * Displays the entry form and toc if required.
+ *
+ * @param stdClass $user user object
+ * @param stdClass $scorm scorm object
+ * @param string $action base URL for the organizations select box
+ * @param stdClass $cm course module object
+ */
+function scorm_print_launch ($user, $scorm, $action, $cm) {
global $CFG, $DB, $PAGE, $OUTPUT, $COURSE;
if ($scorm->updatefreq == SCORM_UPDATE_EVERYTIME) {
--- /dev/null
+<?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/>.
+
+/**
+ * SCORM module external functions tests
+ *
+ * @package mod_scorm
+ * @category external
+ * @copyright 2015 Juan Leyva <juan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since Moodle 3.0
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+
+require_once($CFG->dirroot . '/webservice/tests/helpers.php');
+require_once($CFG->dirroot . '/mod/scorm/lib.php');
+
+/**
+ * SCORM module external functions tests
+ *
+ * @package mod_scorm
+ * @category external
+ * @copyright 2015 Juan Leyva <juan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since Moodle 3.0
+ */
+class mod_scorm_external_testcase extends externallib_advanced_testcase {
+
+ /**
+ * Test view_scorm
+ */
+ public function test_view_scorm() {
+ global $DB;
+
+ $this->resetAfterTest(true);
+
+ $this->setAdminUser();
+ // Setup test data.
+ $course = $this->getDataGenerator()->create_course();
+ $scorm = $this->getDataGenerator()->create_module('scorm', array('course' => $course->id));
+ $context = context_module::instance($scorm->cmid);
+ $cm = get_coursemodule_from_instance('scorm', $scorm->id);
+
+ // Test invalid instance id.
+ try {
+ mod_scorm_external::view_scorm(0);
+ $this->fail('Exception expected due to invalid mod_scorm instance id.');
+ } catch (moodle_exception $e) {
+ $this->assertEquals('invalidrecord', $e->errorcode);
+ }
+
+ // Test not-enrolled user.
+ $user = self::getDataGenerator()->create_user();
+ $this->setUser($user);
+ try {
+ mod_scorm_external::view_scorm($scorm->id);
+ $this->fail('Exception expected due to not enrolled user.');
+ } catch (moodle_exception $e) {
+ $this->assertEquals('requireloginerror', $e->errorcode);
+ }
+
+ // Test user with full capabilities.
+ $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+ $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
+
+ // Trigger and capture the event.
+ $sink = $this->redirectEvents();
+
+ $result = mod_scorm_external::view_scorm($scorm->id);
+ $result = external_api::clean_returnvalue(mod_scorm_external::view_scorm_returns(), $result);
+
+ $events = $sink->get_events();
+ $this->assertCount(1, $events);
+ $event = array_shift($events);
+
+ // Checking that the event contains the expected values.
+ $this->assertInstanceOf('\mod_scorm\event\course_module_viewed', $event);
+ $this->assertEquals($context, $event->get_context());
+ $moodleurl = new \moodle_url('/mod/scorm/view.php', array('id' => $cm->id));
+ $this->assertEquals($moodleurl, $event->get_url());
+ $this->assertEventContextNotUsed($event);
+ $this->assertNotEmpty($event->get_name());
+ }
+}
--- /dev/null
+<?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/>.
+
+/**
+ * SCORM module library functions tests
+ *
+ * @package mod_scorm
+ * @category test
+ * @copyright 2015 Juan Leyva <juan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since Moodle 3.0
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+
+require_once($CFG->dirroot . '/webservice/tests/helpers.php');
+require_once($CFG->dirroot . '/mod/scorm/lib.php');
+
+/**
+ * SCORM module library functions tests
+ *
+ * @package mod_scorm
+ * @category test
+ * @copyright 2015 Juan Leyva <juan@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since Moodle 3.0
+ */
+class mod_scorm_lib_testcase extends externallib_advanced_testcase {
+
+ /**
+ * Test scorm_view
+ * @return void
+ */
+ public function test_scorm_view() {
+ global $CFG;
+
+ $this->resetAfterTest();
+
+ $this->setAdminUser();
+ // Setup test data.
+ $course = $this->getDataGenerator()->create_course();
+ $scorm = $this->getDataGenerator()->create_module('scorm', array('course' => $course->id));
+ $context = context_module::instance($scorm->cmid);
+ $cm = get_coursemodule_from_instance('scorm', $scorm->id);
+
+ // Trigger and capture the event.
+ $sink = $this->redirectEvents();
+
+ scorm_view($scorm, $course, $cm, $context);
+
+ $events = $sink->get_events();
+ $this->assertCount(1, $events);
+ $event = array_shift($events);
+
+ // Checking that the event contains the expected values.
+ $this->assertInstanceOf('\mod_scorm\event\course_module_viewed', $event);
+ $this->assertEquals($context, $event->get_context());
+ $url = new \moodle_url('/mod/scorm/view.php', array('id' => $cm->id));
+ $this->assertEquals($url, $event->get_url());
+ $this->assertEventContextNotUsed($event);
+ $this->assertNotEmpty($event->get_name());
+ }
+
+}
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2015051101; // The current module version (Date: YYYYMMDDXX).
+$plugin->version = 2015051102; // The current module version (Date: YYYYMMDDXX).
$plugin->requires = 2015050500; // Requires this Moodle version.
$plugin->component = 'mod_scorm'; // Full name of the plugin (used for diagnostics).
$plugin->cron = 300;
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
require_once("../../config.php");
+require_once($CFG->dirroot.'/mod/scorm/lib.php');
require_once($CFG->dirroot.'/mod/scorm/locallib.php');
require_once($CFG->dirroot.'/course/lib.php');
$pagetitle = strip_tags($shortname.': '.format_string($scorm->name));
// Trigger module viewed event.
-$event = \mod_scorm\event\course_module_viewed::create(array(
- 'objectid' => $scorm->id,
- 'context' => $contextmodule,
-));
-$event->add_record_snapshot('course', $course);
-$event->add_record_snapshot('scorm', $scorm);
-$event->add_record_snapshot('course_modules', $cm);
-$event->trigger();
+scorm_view($scorm, $course, $cm, $contextmodule);
if (empty($preventskip) && empty($launch) && (has_capability('mod/scorm:skipview', $contextmodule))) {
scorm_simple_play($scorm, $USER, $contextmodule, $cm->id);
$scormopen = false;
}
if ($scormopen && empty($launch)) {
- scorm_view_display($USER, $scorm, 'view.php?id='.$cm->id, $cm);
+ scorm_print_launch($USER, $scorm, 'view.php?id='.$cm->id, $cm);
}
if (!empty($forcejs)) {
echo $OUTPUT->box(get_string("forcejavascriptmessage", "scorm"), "generalbox boxaligncenter forcejavascriptmessage");
echo $OUTPUT->heading($survey->name);
if (survey_already_done($survey->id, $USER->id)) {
- notice(get_string("alreadysubmitted", "survey"), clean_param($_SERVER["HTTP_REFERER"], PARAM_LOCALURL));
+ notice(get_string("alreadysubmitted", "survey"), get_local_referer(false));
exit;
}
This files describes API changes in /mod/* - activity modules,
information provided here is intended especially for developers.
+=== 3.0 ===
+
+* Function scorm_view_display was renamed to scorm_print_launch to avoid confussion with new function scorm_view.
+
=== 2.9 ===
* Added Grade to pass field to mod_form for activities that support grading.
if ($displaytype == RESOURCELIB_DISPLAY_OPEN) {
// For 'open' links, we always redirect to the content - except if the user
// just chose 'save and display' from the form then that would be confusing
- if (!isset($_SERVER['HTTP_REFERER']) || strpos($_SERVER['HTTP_REFERER'], 'modedit.php') === false) {
+ if (strpos(get_local_referer(false), 'modedit.php') === false) {
$redirect = true;
}
}
$pageid = required_param('pageid', PARAM_INT);
$contentformat = optional_param('contentformat', '', PARAM_ALPHA);
$option = optional_param('editoption', '', PARAM_TEXT);
-$section = optional_param('section', "", PARAM_TEXT);
+$section = optional_param('section', "", PARAM_RAW);
$version = optional_param('version', -1, PARAM_INT);
$attachments = optional_param('attachments', 0, PARAM_INT);
$deleteuploads = optional_param('deleteuploads', 0, PARAM_RAW);
require_capability('mod/wiki:managefiles', $context);
if (empty($returnurl)) {
- $referer = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+ $referer = get_local_referer(false);
if (!empty($referer)) {
$returnurl = $referer;
} else {
$string['notoverridden'] = 'Not overridden';
$string['noworkshops'] = 'There are no workshops in this course';
$string['noyoursubmission'] = 'You have not submitted your work yet';
+$string['nothingfound'] = 'Nothing to display';
$string['nullgrade'] = '-';
$string['overallfeedback'] = 'Overall feedback';
$string['overallfeedbackfiles'] = 'Maximum number of overall feedback attachments';
$string['submissiongrade'] = 'Grade for submission';
$string['submissiongrade_help'] = 'This setting specifies the maximum grade that may be obtained for submitted work.';
$string['submissiongradeof'] = 'Grade for submission (of {$a})';
+$string['submissionlastmodified'] = 'Last modified';
$string['submissionsettings'] = 'Submission settings';
$string['submissionstart'] = 'Open for submissions from';
$string['submissionstartevent'] = '{$a} (opens for submissions)';
$string['submissionstartdatetime'] = 'Open for submissions from {$a->daydatetime} ({$a->distanceday})';
$string['submissiontitle'] = 'Title';
+$string['submissionsreport'] = 'Workshop submissions report';
+$string['submittednotsubmitted'] = 'Submitted ({$a->submitted}) / not submitted ({$a->notsubmitted})';
$string['subplugintype_workshopallocation'] = 'Submissions allocation method';
$string['subplugintype_workshopallocation_plural'] = 'Submissions allocation methods';
$string['subplugintype_workshopeval'] = 'Grading evaluation method';
return array();
}
- if (!in_array($sortby, array('lastname','firstname','submissiontitle','submissiongrade','gradinggrade'))) {
+ if (!in_array($sortby, array('lastname', 'firstname', 'submissiontitle', 'submissionmodified',
+ 'submissiongrade', 'gradinggrade'))) {
$sortby = 'lastname';
}
}
$sqlsort = implode(',', $sqlsort);
$picturefields = user_picture::fields('u', array(), 'userid');
- $sql = "SELECT $picturefields, s.title AS submissiontitle, s.grade AS submissiongrade, ag.gradinggrade
+ $sql = "SELECT $picturefields, s.title AS submissiontitle, s.timemodified AS submissionmodified,
+ s.grade AS submissiongrade, ag.gradinggrade
FROM {user} u
LEFT JOIN {workshop_submissions} s ON (s.authorid = u.id AND s.workshopid = :workshopid1 AND s.example = 0)
LEFT JOIN {workshop_aggregations} ag ON (ag.userid = u.id AND ag.workshopid = :workshopid2)
$sortbyname = $sortbyfirstname . ' / ' . $sortbylastname;
}
+ $sortbysubmisstiontitle = $this->helper_sortable_heading(get_string('submission', 'workshop'), 'submissiontitle',
+ $options->sortby, $options->sorthow);
+ $sortbysubmisstionlastmodified = $this->helper_sortable_heading(get_string('submissionlastmodified', 'workshop'),
+ 'submissionmodified', $options->sortby, $options->sorthow);
+ $sortbysubmisstion = $sortbysubmisstiontitle . ' / ' . $sortbysubmisstionlastmodified;
+
$table->head = array();
$table->head[] = $sortbyname;
- $table->head[] = $this->helper_sortable_heading(get_string('submission', 'workshop'), 'submissiontitle',
- $options->sortby, $options->sorthow);
- $table->head[] = $this->helper_sortable_heading(get_string('receivedgrades', 'workshop'));
- if ($options->showsubmissiongrade) {
- $table->head[] = $this->helper_sortable_heading(get_string('submissiongradeof', 'workshop', $data->maxgrade),
- 'submissiongrade', $options->sortby, $options->sorthow);
- }
- $table->head[] = $this->helper_sortable_heading(get_string('givengrades', 'workshop'));
- if ($options->showgradinggrade) {
- $table->head[] = $this->helper_sortable_heading(get_string('gradinggradeof', 'workshop', $data->maxgradinggrade),
- 'gradinggrade', $options->sortby, $options->sorthow);
+ $table->head[] = $sortbysubmisstion;
+
+ // If we are in submission phase ignore the following headers (columns).
+ if ($options->workshopphase != workshop::PHASE_SUBMISSION) {
+ $table->head[] = $this->helper_sortable_heading(get_string('receivedgrades', 'workshop'));
+ if ($options->showsubmissiongrade) {
+ $table->head[] = $this->helper_sortable_heading(get_string('submissiongradeof', 'workshop', $data->maxgrade),
+ 'submissiongrade', $options->sortby, $options->sorthow);
+ }
+ $table->head[] = $this->helper_sortable_heading(get_string('givengrades', 'workshop'));
+ if ($options->showgradinggrade) {
+ $table->head[] = $this->helper_sortable_heading(get_string('gradinggradeof', 'workshop', $data->maxgradinggrade),
+ 'gradinggrade', $options->sortby, $options->sorthow);
+ }
}
-
$table->rowclasses = array();
$table->colclasses = array();
$table->data = array();
$cell->attributes['class'] = 'submission';
$row->cells[] = $cell;
}
+
+ // If we are in submission phase ignore the following columns.
+ if ($options->workshopphase == workshop::PHASE_SUBMISSION) {
+ $table->data[] = $row;
+ continue;
+ }
+
// column #3 - received grades
if ($tr % $spanreceived == 0) {
$idx = intval($tr / $spanreceived);
$url = new moodle_url('/mod/workshop/submission.php',
array('cmid' => $this->page->context->instanceid, 'id' => $participant->submissionid));
$out = html_writer::link($url, format_string($participant->submissiontitle), array('class'=>'title'));
+
+ $lastmodified = get_string('userdatemodified', 'workshop', userdate($participant->submissionmodified));
+ $out .= html_writer::tag('div', $lastmodified, array('class' => 'lastmodified'));
}
return $out;
text-align: center;
}
+.path-mod-workshop .lastmodified {
+ line-height: 1.0em;
+}
+
+.path-mod-workshop .nothingfound {
+ font-size: 150%;
+ color: #FF4500;
+}
+
.path-mod-workshop .workshop-risk-dataloss { vertical-align: text-bottom; }
And I follow "TestWorkshop"
And I should see "to allocate: 3"
And I should see "There is at least one author who has not yet submitted their work"
- And I should see "All submissions (3)"
- And I should see "Submission1"
- And I should see "Submission2"
- And I should see "Submission3"
+ Then I should see "Workshop submissions report"
+ And I should see "Submitted (3) / not submitted (1)"
+ And I should see "Submission1" in the "Sam1 Student1" "table_row"
+ And I should see "Submission2" in the "Sam2 Student2" "table_row"
+ And I should see "Submission3" in the "Sam3 Student3" "table_row"
+ And I should see "No submission found for this user" in the "Sam4 Student4" "table_row"
And I allocate submissions in workshop "TestWorkshop" as:"
| Participant | Reviewer |
| Sam1 Student1 | Sam2 Student2 |
}
}
- $countsubmissions = $workshop->count_submissions('all', $groupid);
+ print_collapsible_region_start('', 'workshop-viewlet-allsubmissions', get_string('submissionsreport', 'workshop'));
+
$perpage = get_user_preferences('workshop_perpage', 10);
- $pagingbar = new paging_bar($countsubmissions, $page, $perpage, $PAGE->url, 'page');
+ $data = $workshop->prepare_grading_report_data($USER->id, $groupid, $page, $perpage, $sortby, $sorthow);
+ if ($data) {
+ $countparticipants = $workshop->count_participants();
+ $countsubmissions = $workshop->count_submissions(array_keys($data->grades), $groupid);
+ $a = new stdClass();
+ $a->submitted = $countsubmissions;
+ $a->notsubmitted = $data->totalcount - $countsubmissions;
- print_collapsible_region_start('', 'workshop-viewlet-allsubmissions', get_string('allsubmissions', 'workshop', $countsubmissions));
- echo $output->box_start('generalbox allsubmissions');
- echo $output->container(groups_print_activity_menu($workshop->cm, $PAGE->url, true), 'groupwidget');
+ echo html_writer::tag('div', get_string('submittednotsubmitted', 'workshop', $a));
- if ($countsubmissions == 0) {
- echo $output->container(get_string('nosubmissions', 'workshop'), 'nosubmissions');
+ echo $output->container(groups_print_activity_menu($workshop->cm, $PAGE->url, true), 'groupwidget');
+
+ // Prepare the paging bar.
+ $baseurl = new moodle_url($PAGE->url, array('sortby' => $sortby, 'sorthow' => $sorthow));
+ $pagingbar = new paging_bar($data->totalcount, $page, $perpage, $baseurl, 'page');
+
+ // Populate the display options for the submissions report.
+ $reportopts = new stdclass();
+ $reportopts->showauthornames = has_capability('mod/workshop:viewauthornames', $workshop->context);
+ $reportopts->showreviewernames = has_capability('mod/workshop:viewreviewernames', $workshop->context);
+ $reportopts->sortby = $sortby;
+ $reportopts->sorthow = $sorthow;
+ $reportopts->showsubmissiongrade = false;
+ $reportopts->showgradinggrade = false;
+ $reportopts->workshopphase = $workshop->phase;
- } else {
- $submissions = $workshop->get_submissions('all', $groupid, $page * $perpage, $perpage);
- $shownames = has_capability('mod/workshop:viewauthornames', $workshop->context);
echo $output->render($pagingbar);
- foreach ($submissions as $submission) {
- echo $output->render($workshop->prepare_submission_summary($submission, $shownames));
- }
+ echo $output->render(new workshop_grading_report($data, $reportopts));
echo $output->render($pagingbar);
echo $output->perpage_selector($perpage);
+ } else {
+ echo html_writer::tag('div', get_string('nothingfound', 'workshop'), array('class' => 'nothingfound'));
}
-
- echo $output->box_end();
print_collapsible_region_end();
}
-
break;
case workshop::PHASE_ASSESSMENT:
$reportopts->sorthow = $sorthow;
$reportopts->showsubmissiongrade = false;
$reportopts->showgradinggrade = false;
+ $reportopts->workshopphase = $workshop->phase;
print_collapsible_region_start('', 'workshop-viewlet-gradereport', get_string('gradesreport', 'workshop'));
echo $output->box_start('generalbox gradesreport');
$reportopts->sorthow = $sorthow;
$reportopts->showsubmissiongrade = true;
$reportopts->showgradinggrade = true;
+ $reportopts->workshopphase = $workshop->phase;
print_collapsible_region_start('', 'workshop-viewlet-gradereport', get_string('gradesreport', 'workshop'));
echo $output->box_start('generalbox gradesreport');
$reportopts->sorthow = $sorthow;
$reportopts->showsubmissiongrade = true;
$reportopts->showgradinggrade = true;
+ $reportopts->workshopphase = $workshop->phase;
print_collapsible_region_start('', 'workshop-viewlet-gradereport', get_string('gradesreport', 'workshop'));
echo $output->box_start('generalbox gradesreport');
<?php
-
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
}
// Toggle the editing state and switches
-if ($PAGE->user_allowed_editing()) {
+if (empty($CFG->forcedefaultmymoodle) && $PAGE->user_allowed_editing()) {
if ($reset !== null) {
if (!is_null($userid)) {
require_sesskey();
- if(!$currentpage = my_reset_page($userid, MY_PAGE_PRIVATE)){
+ if (!$currentpage = my_reset_page($userid, MY_PAGE_PRIVATE)) {
print_error('reseterror', 'my');
}
redirect(new moodle_url('/my'));
function my_copy_page($userid, $private=MY_PAGE_PRIVATE, $pagetype='my-index') {
global $DB;
- if ($customised = $DB->record_exists('my_pages', array('userid' => $userid, 'private' => $private))) {
+ if ($customised = $DB->get_record('my_pages', array('userid' => $userid, 'private' => $private))) {
return $customised; // We're done!
}
// Get record from sql_internal_table_reader and merge with records got from legacy log (if needed).
if (!$onlyuselegacyreader) {
- $sql = "SELECT ra.userid, $usernamefields, u.idnumber, COUNT(l.actioncount) AS count
- FROM (SELECT DISTINCT userid FROM {role_assignments} WHERE contextid $relatedctxsql AND roleid = :roleid ) ra
- JOIN {user} u ON u.id = ra.userid
+ $sql = "SELECT ra.userid, $usernamefields, u.idnumber, COUNT(DISTINCT l.timecreated) AS count
+ FROM {user} u
+ JOIN {role_assignments} ra ON u.id = ra.userid AND ra.contextid $relatedctxsql AND ra.roleid = :roleid
$groupsql
- LEFT JOIN (
- SELECT userid, COUNT(crud) AS actioncount
- FROM {" . $logtable . "}
- WHERE contextinstanceid = :instanceid
- AND timecreated > :timefrom" . $crudsql ."
- AND edulevel = :edulevel
- AND anonymous = 0
- AND contextlevel = :contextlevel
- AND (origin = 'web' OR origin = 'ws')
- GROUP BY userid,timecreated) l ON (l.userid = ra.userid)";
+ LEFT JOIN {" . $logtable . "} l
+ ON l.contextinstanceid = :instanceid
+ AND l.timecreated > :timefrom" . $crudsql ."
+ AND l.edulevel = :edulevel
+ AND l.anonymous = 0
+ AND l.contextlevel = :contextlevel
+ AND (l.origin = 'web' OR l.origin = 'ws')
+ AND l.userid = ra.userid";
// We add this after the WHERE statement that may come below.
$groupbysql = " GROUP BY ra.userid, $usernamefields, u.idnumber";
}
if ($err_notice) {
- echo $OUTPUT->notification($err_notice, 'red');
+ echo $OUTPUT->notification($err_notice, 'notifyproblem');
}
if ($notice) {
- echo $OUTPUT->notification($notice, 'green');
+ echo $OUTPUT->notification($notice, 'notifysuccess');
}
// small form to add an official tag
This files describes API changes in /theme/* themes,
information provided here is intended especially for theme designer.
+=== 3.0 ===
+
+* The renderer function core_availability_renderer::multiple_messages was changed to
+ render_core_availability_multiple_messages, requiring a parameter of the new
+ \core_availability\multiple_messages type.
+
=== 2.9 ===
* Themes Bootstrapbase, Clean and More have undergone some changes for RTL layouts see - MDL-48160.
}
// Plugins.
- $types = \core_component::get_plugin_types();
- foreach ($types as $type => $dir) {
- $pluginlist = get_plugin_list_with_function($type, "myprofile_navigation", "lib.php");
- foreach ($pluginlist as $function) {
+ $pluginswithfunction = get_plugins_with_function('myprofile_navigation', 'lib.php');
+ foreach ($pluginswithfunction as $plugins) {
+ foreach ($plugins as $function) {
$function($tree, $user, $iscurrentuser, $course);
}
}
+
$tree->sort_categories();
return $tree;
}
// Need to have full access to a course to see the rest of own info.
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('notenrolled', '', $fullname));
- $referer = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+ $referer = get_local_referer(false);
if (!empty($referer)) {
echo $OUTPUT->continue_button($referer);
}
$PAGE->navbar->add($struser);
echo $OUTPUT->heading(get_string('notenrolledprofile'));
}
- $referer = clean_param($_SERVER['HTTP_REFERER'], PARAM_LOCALURL);
+ $referer = get_local_referer(false);
if (!empty($referer)) {
echo $OUTPUT->continue_button($referer);
}
defined('MOODLE_INTERNAL') || die();
-$version = 2015071600.00; // YYYYMMDD = weekly release date of this DEV branch.
+$version = 2015072700.00; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
-$release = '3.0dev (Build: 20150716)'; // Human-friendly version name
+$release = '3.0dev (Build: 20150723)'; // Human-friendly version name
$branch = '30'; // This version's branch.
$maturity = MATURITY_ALPHA; // This version's maturity level.