"sub": false,
"supernew": false,
"maxerr": 500,
- "maxlen": 150,
+ "maxlen": 180,
"passfail": false,
"latedef": true
}
echo $OUTPUT->header();
// This may take a long time.
- set_time_limit(0);
+ core_php_time_limit::raise();
// Disable plugin to prevent concurrent cron execution.
unset($enabled[$enrol]);
define('NO_OUTPUT_BUFFERING', true);
-if (empty($_GET['cache']) and empty($_POST['cache']) and empty($_GET['sesskey']) and empty($_POST['sesskey'])) {
+if ((isset($_GET['cache']) and $_GET['cache'] === '0')
+ or (isset($_POST['cache']) and $_POST['cache'] === '0')
+ or (!isset($_POST['cache']) and !isset($_GET['cache']) and empty($_GET['sesskey']) and empty($_POST['sesskey']))) {
// Prevent caching at all cost when visiting this page directly,
// we redirect to self once we known no upgrades are necessary.
// Note: $_GET and $_POST are used here intentionally because our param cleaning is not loaded yet.
// Set up PAGE.
$url = new moodle_url('/admin/index.php');
-if ($cache) {
- $url->param('cache', 1);
-}
+$url->param('cache', $cache);
$PAGE->set_url($url);
unset($url);
$PAGE->set_pagelayout('maintenance');
$PAGE->set_popup_notification_allowed(false);
+ /** @var core_admin_renderer $output */
+ $output = $PAGE->get_renderer('core', 'admin');
+
if (upgrade_stale_php_files_present()) {
$PAGE->set_title($stradministration);
$PAGE->set_cacheable(false);
- /** @var core_admin_renderer $output */
- $output = $PAGE->get_renderer('core', 'admin');
echo $output->upgrade_stale_php_files_page();
die();
}
$PAGE->set_heading($strdatabasechecking);
$PAGE->set_cacheable(false);
- /** @var core_admin_renderer $output */
- $output = $PAGE->get_renderer('core', 'admin');
echo $output->upgrade_confirm_page($a->newversion, $maturity, $testsite);
die();
$PAGE->set_heading($strcurrentrelease);
$PAGE->set_cacheable(false);
- /** @var core_admin_renderer $output */
- $output = $PAGE->get_renderer('core', 'admin');
echo $output->upgrade_environment_page($release, $envstatus, $environment_results);
die();
$PAGE->set_heading($strplugincheck);
$PAGE->set_cacheable(false);
- $reloadurl = new moodle_url('/admin/index.php', array('confirmupgrade' => 1, 'confirmrelease' => 1));
-
- /** @var core_admin_renderer $output */
- $output = $PAGE->get_renderer('core', 'admin');
-
- // check plugin dependencies first
- $failed = array();
- if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
- echo $output->unsatisfied_dependencies_page($version, $failed, $reloadurl);
- die();
- }
- unset($failed);
+ $reloadurl = new moodle_url('/admin/index.php', array('confirmupgrade' => 1, 'confirmrelease' => 1, 'cache' => 0));
if ($fetchupdates) {
- // no sesskey support guaranteed here
- if (empty($CFG->disableupdatenotifications)) {
- \core\update\checker::instance()->fetch();
+ // No sesskey support guaranteed here, because sessions might not work yet.
+ $updateschecker = \core\update\checker::instance();
+ if ($updateschecker->enabled()) {
+ $updateschecker->fetch();
}
redirect($reloadurl);
}
$deploydata = $deployer->submitted_data();
if (!empty($deploydata)) {
+ // No sesskey support guaranteed here, because sessions might not work yet.
echo $output->upgrade_plugin_confirm_deploy_page($deployer, $deploydata);
die();
}
echo $output->upgrade_plugin_check_page(core_plugin_manager::instance(), \core\update\checker::instance(),
$version, $showallplugins, $reloadurl,
- new moodle_url('/admin/index.php', array('confirmupgrade'=>1, 'confirmrelease'=>1, 'confirmplugincheck'=>1)));
+ new moodle_url('/admin/index.php', array('confirmupgrade'=>1, 'confirmrelease'=>1, 'confirmplugincheck'=>1, 'cache'=>0)));
die();
} else {
- // Launch main upgrade
+ // Always verify plugin dependencies!
+ $failed = array();
+ if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
+ $PAGE->set_pagelayout('maintenance');
+ $PAGE->set_popup_notification_allowed(false);
+ $reloadurl = new moodle_url('/admin/index.php', array('confirmupgrade' => 1, 'confirmrelease' => 1, 'cache' => 0));
+ echo $output->unsatisfied_dependencies_page($version, $failed, $reloadurl);
+ die();
+ }
+ unset($failed);
+
+ // Launch main upgrade.
upgrade_core($version, true);
}
} else if ($version < $CFG->version) {
if (!$cache and moodle_needs_upgrading()) {
if (!$PAGE->headerprinted) {
// means core upgrade or installation was not already done
+
+ /** @var core_admin_renderer $output */
+ $output = $PAGE->get_renderer('core', 'admin');
+
if (!$confirmplugins) {
$strplugincheck = get_string('plugincheck');
$PAGE->set_cacheable(false);
if ($fetchupdates) {
- // no sesskey support guaranteed here
- \core\update\checker::instance()->fetch();
+ require_sesskey();
+ $updateschecker = \core\update\checker::instance();
+ if ($updateschecker->enabled()) {
+ $updateschecker->fetch();
+ }
redirect($PAGE->url);
}
- $output = $PAGE->get_renderer('core', 'admin');
-
$deployer = \core\update\deployer::instance();
if ($deployer->enabled()) {
$deployer->initialize($PAGE->url, $PAGE->url);
$deploydata = $deployer->submitted_data();
if (!empty($deploydata)) {
+ require_sesskey();
echo $output->upgrade_plugin_confirm_deploy_page($deployer, $deploydata);
die();
}
}
- // check plugin dependencies first
- $failed = array();
- if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
- echo $output->unsatisfied_dependencies_page($version, $failed, $PAGE->url);
- die();
- }
- unset($failed);
-
- // dependencies check passed, let's rock!
+ // Show plugins info.
echo $output->upgrade_plugin_check_page(core_plugin_manager::instance(), \core\update\checker::instance(),
$version, $showallplugins,
new moodle_url($PAGE->url),
- new moodle_url('/admin/index.php', array('confirmplugincheck'=>1)));
+ new moodle_url('/admin/index.php', array('confirmplugincheck'=>1, 'cache'=>0)));
+ die();
+ }
+
+ // Make sure plugin dependencies are always checked.
+ $failed = array();
+ if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
+ $PAGE->set_pagelayout('maintenance');
+ $PAGE->set_popup_notification_allowed(false);
+ $reloadurl = new moodle_url('/admin/index.php', array('cache' => 0));
+ echo $output->unsatisfied_dependencies_page($version, $failed, $reloadurl);
die();
}
+ unset($failed);
}
+
// install/upgrade all plugins and other parts
upgrade_noncore(true);
}
upgrade_finished('upgradesettings.php');
}
+if (has_capability('moodle/site:config', context_system::instance())) {
+ if ($fetchupdates) {
+ require_sesskey();
+ $updateschecker = \core\update\checker::instance();
+ if ($updateschecker->enabled()) {
+ $updateschecker->fetch();
+ }
+ redirect(new moodle_url('/admin/index.php', array('cache' => 0)));
+ }
+}
+
// Now we can be sure everything was upgraded and caches work fine,
// redirect if necessary to make sure caching is enabled.
if (!$cache) {
admin_externalpage_setup('adminnotifications');
-if ($fetchupdates) {
- require_sesskey();
- $updateschecker->fetch();
- redirect(new moodle_url('/admin/index.php'));
-}
-
$output = $PAGE->get_renderer('core', 'admin');
echo $output->admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
$cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch, $buggyiconvnomb,
admin_externalpage_setup('ssoaccesscontrol');
-echo $OUTPUT->header();
-
if (!extension_loaded('openssl')) {
print_error('requiresopenssl', 'mnet');
}
if (mnet_update_sso_access_control($idrec->username, $idrec->mnet_host_id, $accessctrl)) {
if ($accessctrl == 'allow') {
- redirect('access_control.php', get_string('ssl_acl_allow','mnet', array('uset'=>$idrec->username, 'host'=>$mnethosts[$idrec->mnet_host_id])));
- } elseif ($accessctrl == 'deny') {
- redirect('access_control.php', get_string('ssl_acl_deny','mnet', array('user'=>$idrec->username, 'host'=>$mnethosts[$idrec->mnet_host_id])));
+ redirect('access_control.php', get_string('ssl_acl_allow','mnet', array('user' => $idrec->username,
+ 'host' => $mnethosts[$idrec->mnet_host_id])));
+ } else if ($accessctrl == 'deny') {
+ redirect('access_control.php', get_string('ssl_acl_deny','mnet', array('user' => $idrec->username,
+ 'host' => $mnethosts[$idrec->mnet_host_id])));
}
}
break;
exit;
}
+echo $OUTPUT->header();
+
// Explain
echo $OUTPUT->box(get_string('ssoacldescr','mnet'));
// Are the needed bits enabled?
public function upgrade_confirm_page($strnewversion, $maturity, $testsite) {
$output = '';
- $continueurl = new moodle_url('/admin/index.php', array('confirmupgrade' => 1));
+ $continueurl = new moodle_url('/admin/index.php', array('confirmupgrade' => 1, 'cache' => 0));
$continue = new single_button($continueurl, get_string('continue'), 'get');
$cancelurl = new moodle_url('/admin/index.php');
$output .= $this->environment_check_table($envstatus, $environment_results);
if (!$envstatus) {
- $output .= $this->upgrade_reload(new moodle_url('/admin/index.php'), array('confirmupgrade' => 1));
+ $output .= $this->upgrade_reload(new moodle_url('/admin/index.php'), array('confirmupgrade' => 1, 'cache' => 0));
} else {
$output .= $this->notification(get_string('environmentok', 'admin'), 'notifysuccess');
$output .= $this->box(get_string('langpackwillbeupdated', 'admin'), 'generalbox', 'notice');
}
- $output .= $this->continue_button(new moodle_url('/admin/index.php', array('confirmupgrade' => 1, 'confirmrelease' => 1)));
+ $output .= $this->continue_button(new moodle_url('/admin/index.php', array('confirmupgrade' => 1, 'confirmrelease' => 1, 'cache' => 0)));
}
$output .= $this->footer();
}
$updateinfo .= $this->container_start('checkforupdates');
- $fetchurl = new moodle_url('/admin/index.php', array('fetchupdates' => 1, 'sesskey' => sesskey(), 'cache' => 1));
+ $fetchurl = new moodle_url('/admin/index.php', array('fetchupdates' => 1, 'sesskey' => sesskey(), 'cache' => 0));
$updateinfo .= $this->single_button($fetchurl, get_string('checkforupdates', 'core_plugin'));
if ($fetch) {
$updateinfo .= $this->container(get_string('checkforupdateslast', 'core_plugin',
$out .= $this->output->heading(get_string('nonehighlighted', 'core_plugin'));
if (empty($options['full'])) {
$out .= html_writer::link(new moodle_url('/admin/index.php',
- array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 1)),
+ array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 1, 'cache' => 0)),
get_string('nonehighlightedinfo', 'core_plugin'));
}
$out .= $this->output->container_end();
$out .= $this->output->heading(get_string('somehighlighted', 'core_plugin', $sumofhighlighted));
if (empty($options['full'])) {
$out .= html_writer::link(new moodle_url('/admin/index.php',
- array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 1)),
+ array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 1, 'cache' => 0)),
get_string('somehighlightedinfo', 'core_plugin'));
} else {
$out .= html_writer::link(new moodle_url('/admin/index.php',
- array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 0)),
+ array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 0, 'cache' => 0)),
get_string('somehighlightedonly', 'core_plugin'));
}
$out .= $this->output->container_end();
get_string('displayname', 'core_plugin'),
get_string('source', 'core_plugin'),
get_string('version', 'core_plugin'),
+ get_string('release', 'core_plugin'),
get_string('availability', 'core_plugin'),
get_string('actions', 'core_plugin'),
get_string('notes','core_plugin'),
);
- $table->headspan = array(1, 1, 1, 1, 2, 1);
+ $table->headspan = array(1, 1, 1, 1, 1, 2, 1);
$table->colclasses = array(
- 'pluginname', 'source', 'version', 'availability', 'settings', 'uninstall', 'notes'
+ 'pluginname', 'source', 'version', 'release', 'availability', 'settings', 'uninstall', 'notes'
);
foreach ($plugininfo as $type => $plugins) {
}
$version = new html_table_cell($plugin->versiondb);
+ $release = new html_table_cell($plugin->release);
$isenabled = $plugin->is_enabled();
if (is_null($isenabled)) {
$notes = new html_table_cell($requiredby.$updateinfo);
$row->cells = array(
- $pluginname, $source, $version, $availability, $settings, $uninstall, $notes
+ $pluginname, $source, $version, $release, $availability, $settings, $uninstall, $notes
);
$table->data[] = $row;
}
// This file defines settingpages and externalpages under the "appearance" category
-if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
+$capabilities = array(
+ 'moodle/my:configsyspages',
+ 'moodle/tag:manage'
+);
+
+if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) { // speedup for non-admins, add all caps used on this page
$ADMIN->add('appearance', new admin_category('themes', new lang_string('themes')));
// "themesettings" settingpage
$temp->add(new admin_setting_configcheckbox('doctonewwindow', new lang_string('doctonewwindow', 'admin'), new lang_string('configdoctonewwindow', 'admin'), 0));
$ADMIN->add('appearance', $temp);
- $temp = new admin_externalpage('mypage', new lang_string('mypage', 'admin'), $CFG->wwwroot . '/my/indexsys.php');
+ $temp = new admin_externalpage('mypage', new lang_string('mypage', 'admin'), $CFG->wwwroot . '/my/indexsys.php',
+ 'moodle/my:configsyspages');
$ADMIN->add('appearance', $temp);
- $temp = new admin_externalpage('profilepage', new lang_string('myprofile', 'admin'), $CFG->wwwroot . '/user/profilesys.php');
+ $temp = new admin_externalpage('profilepage', new lang_string('myprofile', 'admin'), $CFG->wwwroot . '/user/profilesys.php',
+ 'moodle/my:configsyspages');
$ADMIN->add('appearance', $temp);
// coursecontact is the person responsible for course - usually manages enrolments, receives notification, etc.
$ADMIN->add('appearance', $temp);
// link to tag management interface
- $ADMIN->add('appearance', new admin_externalpage('managetags', new lang_string('managetags', 'tag'), "$CFG->wwwroot/tag/manage.php"));
+ $ADMIN->add('appearance', new admin_externalpage('managetags', new lang_string('managetags', 'tag'), $CFG->wwwroot.'/tag/manage.php', 'moodle/tag:manage'));
$temp = new admin_settingpage('additionalhtml', new lang_string('additionalhtml', 'admin'));
$temp->add(new admin_setting_heading('additionalhtml_heading', new lang_string('additionalhtml_heading', 'admin'), new lang_string('additionalhtml_desc', 'admin')));
// Add common settings page
$temp = new admin_settingpage('managerepositoriescommon', new lang_string('commonrepositorysettings', 'repository'));
- $temp->add(new admin_setting_configtext('repositorycacheexpire', new lang_string('cacheexpire', 'repository'), new lang_string('configcacheexpire', 'repository'), 120));
+ $temp->add(new admin_setting_configtext('repositorycacheexpire', new lang_string('cacheexpire', 'repository'), new lang_string('configcacheexpire', 'repository'), 120, PARAM_INT));
+ $temp->add(new admin_setting_configtext('repositorygetfiletimeout', new lang_string('getfiletimeout', 'repository'), new lang_string('configgetfiletimeout', 'repository'), 30, PARAM_INT));
+ $temp->add(new admin_setting_configtext('repositorysyncfiletimeout', new lang_string('syncfiletimeout', 'repository'), new lang_string('configsyncfiletimeout', 'repository'), 1, PARAM_INT));
+ $temp->add(new admin_setting_configtext('repositorysyncimagetimeout', new lang_string('syncimagetimeout', 'repository'), new lang_string('configsyncimagetimeout', 'repository'), 3, PARAM_INT));
$temp->add(new admin_setting_configcheckbox('repositoryallowexternallinks', new lang_string('allowexternallinks', 'repository'), new lang_string('configallowexternallinks', 'repository'), 1));
$temp->add(new admin_setting_configcheckbox('legacyfilesinnewcourses', new lang_string('legacyfilesinnewcourses', 'admin'), new lang_string('legacyfilesinnewcourses_help', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('legacyfilesaddallowed', new lang_string('legacyfilesaddallowed', 'admin'), new lang_string('legacyfilesaddallowed_help', 'admin'), 1));
GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR => 'HTTP_CLIENT, REMOTE_ADDR',
GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR|GETREMOTEADDR_SKIP_HTTP_CLIENT_IP => 'REMOTE_ADDR');
$temp->add(new admin_setting_configselect('getremoteaddrconf', new lang_string('getremoteaddrconf', 'admin'), new lang_string('configgetremoteaddrconf', 'admin'), 0, $options));
+
$temp->add(new admin_setting_heading('webproxy', new lang_string('webproxy', 'admin'), new lang_string('webproxyinfo', 'admin')));
$temp->add(new admin_setting_configtext('proxyhost', new lang_string('proxyhost', 'admin'), new lang_string('configproxyhost', 'admin'), '', PARAM_HOST));
$temp->add(new admin_setting_configtext('proxyport', new lang_string('proxyport', 'admin'), new lang_string('configproxyport', 'admin'), 0, PARAM_INT));
$temp->add(new admin_setting_configselect('extramemorylimit', new lang_string('extramemorylimit', 'admin'),
new lang_string('configextramemorylimit', 'admin'), '512M',
$memoryoptions));
+$temp->add(new admin_setting_configtext('maxtimelimit', new lang_string('maxtimelimit', 'admin'),
+ new lang_string('maxtimelimit_desc', 'admin'), 0, PARAM_INT));
$temp->add(new admin_setting_configtext('curlcache', new lang_string('curlcache', 'admin'),
new lang_string('configcurlcache', 'admin'), 120, PARAM_INT));
$this->getSession()->wait($timeout, $javascript);
}
}
-
- /**
- * Goes to notification page ensuring site admin navigation is loaded.
- *
- * @Given /^I go to notifications page$/
- * @return Given[]
- */
- public function i_go_to_notifications_page() {
- if ($this->running_javascript()) {
- return array(
- new Given('I expand "' . get_string('administrationsite') . '" node'),
- new Given('I follow "' . get_string('notifications') . '"')
- );
- } else {
- return array(
- new Given('I follow "' . get_string('administrationsite') . '"')
- );
- }
- }
}
And I should not see "C_shortname Course fullname"
Scenario: Courses list with extended course names
- Given I go to notifications page
+ Given I expand "Site administration" node
+ And I expand "Appearance" node
And I click on "Courses" "link" in the "//div[@id='settingsnav']/descendant::li[contains(concat(' ', normalize-space(@class), ' '), ' type_setting ')][contains(., 'Appearance')]" "xpath_element"
And I check "Display extended course names"
When I press "Save changes"
// Getting $CFG data.
require_once(__DIR__ . '/../../../../config.php');
-// CFG->behat_prefix must be set and with value different than CFG->prefix and phpunit_prefix.
-if (empty($CFG->behat_prefix) ||
- ($CFG->behat_prefix == $CFG->prefix) ||
- (!empty($CFG->phpunit_prefix) && $CFG->behat_prefix == $CFG->phpunit_prefix)) {
- behat_error(BEHAT_EXITCODE_CONFIG,
- 'Define $CFG->behat_prefix in config.php with a value different than $CFG->prefix and $CFG->phpunit_prefix');
-}
-
-// CFG->behat_dataroot must be set and with value different than CFG->dataroot and phpunit_dataroot.
-if (empty($CFG->behat_dataroot) ||
- ($CFG->behat_dataroot == $CFG->dataroot) ||
- (!empty($CFG->phpunit_dataroot) && $CFG->behat_dataroot == $CFG->phpunit_dataroot)) {
- behat_error(BEHAT_EXITCODE_CONFIG,
- 'Define $CFG->behat_dataroot in config.php with a value different than $CFG->dataroot and $CFG->phpunit_dataroot');
-}
+// When we use the utilities we don't know how the site
+// will be accessed, so if neither $CFG->behat_switchcompletely or
+// $CFG->behat_wwwroot are set we must think that the site will
+// be accessed using the built-in server which is set by default
+// to localhost:8000. We need to do this to prevent uses of the production
+// wwwroot when the site is being installed / dropped...
+$CFG->behat_wwwroot = behat_get_wwwroot();
+
+// Checking the integrity of the provided $CFG->behat_* vars
+// to prevent conflicts with production and phpunit environments.
+behat_check_config_vars();
// Create behat_dataroot if it doesn't exists.
if (!file_exists($CFG->behat_dataroot)) {
-@tool @tool_behat
+@tool @tool_behat @_only_local
Feature: Set up contextual data for tests
In order to write tests quickly
As a developer
| fullname | shortname |
| Course 1 | C1 |
And the following "activities" exists:
- | activity | name | intro | course | idnumber |
- | assign | Test assignment name | Test assignment description | C1 | assign1 |
- | data | Test database name | Test database description | C1 | data1 |
+ | activity | name | intro | course | idnumber |
+ | assign | Test assignment name | Test assignment description | C1 | assign1 |
+ | assignment | Test assignment22 name | Test assignment22 description | C1 | assignment1 |
+ | book | Test book name | Test book description | C1 | book1 |
+ | chat | Test chat name | Test chat description | C1 | chat1 |
+ | choice | Test choice name | Test choice description | C1 | choice1 |
+ | data | Test database name | Test database description | C1 | data1 |
+ | feedback | Test feedback name | Test feedback description | C1 | feedback1 |
+ | folder | Test folder name | Test folder description | C1 | folder1 |
+ | forum | Test forum name | Test forum description | C1 | forum1 |
+ | glossary | Test glossary name | Test glossary description | C1 | glossary1 |
+ | imscp | Test imscp name | Test imscp description | C1 | imscp1 |
+ | label | Test label name | Test label description | C1 | label1 |
+ | lesson | Test lesson name | Test lesson description | C1 | lesson1 |
+ | lti | Test lti name | Test lti description | C1 | lti1 |
+ | page | Test page name | Test page description | C1 | page1 |
+ | quiz | Test quiz name | Test quiz description | C1 | quiz1 |
+ | resource | Test resource name | Test resource description | C1 | resource1 |
+ | scorm | Test scorm name | Test scorm description | C1 | scorm1 |
+ | survey | Test survey name | Test survey description | C1 | survey1 |
+ | url | Test url name | Test url description | C1 | url1 |
+ | wiki | Test wiki name | Test wiki description | C1 | wiki1 |
+ | workshop | Test workshop name | Test workshop description | C1 | workshop1 |
When I log in as "admin"
And I follow "Course 1"
Then I should see "Test assignment name"
+ # Assignment 2.2 module type is disabled by default
+ # And I should see "Test assignment22 name"
+ And I should see "Test book name"
+ And I should see "Test chat name"
+ And I should see "Test choice name"
And I should see "Test database name"
+ # Feedback module type is disabled by default
+ # And I should see "Test feedback name"
+ And I should see "Test folder name"
+ And I should see "Test forum name"
+ And I should see "Test glossary name"
+ And I should see "Test imscp name"
+ # We don't see label name, we see only description:
+ And I should see "Test label description"
+ And I should see "Test lesson name"
+ And I should see "Test lti name"
+ And I should see "Test page name"
+ And I should see "Test quiz name"
+ And I should see "Test resource name"
+ And I should see "Test scorm name"
+ And I should see "Test survey name"
+ And I should see "Test url name"
+ And I should see "Test wiki name"
+ And I should see "Test workshop name"
And I follow "Test assignment name"
And I should see "Test assignment description"
$this->markTestSkipped('Behat not installed.');
}
+ // It is possible that it has no value.
+ if (empty($CFG->behat_wwwroot)) {
+ $CFG->behat_wwwroot = behat_get_wwwroot();
+ }
+
// To avoid user value at config.php level.
unset($CFG->behat_config);
// Lists.
$this->assertContains('- feature1', $contents);
$this->assertContains('- feature3', $contents);
+
+ unset($CFG->behat_wwwroot);
}
}
$progressbar->create(); // prints the HTML code of the progress bar
// we may need a bit of extra execution time and memory here
- @set_time_limit(HOURSECS);
+ core_php_time_limit::raise(HOURSECS);
raise_memory_limit(MEMORY_EXTRA);
tool_customlang_utils::checkout($lng, $progressbar);
* @return does not return, calls die()
*/
function tool_dbtransfer_export_xml_database($description, $mdb) {
- @set_time_limit(0);
+ core_php_time_limit::raise();
\core\session\manager::write_close(); // Release session.
* @return void
*/
function tool_dbtransfer_transfer_database(moodle_database $sourcedb, moodle_database $targetdb, progress_trace $feedback = null) {
- @set_time_limit(0);
+ core_php_time_limit::raise();
\core\session\manager::write_close(); // Release session.
// Update time limit so PHP doesn't time out.
if (!CLI_SCRIPT) {
- set_time_limit(120);
+ core_php_time_limit::raise(120);
}
}
echo $OUTPUT->notification('Please be patient and wait for this to complete...', 'notifysuccess');
- set_time_limit(0);
+ core_php_time_limit::raise();
foreach ($rs as $table) {
$DB->set_debug(true);
$notice_error = array();
if (($mode == INSTALLATION_OF_SELECTED_LANG) and confirm_sesskey() and !empty($pack)) {
- set_time_limit(0);
+ core_php_time_limit::raise();
make_temp_directory('');
make_upload_directory('lang');
}
if ($mode == UPDATE_ALL_LANG) {
- set_time_limit(0);
+ core_php_time_limit::raise();
$installer = new lang_installer();
/// Turn off time limits, sometimes upgrades can be slow.
-@set_time_limit(0);
+core_php_time_limit::raise();
echo '<strong>Progress:</strong>';
$i = 0;
error('Not available on production sites, sorry.');
}
-set_time_limit(60*30);
+core_php_time_limit::raise(60*30);
$oldcwd = getcwd();
$code = 0;
$errors = 0;
// We will most certainly need extra time and memory to process big files.
- @set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_EXTRA);
// Loop over the CSV lines.
$tracker->start();
// We might need extra time and memory depending on the number of rows to preview.
- @set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_EXTRA);
// Loop over the CSV lines.
}
}
$this->assertTrue($found);
-
- // Restore the time limit to prevent warning.
- set_time_limit(0);
}
public function test_restore_file() {
}
}
$this->assertTrue($found);
-
- // Restore the time limit to prevent warning.
- set_time_limit(0);
}
public function test_restore_invalid_file() {
$this->assertEquals($dir, $dir2);
$CFG->keeptempdirectoriesonbackup = $oldcfg;
-
- // Restore the time limit to prevent warning.
- set_time_limit(0);
}
public function test_get_role_ids() {
}
}
$this->assertTrue($found);
-
- // Restore the time limit to prevent warning.
- set_time_limit(0);
}
public function test_restore_restore_file() {
}
}
$this->assertTrue($found);
-
- // Restore the time limit to prevent warning.
- set_time_limit(0);
}
public function test_shortname_template() {
$iid = optional_param('iid', '', PARAM_INT);
$previewrows = optional_param('previewrows', 10, PARAM_INT);
-@set_time_limit(60*60); // 1 hour should be enough
+core_php_time_limit::raise(60*60); // 1 hour should be enough
raise_memory_limit(MEMORY_HUGE);
require_login();
continue;
}
if (!property_exists($user, $column) or !property_exists($existinguser, $column)) {
- // this should never happen
- debugging("Could not find $column on the user objects", DEBUG_DEVELOPER);
continue;
}
if ($updatetype == UU_UPDATE_MISSING) {
// Large files are likely to take their time and memory. Let PHP know
// that we'll take longer, and that the process should be recycled soon
// to free up memory.
- @set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_EXTRA);
// Create a unique temporary directory, to process the zip file
* @return moodle_url
*/
function change_password_url() {
- if ($this->is_internal()) {
+ if ($this->is_internal() || empty($this->config->changepasswordurl)) {
// Standard form.
return null;
} else {
* @return moodle_url
*/
function change_password_url() {
- return new moodle_url($this->config->changepasswordurl);
+ if (!empty($this->config->changepasswordurl)) {
+ return new moodle_url($this->config->changepasswordurl);
+ } else {
+ return null;
+ }
}
/**
*/
function change_password_url() {
if (empty($this->config->stdchangepassword)) {
- return new moodle_url($this->config->changepasswordurl);
+ if (!empty($this->config->changepasswordurl)) {
+ return new moodle_url($this->config->changepasswordurl);
+ } else {
+ return null;
+ }
} else {
return null;
}
* @return moodle_url
*/
function change_password_url() {
- return new moodle_url($this->config->changepasswordurl);
+ if (!empty($this->config->changepasswordurl)) {
+ return new moodle_url($this->config->changepasswordurl);
+ } else {
+ return null;
+ }
}
/**
This files describes API changes in /auth/* - plugins,
information provided here is intended especially for developers.
+=== 2.7 ===
+
+* If you are returning a url in method change_password_url() from config, please make sure it is set before trying to use it.
+
=== 2.6 ===
* can_be_manually_set() - This function was introduced in the base class and returns false by default. If overriden by
/**
* Returns true if this authentication plugin is 'internal'.
*
+ * Webserice auth doesn't use password fields, it uses only tokens.
+ *
* @return bool
*/
function is_internal() {
- return true;
+ return false;
}
/**
*/
public function execute_plan() {
// Basic/initial prevention against time/memory limits
- set_time_limit(1 * 60 * 60); // 1 hour for 1 course initially granted
+ core_php_time_limit::raise(1 * 60 * 60); // 1 hour for 1 course initially granted
raise_memory_limit(MEMORY_EXTRA);
// If this is not a course backup, inform the plan we are not
// including all the activities for sure. This will affect any
public function execute_plan() {
// Basic/initial prevention against time/memory limits
- set_time_limit(1 * 60 * 60); // 1 hour for 1 course initially granted
+ core_php_time_limit::raise(1 * 60 * 60); // 1 hour for 1 course initially granted
raise_memory_limit(MEMORY_EXTRA);
// If this is not a course restore, inform the plan we are not
// including all the activities for sure. This will affect any
throw new restore_controller_exception('cannot_precheck_wrong_status', $this->status);
}
// Basic/initial prevention against time/memory limits
- set_time_limit(1 * 60 * 60); // 1 hour for 1 course initially granted
+ core_php_time_limit::raise(1 * 60 * 60); // 1 hour for 1 course initially granted
raise_memory_limit(MEMORY_EXTRA);
$this->precheck = restore_prechecks_helper::execute_prechecks($this, $droptemptablesafter);
if (!array_key_exists('errors', $this->precheck)) { // No errors, can be executed
require_once($CFG->dirroot . '/backup/util/helper/convert_helper.class.php');
// Basic/initial prevention against time/memory limits
- set_time_limit(1 * 60 * 60); // 1 hour for 1 course initially granted
+ core_php_time_limit::raise(1 * 60 * 60); // 1 hour for 1 course initially granted
raise_memory_limit(MEMORY_EXTRA);
$this->progress->start_progress('Backup format conversion');
cron_trace_time_and_memory();
// This could take a while!
- @set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_EXTRA);
$nextstarttime = backup_cron_automated_helper::calculate_next_automated_backup($admin->timezone, $now);
// Remove the test dir and any content
@remove_dir(dirname($file));
-
- // Clear the time limit, otherwise PHPUnit complains.
- set_time_limit(0);
}
/**
const INDETERMINATE = -1;
/**
+ * This value is set rather high to ensure there are no regressions from
+ * previous behaviour. For testing, it may be useful to set the
+ * frontendservertimeout config option to a lower value, such as 180
+ * seconds (default for some commercial products).
+ *
* @var int The number of seconds that can pass without progress() calls.
*/
- const TIME_LIMIT_WITHOUT_PROGRESS = 120;
+ const TIME_LIMIT_WITHOUT_PROGRESS = 3600;
/**
* @var int Time of last progress call.
// Update progress.
$this->count++;
$this->lastprogresstime = $now;
- set_time_limit(self::TIME_LIMIT_WITHOUT_PROGRESS);
+
+ // Update time limit before next progress display.
+ core_php_time_limit::raise(self::TIME_LIMIT_WITHOUT_PROGRESS);
$this->update_progress();
}
// Make some progress and check that the time limit gets added.
$progress->step_time();
+ core_php_time_limit::get_and_clear_unit_test_data();
$progress->progress(2);
$this->assertTrue($progress->was_update_called());
- $this->assertEquals(120, ini_get('max_execution_time'));
+ $this->assertEquals(array(core_backup_progress::TIME_LIMIT_WITHOUT_PROGRESS),
+ core_php_time_limit::get_and_clear_unit_test_data());
// Check the new value.
$this->assert_min_max(0.2, 0.2, $progress);
// There was 1 progress call.
$this->assertEquals(1, $progress->get_progress_count());
-
- // Clear the time limit, otherwise phpunit complains.
- set_time_limit(0);
}
/**
$this->assert_min_max(0.8, 0.8, $progress);
$progress->end_progress();
$this->assertFalse($progress->is_in_progress_section());
-
- set_time_limit(0);
}
/**
$this->assert_min_max(0.4, 1.0, $progress);
$progress->end_progress();
$this->assert_min_max(1.0, 1.0, $progress);
-
- set_time_limit(0);
}
/**
$this->assert_min_max(0.01, 0.01, $progress);
$progress->end_progress();
$this->assert_min_max(0.01, 0.01, $progress);
-
- // Clear the time limit, otherwise phpunit complains.
- set_time_limit(0);
}
/**
$this->assert_min_max(0.02, 0.02, $progress);
$progress->end_progress();
$this->assert_min_max(0.02, 0.02, $progress);
-
- set_time_limit(0);
}
/**
} catch (coding_exception $e) {
$this->assertEquals(1, preg_match('~would exceed max~', $e->getMessage()));
}
-
- // Clear the time limit, otherwise phpunit complains.
- set_time_limit(0);
}
/**
*/
function __construct(base_ui_stage $uistage, $action=null, $customdata=null, $method='post', $target='', $attributes=null, $editable=true) {
$this->uistage = $uistage;
+ // Add a class to the attributes to prevent the default collapsible behaviour.
+ if (!$attributes) {
+ $attributes = array();
+ }
+ $attributes['class'] = 'unresponsive';
+ if (!isset($attributes['enctype'])) {
+ $attributes['enctype'] = 'application/x-www-form-urlencoded'; // Enforce compatibility with our max_input_vars hack.
+ }
parent::__construct($action, $customdata, $method, $target, $attributes, $editable);
}
/**
$html .= html_writer::start_tag('form', array(
'action' => $url->out_omit_querystring(),
'class' => 'backup-restore',
+ 'enctype' => 'application/x-www-form-urlencoded', // Enforce compatibility with our max_input_vars hack.
'method' => 'post'));
foreach ($url->params() as $name => $value) {
$html .= html_writer::empty_tag('input', array(
--- /dev/null
+@block @block_activity_modules @_only_local
+Feature: Block activity modules
+ In order to overview activity modules in a course
+ As a manager
+ I can add activities block in a course or on the frontpage
+
+ Background:
+ Given I log in as "admin"
+ And I expand "Site administration" node
+ And I expand "Plugins" node
+ And I expand "Activity modules" node
+ And I follow "Manage activities"
+ And I click on "//a[@title=\"Show\"]" "xpath_element" in the "Feedback" "table_row"
+ And I click on "//a[@title=\"Show\"]" "xpath_element" in the "Assignment (2.2)" "table_row"
+
+ Scenario: Add activities block on the frontpage
+ And the following "activities" exists:
+ | activity | name | intro | course | idnumber |
+ | assign | Frontpage assignment name | Frontpage assignment description | Acceptance test site | assign0 |
+ | assignment | Frontpage assignment22 name | Frontpage assignment22 description | Acceptance test site | assignment0 |
+ | book | Frontpage book name | Frontpage book description | Acceptance test site | book0 |
+ | chat | Frontpage chat name | Frontpage chat description | Acceptance test site | chat0 |
+ | choice | Frontpage choice name | Frontpage choice description | Acceptance test site | choice0 |
+ | data | Frontpage database name | Frontpage database description | Acceptance test site | data0 |
+ | feedback | Frontpage feedback name | Frontpage feedback description | Acceptance test site | feedback0 |
+ | forum | Frontpage forum name | Frontpage forum description | Acceptance test site | forum0 |
+ | label | Frontpage label name | Frontpage label description | Acceptance test site | label0 |
+ | lti | Frontpage lti name | Frontpage lti description | Acceptance test site | lti0 |
+ | page | Frontpage page name | Frontpage page description | Acceptance test site | page0 |
+ | quiz | Frontpage quiz name | Frontpage quiz description | Acceptance test site | quiz0 |
+ | resource | Frontpage resource name | Frontpage resource description | Acceptance test site | resource0 |
+ | imscp | Frontpage imscp name | Frontpage imscp description | Acceptance test site | imscp0 |
+ | folder | Frontpage folder name | Frontpage folder description | Acceptance test site | folder0 |
+ | glossary | Frontpage glossary name | Frontpage glossary description | Acceptance test site | glossary0 |
+ | scorm | Frontpage scorm name | Frontpage scorm description | Acceptance test site | scorm0 |
+ | lesson | Frontpage lesson name | Frontpage lesson description | Acceptance test site | lesson0 |
+ | survey | Frontpage survey name | Frontpage survey description | Acceptance test site | survey0 |
+ | url | Frontpage url name | Frontpage url description | Acceptance test site | url0 |
+ | wiki | Frontpage wiki name | Frontpage wiki description | Acceptance test site | wiki0 |
+ | workshop | Frontpage workshop name | Frontpage workshop description | Acceptance test site | workshop0 |
+
+ And I am on homepage
+ When I follow "Turn editing on"
+ And I add the "Activities" block
+ And I click on "Assignments" "link" in the "Activities" "block"
+ Then I should see "Frontpage assignment name"
+ And I am on homepage
+ And I click on "Assignments (2.2)" "link" in the "Activities" "block"
+ And I should see "Frontpage assignment22 name"
+ And I am on homepage
+ And I click on "Chats" "link" in the "Activities" "block"
+ And I should see "Frontpage chat name"
+ And I am on homepage
+ And I click on "Choices" "link" in the "Activities" "block"
+ And I should see "Frontpage choice name"
+ And I am on homepage
+ And I click on "Databases" "link" in the "Activities" "block"
+ And I should see "Frontpage database name"
+ And I am on homepage
+ And I click on "Feedback" "link" in the "Activities" "block"
+ And I should see "Frontpage feedback name"
+ And I am on homepage
+ And I click on "Forums" "link" in the "Activities" "block"
+ And I should see "Frontpage forum name"
+ And I am on homepage
+ And I click on "External Tools" "link" in the "Activities" "block"
+ And I should see "Frontpage lti name"
+ And I am on homepage
+ And I click on "Quizzes" "link" in the "Activities" "block"
+ And I should see "Frontpage quiz name"
+ And I am on homepage
+ And I click on "Glossaries" "link" in the "Activities" "block"
+ And I should see "Frontpage glossary name"
+ And I am on homepage
+ And I click on "SCORM packages" "link" in the "Activities" "block"
+ And I should see "Frontpage scorm name"
+ And I am on homepage
+ And I click on "Lessons" "link" in the "Activities" "block"
+ And I should see "Frontpage lesson name"
+ And I am on homepage
+ And I click on "Wikis" "link" in the "Activities" "block"
+ And I should see "Frontpage wiki name"
+ And I am on homepage
+ And I click on "Workshop" "link" in the "Activities" "block"
+ And I should see "Frontpage workshop name"
+ And I am on homepage
+ And I click on "Resources" "link" in the "Activities" "block"
+ And I should see "Frontpage book name"
+ And I should see "Frontpage page name"
+ And I should see "Frontpage resource name"
+ And I should see "Frontpage imscp name"
+ And I should see "Frontpage folder name"
+ And I should see "Frontpage url name"
+
+ Scenario: Add activities block in a course
+ Given the following "courses" exists:
+ | fullname | shortname | format |
+ | Course 1 | C1 | topics |
+ And the following "activities" exists:
+ | activity | name | intro | course | idnumber |
+ | assign | Test assignment name | Test assignment description | C1 | assign1 |
+ | assignment | Test assignment22 name | Test assignment22 description | C1 | assignment1 |
+ | book | Test book name | Test book description | C1 | book1 |
+ | chat | Test chat name | Test chat description | C1 | chat1 |
+ | choice | Test choice name | Test choice description | C1 | choice1 |
+ | data | Test database name | Test database description | C1 | data1 |
+ | feedback | Test feedback name | Test feedback description | C1 | feedback1 |
+ | folder | Test folder name | Test folder description | C1 | folder1 |
+ | forum | Test forum name | Test forum description | C1 | forum1 |
+ | glossary | Test glossary name | Test glossary description | C1 | glossary1 |
+ | imscp | Test imscp name | Test imscp description | C1 | imscp1 |
+ | label | Test label name | Test label description | C1 | label1 |
+ | lesson | Test lesson name | Test lesson description | C1 | lesson1 |
+ | lti | Test lti name | Test lti description | C1 | lti1 |
+ | page | Test page name | Test page description | C1 | page1 |
+ | quiz | Test quiz name | Test quiz description | C1 | quiz1 |
+ | resource | Test resource name | Test resource description | C1 | resource1 |
+ | scorm | Test scorm name | Test scorm description | C1 | scorm1 |
+ | survey | Test survey name | Test survey description | C1 | survey1 |
+ | url | Test url name | Test url description | C1 | url1 |
+ | wiki | Test wiki name | Test wiki description | C1 | wiki1 |
+ | workshop | Test workshop name | Test workshop description | C1 | workshop1 |
+
+ When I follow "Courses"
+ And I follow "Course 1"
+ And I turn editing mode on
+ And I add the "Activities" block
+ And I click on "Assignments" "link" in the "Activities" "block"
+ Then I should see "Test assignment name"
+ And I follow "Course 1"
+ And I click on "Assignments (2.2)" "link" in the "Activities" "block"
+ And I should see "Test assignment22 name"
+ And I follow "Course 1"
+ And I click on "Chats" "link" in the "Activities" "block"
+ And I should see "Test chat name"
+ And I follow "Course 1"
+ And I click on "Choices" "link" in the "Activities" "block"
+ And I should see "Test choice name"
+ And I follow "Course 1"
+ And I click on "Databases" "link" in the "Activities" "block"
+ And I should see "Test database name"
+ And I follow "Course 1"
+ And I click on "Feedback" "link" in the "Activities" "block"
+ And I should see "Test feedback name"
+ And I follow "Course 1"
+ And I click on "Forums" "link" in the "Activities" "block"
+ And I should see "Test forum name"
+ And I follow "Course 1"
+ And I click on "External Tools" "link" in the "Activities" "block"
+ And I should see "Test lti name"
+ And I follow "Course 1"
+ And I click on "Quizzes" "link" in the "Activities" "block"
+ And I should see "Test quiz name"
+ And I follow "Course 1"
+ And I click on "Glossaries" "link" in the "Activities" "block"
+ And I should see "Test glossary name"
+ And I follow "Course 1"
+ And I click on "SCORM packages" "link" in the "Activities" "block"
+ And I should see "Test scorm name"
+ And I follow "Course 1"
+ And I click on "Lessons" "link" in the "Activities" "block"
+ And I should see "Test lesson name"
+ And I follow "Course 1"
+ And I click on "Wikis" "link" in the "Activities" "block"
+ And I should see "Test wiki name"
+ And I follow "Course 1"
+ And I click on "Workshop" "link" in the "Activities" "block"
+ And I should see "Test workshop name"
+ And I follow "Course 1"
+ And I click on "Resources" "link" in the "Activities" "block"
+ And I should see "Test book name"
+ And I should see "Test page name"
+ And I should see "Test resource name"
+ And I should see "Test imscp name"
+ And I should see "Test folder name"
+ And I should see "Test url name"
instance : {
value : false,
setter : function(val) {
- return parseInt(val);
+ return parseInt(val, 10);
}
}
}
} else {
e.stopPropagation();
}
- if (e.type === 'actionkey' && e.action === 'enter' && e.target.test('A')) {
+ if ((e.type === 'actionkey' && e.action === 'enter') || e.target.test('a')) {
// No ajaxLoad for enter.
this.node.setAttribute('data-expandable', '0');
this.node.setAttribute('data-loaded', '1');
this.node.setAttribute('data-loaded', '1');
try {
var object = Y.JSON.parse(outcome.responseText);
+ if (object.error) {
+ Y.use('moodle-core-notification-ajaxException', function () {
+ return new M.core.ajaxException(object).show();
+ });
+ return false;
+ }
if (object.children && object.children.length > 0) {
var coursecount = 0;
for (var i in object.children) {
return true;
}
Y.log('AJAX loading complete but there were no children.', 'note', 'moodle-block_navigation');
- } catch (ex) {
- // If we got here then there was an error parsing the result.
- Y.log('Error parsing AJAX response or adding branches to the navigation tree', 'error', 'moodle-block_navigation');
+ } catch (error) {
+ if (outcome && outcome.status && outcome.status > 0) {
+ // If we got here then there was an error parsing the result.
+ Y.log('Error parsing AJAX response or adding branches to the navigation tree', 'error', 'moodle-block_navigation');
+ Y.use('moodle-core-notification-exception', function () {
+ return new M.core.exception(error).show();
+ });
+ }
+
+ return false;
}
// The branch is empty so class it accordingly
this.node.replaceClass('branch', 'emptybranch');
mtrace(' ' . $rec->url . ' ', '');
// Fetch the rss feed, using standard simplepie caching
// so feeds will be renewed only if cache has expired
- @set_time_limit(60);
+ core_php_time_limit::raise(60);
$feed = new moodle_simplepie();
// set timeout for longer than normal to be agressive at
}
if (!$ismoving) {
$actions = course_get_cm_edit_actions($mod, -1);
+
+ // Add the action move.
+ $modcontext = context_module::instance($mod->id);
+ $hasmanageactivities = has_capability('moodle/course:manageactivities', $modcontext);
+ if ($hasmanageactivities) {
+ $baseurl = new moodle_url('/course/mod.php', array('sesskey' => sesskey()));
+ $actions['move'] = new action_menu_link_primary(
+ new moodle_url($baseurl, array('copy' => $mod->id)),
+ new pix_icon('t/move', get_string('move'), 'moodle', array('class' => 'iconsmall', 'title' => '')),
+ null,
+ array('title' => get_string('move'))
+ );
+ }
+
$editbuttons = html_writer::tag('div',
$courserenderer->course_section_cm_edit_actions($actions, $mod, array('donotenhance' => true)),
array('class' => 'buttons')
}
$this->content = new stdClass;
+ $this->content->text = '';
$this->content->footer = '';
// Get a list of tags.
$bloglisting->print_entries();
echo $OUTPUT->footer();
-
-add_to_log($courseid, 'blog', 'view', 'index.php?entryid='.$entryid.'&tagid='.@$tagid.'&tag='.$tag, 'view blog entry');
+$eventparams = array(
+ 'other' => array('entryid' => $entryid, 'tagid' => $tagid, 'userid' => $userid, 'modid' => $modid, 'groupid' => $groupid,
+ 'search' => $search, 'fromstart' => $start)
+);
+if (!empty($userid)) {
+ $eventparams['relateduserid'] = $userid;
+}
+$eventparams['other']['courseid'] = ($courseid === SITEID) ? 0 : $courseid;
+$event = \core\event\blog_entries_viewed::create($eventparams);
+$event->trigger();
}
/**
- * function to add all context associations to an entry
- * @param int entry - data object processed to include all 'entry' fields and extra data from the edit_form object
+ * Function to add all context associations to an entry.
+ * TODO : Remove $action in 2.9 (MDL-41330)
+ *
+ * @param string $action - This does nothing, do not use it. This is present only for Backward compatibility.
*/
- public function add_associations($action='add') {
- global $DB, $USER;
+ public function add_associations($action = null) {
+
+ if (!empty($action)) {
+ debugging('blog_entry->add_associations() does not accept any argument', DEBUG_DEVELOPER);
+ }
$this->remove_associations();
if (!empty($this->courseassoc)) {
- $this->add_association($this->courseassoc, $action);
+ $this->add_association($this->courseassoc);
}
if (!empty($this->modassoc)) {
- $this->add_association($this->modassoc, $action);
+ $this->add_association($this->modassoc);
}
}
/**
- * add a single association for a blog entry
- * @param int contextid - id of context to associate with the blog entry
+ * Add a single association for a blog entry
+ * TODO : Remove $action in 2.9 (MDL-41330)
+ *
+ * @param int $contextid - id of context to associate with the blog entry.
+ * @param string $action - This does nothing, do not use it. This is present only for Backward compatibility.
*/
- public function add_association($contextid, $action='add') {
- global $DB, $USER;
+ public function add_association($contextid, $action = null) {
+ global $DB;
+
+ if (!empty($action)) {
+ debugging('blog_entry->add_association() accepts only one argument', DEBUG_DEVELOPER);
+ }
$assocobject = new StdClass;
$assocobject->contextid = $contextid;
$assocobject->blogid = $this->id;
- $DB->insert_record('blog_association', $assocobject);
+ $id = $DB->insert_record('blog_association', $assocobject);
+ // Trigger an association created event.
$context = context::instance_by_id($contextid);
- $courseid = null;
-
+ $eventparam = array(
+ 'objectid' => $id,
+ 'other' => array('associateid' => $context->instanceid, 'subject' => $this->subject, 'blogid' => $this->id),
+ 'relateduserid' => $this->userid
+ );
if ($context->contextlevel == CONTEXT_COURSE) {
- $courseid = $context->instanceid;
- add_to_log($courseid, 'blog', $action, 'index.php?userid='.$this->userid.'&entryid='.$this->id, $this->subject);
+ $eventparam['other']['associatetype'] = 'course';
+
} else if ($context->contextlevel == CONTEXT_MODULE) {
- $cm = $DB->get_record('course_modules', array('id' => $context->instanceid));
- $modulename = $DB->get_field('modules', 'name', array('id' => $cm->module));
- add_to_log($cm->course, 'blog', $action, 'index.php?userid='.$this->userid.'&entryid='.$this->id, $this->subject, $cm->id, $this->userid);
+ $eventparam['other']['associatetype'] = 'coursemodule';
}
+ $event = \core\event\blog_association_created::create($eventparam);
+ $event->trigger();
}
/**
$this->assertEventLegacyLogData($arr, $event);
$this->assertEventLegacyData($blog, $event);
}
+
+
+ /**
+ * Tests for event blog_association_created.
+ */
+ public function test_blog_association_created_event() {
+ global $USER;
+
+ $this->setAdminUser();
+ $this->resetAfterTest();
+ $sitecontext = context_system::instance();
+ $coursecontext = context_course::instance($this->courseid);
+ $contextmodule = context_module::instance($this->cmid);
+
+ // Add blog associations with a course.
+ $blog = new blog_entry($this->postid);
+ $sink = $this->redirectEvents();
+ $blog->add_association($coursecontext->id);
+ $events = $sink->get_events();
+ $event = reset($events);
+ $sink->close();
+
+ // Validate event data.
+ $this->assertInstanceOf('\core\event\blog_association_created', $event);
+ $this->assertEquals($sitecontext->id, $event->contextid);
+ $this->assertEquals($blog->id, $event->other['blogid']);
+ $this->assertEquals($this->courseid, $event->other['associateid']);
+ $this->assertEquals('course', $event->other['associatetype']);
+ $this->assertEquals($blog->subject, $event->other['subject']);
+ $this->assertEquals($USER->id, $event->userid);
+ $this->assertEquals($this->userid, $event->relateduserid);
+ $this->assertEquals('blog_association', $event->objecttable);
+ $arr = array(SITEID, 'blog', 'add association', 'index.php?userid=' . $this->userid . '&entryid=' . $blog->id,
+ $blog->subject, 0, $this->userid);
+ $this->assertEventLegacyLogData($arr, $event);
+
+ // Add blog associations with a module.
+ $blog = new blog_entry($this->postid);
+ $sink = $this->redirectEvents();
+ $blog->add_association($contextmodule->id);
+ $events = $sink->get_events();
+ $event = reset($events);
+ $sink->close();
+
+ // Validate event data.
+ $this->assertEquals($blog->id, $event->other['blogid']);
+ $this->assertEquals($this->cmid, $event->other['associateid']);
+ $this->assertEquals('coursemodule', $event->other['associatetype']);
+ $arr = array(SITEID, 'blog', 'add association', 'index.php?userid=' . $this->userid . '&entryid=' . $blog->id,
+ $blog->subject, $this->cmid, $this->userid);
+ $this->assertEventLegacyLogData($arr, $event);
+ }
+
+ /**
+ * Tests for event blog_association_created validations.
+ */
+ public function test_blog_association_created_event_validations() {
+
+ $this->resetAfterTest();
+
+ // Make sure associatetype validations work.
+ try {
+ \core\event\blog_association_created::create(array(
+ 'contextid' => 1,
+ 'objectid' => 3,
+ 'other' => array('associateid' => 2 , 'blogid' => 3, 'subject' => 'blog subject')));
+ } catch (coding_exception $e) {
+ $this->assertContains('Invalid associatetype', $e->getMessage());
+ }
+ try {
+ \core\event\blog_association_created::create(array(
+ 'contextid' => 1,
+ 'objectid' => 3,
+ 'other' => array('associateid' => 2 , 'blogid' => 3, 'associatetype' => 'random', 'subject' => 'blog subject')));
+ } catch (coding_exception $e) {
+ $this->assertContains('Invalid associatetype', $e->getMessage());
+ }
+ // Make sure associateid validations work.
+ try {
+ \core\event\blog_association_created::create(array(
+ 'contextid' => 1,
+ 'objectid' => 3,
+ 'other' => array('blogid' => 3, 'associatetype' => 'course', 'subject' => 'blog subject')));
+ } catch (coding_exception $e) {
+ $this->assertContains('Associate id must be set', $e->getMessage());
+ }
+ // Make sure blogid validations work.
+ try {
+ \core\event\blog_association_created::create(array(
+ 'contextid' => 1,
+ 'objectid' => 3,
+ 'other' => array('associateid' => 3, 'associatetype' => 'course', 'subject' => 'blog subject')));
+ } catch (coding_exception $e) {
+ $this->assertContains('Blog id must be set', $e->getMessage());
+ }
+ // Make sure blogid validations work.
+ try {
+ \core\event\blog_association_created::create(array(
+ 'contextid' => 1,
+ 'objectid' => 3,
+ 'other' => array('blogid' => 3, 'associateid' => 3, 'associatetype' => 'course')));
+ } catch (coding_exception $e) {
+ $this->assertContains('Subject must be set', $e->getMessage());
+ }
+ }
+
+ /**
+ * Tests for event blog_entries_viewed.
+ */
+ public function test_blog_entries_viewed_event() {
+
+ $this->setAdminUser();
+ $this->resetAfterTest();
+ $other = array('entryid' => $this->postid, 'tagid' => $this->tagid, 'userid' => $this->userid, 'modid' => $this->cmid,
+ 'groupid' => $this->groupid, 'courseid' => $this->courseid, 'search' => 'search', 'fromstart' => 2);
+
+ // Trigger event.
+ $sink = $this->redirectEvents();
+ $eventparams = array('other' => $other);
+ $eventinst = \core\event\blog_entries_viewed::create($eventparams);
+ $eventinst->trigger();
+ $events = $sink->get_events();
+ $event = reset($events);
+ $sink->close();
+
+ // Validate event data.
+ $url = new moodle_url('/blog/index.php', $other);
+ $url2 = new moodle_url('index.php', $other);
+ $this->assertEquals($url, $event->get_url());
+ $arr = array(SITEID, 'blog', 'view', $url2->out(), 'view blog entry');
+ $this->assertEventLegacyLogData($arr, $event);
+ }
}
--- /dev/null
+=== 2.7 ===
+
+* blog_entry->add_association() does not accept any params.
+* blog_entry->add_associations() accepts only one param.
\ No newline at end of file
$PAGE->set_title($title);
$PAGE->set_heading($SITE->fullname);
+/* @var core_cache_renderer $renderer */
$renderer = $PAGE->get_renderer('core_cache');
echo $renderer->header();
public function has_required_identifiers() {
return (count($this->requireidentifiers) > 0);
}
+
+ /**
+ * Returns the possible sharing options that can be used with this defintion.
+ *
+ * @return int
+ */
+ public function get_sharing_options() {
+ return $this->sharingoptions;
+ }
+
+ /**
+ * Returns the user entered sharing key for this definition.
+ *
+ * @return string
+ */
+ public function get_user_input_sharing_key() {
+ return $this->userinputsharingkey;
+ }
+
+ /**
+ * Returns the user selected sharing option for this definition.
+ *
+ * @return int
+ */
+ public function get_selected_sharing_option() {
+ return $this->selectedsharingoption;
+ }
}
*/
public function create_cache(cache_definition $definition) {
$class = $definition->get_cache_class();
- if ($this->is_initialising()) {
- // Do nothing we just want the dummy store.
- $stores = array();
- } else {
- $stores = cache_helper::get_cache_stores($definition);
- }
+ $stores = cache_helper::get_stores_suitable_for_definition($definition);
if (count($stores) === 0) {
- // Hmm no stores, better provide a dummy store to mimick functionality. The dev will be none the wiser.
+ // Hmm still no stores, better provide a dummy store to mimic functionality. The dev will be none the wiser.
$stores[] = $this->create_dummy_store($definition);
}
$loader = null;
*
* @param array $stores
* @param cache_definition $definition
- * @return array
+ * @return cache_store[]
*/
protected static function initialise_cachestore_instances(array $stores, cache_definition $definition) {
$return = array();
/**
* Record a cache hit in the stats for the given store and definition.
*
+ * @internal
* @param string $store
* @param string $definition
+ * @param int $hits The number of hits to record (by default 1)
*/
- public static function record_cache_hit($store, $definition) {
+ public static function record_cache_hit($store, $definition, $hits = 1) {
self::ensure_ready_for_stats($store, $definition);
- self::$stats[$definition][$store]['hits']++;
+ self::$stats[$definition][$store]['hits'] += $hits;
}
/**
* Record a cache miss in the stats for the given store and definition.
*
+ * @internal
* @param string $store
* @param string $definition
+ * @param int $misses The number of misses to record (by default 1)
*/
- public static function record_cache_miss($store, $definition) {
+ public static function record_cache_miss($store, $definition, $misses = 1) {
self::ensure_ready_for_stats($store, $definition);
- self::$stats[$definition][$store]['misses']++;
+ self::$stats[$definition][$store]['misses'] += $misses;
}
/**
* Record a cache set in the stats for the given store and definition.
*
+ * @internal
* @param string $store
* @param string $definition
+ * @param int $sets The number of sets to record (by default 1)
*/
- public static function record_cache_set($store, $definition) {
+ public static function record_cache_set($store, $definition, $sets = 1) {
self::ensure_ready_for_stats($store, $definition);
- self::$stats[$definition][$store]['sets']++;
+ self::$stats[$definition][$store]['sets'] += $sets;
}
/**
}
}
}
+
+ /**
+ * Returns an array of stores that would meet the requirements for every definition.
+ *
+ * These stores would be 100% suitable to map as defaults for cache modes.
+ *
+ * @return array[] An array of stores, keys are the store names.
+ */
+ public static function get_stores_suitable_for_mode_default() {
+ $factory = cache_factory::instance();
+ $config = $factory->create_config_instance();
+ $requirements = 0;
+ foreach ($config->get_definitions() as $definition) {
+ $definition = cache_definition::load($definition['component'].'/'.$definition['area'], $definition);
+ $requirements = $requirements | $definition->get_requirements_bin();
+ }
+ $stores = array();
+ foreach ($config->get_all_stores() as $name => $store) {
+ if (!empty($store['features']) && ($store['features'] & $requirements)) {
+ $stores[$name] = $store;
+ }
+ }
+ return $stores;
+ }
+
+ /**
+ * Returns stores suitable for use with a given definition.
+ *
+ * @param cache_definition $definition
+ * @return cache_store[]
+ */
+ public static function get_stores_suitable_for_definition(cache_definition $definition) {
+ $factory = cache_factory::instance();
+ $stores = array();
+ if ($factory->is_initialising() || $factory->stores_disabled()) {
+ // No suitable stores here.
+ return $stores;
+ } else {
+ $stores = self::get_cache_stores($definition);
+ if (count($stores) === 0) {
+ // No suitable stores we found for the definition. We need to come up with a sensible default.
+ // If this has happened we can be sure that the user has mapped custom stores to either the
+ // mode of the definition. The first alternative to try is the system default for the mode.
+ // e.g. the default file store instance for application definitions.
+ $config = $factory->create_config_instance();
+ foreach ($config->get_stores($definition->get_mode()) as $name => $details) {
+ if (!empty($details['default'])) {
+ $stores[] = $factory->create_store_from_config($name, $details, $definition);
+ break;
+ }
+ }
+ }
+ }
+ return $stores;
+ }
}
}
}
+ if ($this->perfdebug) {
+ $hits = 0;
+ $misses = 0;
+ foreach ($fullresult as $value) {
+ if ($value === false) {
+ $misses++;
+ } else {
+ $hits++;
+ }
+ }
+ cache_helper::record_cache_hit($this->storetype, $this->definition->get_id(), $hits);
+ cache_helper::record_cache_miss($this->storetype, $this->definition->get_id(), $misses);
+ }
+
// Return the result. Phew!
return $fullresult;
}
$this->static_acceleration_set($data[$key]['key'], $value);
}
}
- if ($this->perfdebug) {
- cache_helper::record_cache_set($this->storetype, $this->definition->get_id());
+ $successfullyset = $this->store->set_many($data);
+ if ($this->perfdebug && $successfullyset) {
+ cache_helper::record_cache_set($this->storetype, $this->definition->get_id(), $successfullyset);
}
- return $this->store->set_many($data);
+ return $successfullyset;
}
/**
if ($hasmissingkeys && $strictness === MUST_EXIST) {
throw new coding_exception('Requested key did not exist in any cache stores and could not be loaded.');
}
-
+ if ($this->perfdebug) {
+ $hits = 0;
+ $misses = 0;
+ foreach ($return as $value) {
+ if ($value === false) {
+ $misses++;
+ } else {
+ $hits++;
+ }
+ }
+ cache_helper::record_cache_hit($this->storetype, $this->get_definition()->get_id(), $hits);
+ cache_helper::record_cache_miss($this->storetype, $this->get_definition()->get_id(), $misses);
+ }
return $return;
}
'value' => $value
);
}
- if ($this->perfdebug) {
- cache_helper::record_cache_set($this->storetype, $definitionid);
+ $successfullyset = $this->get_store()->set_many($data);
+ if ($this->perfdebug && $successfullyset) {
+ cache_helper::record_cache_set($this->storetype, $definitionid, $successfullyset);
}
- return $this->get_store()->set_many($data);
+ return $successfullyset;
}
/**
* @return array
*/
public static function get_definition_summaries() {
- $instance = cache_config::instance();
- $definitions = $instance->get_definitions();
-
+ $factory = cache_factory::instance();
+ $config = $factory->create_config_instance();
$storenames = array();
- foreach ($instance->get_all_stores() as $key => $store) {
+ foreach ($config->get_all_stores() as $key => $store) {
if (!empty($store['default'])) {
$storenames[$key] = new lang_string('store_'.$key, 'cache');
- }
- }
-
- $modemappings = array();
- foreach ($instance->get_mode_mappings() as $mapping) {
- $mode = $mapping['mode'];
- if (!array_key_exists($mode, $modemappings)) {
- $modemappings[$mode] = array();
- }
- if (array_key_exists($mapping['store'], $storenames)) {
- $modemappings[$mode][] = $storenames[$mapping['store']];
} else {
- $modemappings[$mode][] = $mapping['store'];
+ $storenames[$store['name']] = $store['name'];
}
}
-
- $definitionmappings = array();
- foreach ($instance->get_definition_mappings() as $mapping) {
- $definition = $mapping['definition'];
- if (!array_key_exists($definition, $definitionmappings)) {
- $definitionmappings[$definition] = array();
- }
- if (array_key_exists($mapping['store'], $storenames)) {
- $definitionmappings[$definition][] = $storenames[$mapping['store']];
- } else {
- $definitionmappings[$definition][] = $mapping['store'];
- }
+ /* @var cache_definition[] $definitions */
+ $definitions = array();
+ foreach ($config->get_definitions() as $key => $definition) {
+ $definitions[$key] = cache_definition::load($definition['component'].'/'.$definition['area'], $definition);
}
-
- $return = array();
-
foreach ($definitions as $id => $definition) {
-
$mappings = array();
- if (array_key_exists($id, $definitionmappings)) {
- $mappings = $definitionmappings[$id];
- } else if (empty($definition['mappingsonly'])) {
- $mappings = $modemappings[$definition['mode']];
+ foreach (cache_helper::get_stores_suitable_for_definition($definition) as $store) {
+ $mappings[] = $storenames[$store->my_name()];
}
-
$return[$id] = array(
'id' => $id,
- 'name' => cache_helper::get_definition_name($definition),
- 'mode' => $definition['mode'],
- 'component' => $definition['component'],
- 'area' => $definition['area'],
+ 'name' => $definition->get_name(),
+ 'mode' => $definition->get_mode(),
+ 'component' => $definition->get_component(),
+ 'area' => $definition->get_area(),
'mappings' => $mappings,
- 'sharingoptions' => self::get_definition_sharing_options($definition['sharingoptions'], false),
- 'selectedsharingoption' => self::get_definition_sharing_options($definition['selectedsharingoption'], true),
- 'userinputsharingkey' => $definition['userinputsharingkey']
+ 'sharingoptions' => self::get_definition_sharing_options($definition->get_sharing_options(), false),
+ 'selectedsharingoption' => self::get_definition_sharing_options($definition->get_selected_sharing_option(), true),
+ 'userinputsharingkey' => $definition->get_user_input_sharing_key()
);
}
return $return;
* @return array An array containing sub-arrays, one for each mode.
*/
public static function get_default_mode_stores() {
+ global $OUTPUT;
$instance = cache_config::instance();
+ $adequatestores = cache_helper::get_stores_suitable_for_mode_default();
+ $icon = new pix_icon('i/warning', new lang_string('inadequatestoreformapping', 'cache'));
$storenames = array();
foreach ($instance->get_all_stores() as $key => $store) {
if (!empty($store['default'])) {
} else {
$modemappings[$mode][$mapping['store']] = $mapping['store'];
}
+ if (!array_key_exists($mapping['store'], $adequatestores)) {
+ $modemappings[$mode][$mapping['store']] = $modemappings[$mode][$mapping['store']].' '.$OUTPUT->render($icon);
+ }
}
return $modemappings;
}
$updatecount = 0;
// Large calendars take a while...
- set_time_limit(300);
+ core_php_time_limit::raise(300);
// Mark all events in a subscription with a zero timestamp.
if (!empty($subscriptionid)) {
$userid = $DB->get_field('user', 'id', array('username' => $username));
$steps = array(
- new Given('I click on "' . get_string('assign', 'cohort') . '" "link" in the "' . $this->escape($cohortidnumber) . '" table row'),
+ new Given('I click on "' . get_string('assign', 'cohort') . '" "link" in the "' . $this->escape($cohortidnumber) . '" "table_row"'),
new Given('I select "' . $userid . '" from "' . get_string('potusers', 'cohort') . '"'),
new Given('I press "' . get_string('add') . '"'),
new Given('I press "' . get_string('backtocohorts', 'cohort') . '"')
And I press "Upload users"
And I press "Continue"
And I follow "Cohorts"
- And I click on "Assign" "link" in the "Cohort 1" table row
+ And I click on "Assign" "link" in the "Cohort 1" "table_row"
Then the "Current users" select box should contain "Tom Jones (tomjones@example.com)"
And the "Current users" select box should contain "Bob Jones (bobjones@example.com)"
And I press "Back to cohorts"
- And I click on "Assign" "link" in the "Cohort 2" table row
+ And I click on "Assign" "link" in the "Cohort 2" "table_row"
And the "Current users" select box should contain "Mary Smith (marysmith@example.com)"
And the "Current users" select box should contain "Alice Smith (alicesmith@example.com)"
And I am on homepage
"require-dev": {
"phpunit/phpunit": "3.7.*",
"phpunit/dbUnit": "1.2.*",
- "moodlehq/behat-extension": "1.26.3"
+ "moodlehq/behat-extension": "1.27.0"
}
}
// $CFG->behat_prefix = 'bht_';
// $CFG->behat_dataroot = '/home/example/bht_moodledata';
//
-// Behat uses http://localhost:8000 as default URL to run
-// the acceptance tests, you can override this value.
+// To set a seperate wwwroot for Behat to use, use $CFG->behat_wwwroot; this is set automatically
+// to http://localhost:8000 as it is the proposed PHP built-in server URL. Instead of that you can,
+// for example, use an alias, add a host to /etc/hosts or add a new virtual host having a URL
+// poiting to your production site and another one poiting to your test site. Note that you need
+// to ensure that this URL is not accessible from the www as the behat test site uses "sugar"
+// credentials (admin/admin) and can be easily hackable.
+//
// Example:
// $CFG->behat_wwwroot = 'http://192.168.1.250:8000';
+// $CFG->behat_wwwroot = 'http://localhost/moodlesitetesting';
//
// You can override default Moodle configuration for Behat and add your own
// params; here you can add more profiles, use different Mink drivers than Selenium...
// Example:
// $CFG->behat_extraallowedsettings = array('logsql', 'dblogerror');
//
+// You should explicitly allow the usage of the deprecated behat steps, otherwise an exception will
+// be thrown when using them. The setting is disabled by default.
+// Example:
+// $CFG->behat_usedeprecated = true;
+//
+// Including feature files from directories outside the dirroot is possible if required. The setting
+// requires that the running user has executable permissions on all parent directories in the paths.
+// Example:
+// $CFG->behat_additionalfeatures = array('/home/developer/code/wipfeatures');
+//
//=========================================================================
// 12. DEVELOPER DATA GENERATOR
//=========================================================================
if ($PAGE->user_is_editing() && has_capability('moodle/course:update', $context)) {
$url = new moodle_url('/course/editsection.php', array('id'=>$section->id, 'sr'=>$sectionreturn));
$o.= html_writer::link($url,
- html_writer::empty_tag('img', array('src' => $this->output->pix_url('t/edit'),
+ html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/settings'),
'class' => 'iconsmall edit', 'alt' => get_string('edit'))),
array('title' => get_string('editsummary')));
}
}
}
- // Hide the associated grade items so the teacher doesn't also have to go to the gradebook and hide them there.
- $grade_items = grade_item::fetch_all(array('itemtype'=>'mod', 'itemmodule'=>$modulename, 'iteminstance'=>$cm->instance, 'courseid'=>$cm->course));
- if ($grade_items) {
- foreach ($grade_items as $grade_item) {
- $grade_item->set_hidden(!$visible);
- }
- }
-
// Updating visible and visibleold to keep them in sync. Only changing a section visibility will
// affect visibleold to allow for an original visibility restore. See set_section_visible().
$cminfo = new stdClass();
$cminfo->visibleold = $visible;
$DB->update_record('course_modules', $cminfo);
+ // Hide the associated grade items so the teacher doesn't also have to go to the gradebook and hide them there.
+ // Note that this must be done after updating the row in course_modules, in case
+ // the modules grade_item_update function needs to access $cm->visible.
+ if (plugin_supports('mod', $modulename, FEATURE_CONTROLS_GRADE_VISIBILITY) &&
+ component_callback_exists('mod_' . $modulename, 'grade_item_update')) {
+ $instance = $DB->get_record($modulename, array('id' => $cm->instance), '*', MUST_EXIST);
+ component_callback('mod_' . $modulename, 'grade_item_update', array($instance));
+ } else {
+ $grade_items = grade_item::fetch_all(array('itemtype'=>'mod', 'itemmodule'=>$modulename, 'iteminstance'=>$cm->instance, 'courseid'=>$cm->course));
+ if ($grade_items) {
+ foreach ($grade_items as $grade_item) {
+ $grade_item->set_hidden(!$visible);
+ }
+ }
+ }
+
rebuild_course_cache($cm->course, true);
return true;
}
* @return Given[]
*/
public function i_go_to_the_courses_management_page() {
- if ($this->running_javascript()) {
- $scenario = array(new Given('I expand "' . get_string('administrationsite') . '" node'));
- } else {
- $scenario = array(new Given('I follow "' . get_string('administrationsite') . '"'));
- }
- $scenario[] = new Given('I expand "' . get_string('courses', 'admin') . '" node');
- $scenario[] = new Given('I follow "' . get_string('coursemgmt', 'admin') . '"');
- return $scenario;
+ return array(
+ new Given('I am on homepage'),
+ new Given('I expand "' . get_string('administrationsite') . '" node'),
+ new Given('I expand "' . get_string('courses', 'admin') . '" node'),
+ new Given('I follow "' . get_string('coursemgmt', 'admin') . '"')
+ );
}
/**
- * Adds the selected activity/resource filling the form data with the specified field/value pairs.
+ * Adds the selected activity/resource filling the form data with the specified field/value pairs. Sections 0 and 1 are also allowed on frontpage.
*
* @When /^I add a "(?P<activity_or_resource_name_string>(?:[^"]|\\")*)" to section "(?P<section_number>\d+)" and I fill the form with:$/
* @param string $activity The activity name
}
/**
- * Opens the activity chooser and opens the activity/resource form page.
+ * Opens the activity chooser and opens the activity/resource form page. Sections 0 and 1 are also allowed on frontpage.
*
* @Given /^I add a "(?P<activity_or_resource_name_string>(?:[^"]|\\")*)" to section "(?P<section_number>\d+)"$/
* @throws ElementNotFoundException Thrown by behat_base::find
*/
public function i_add_to_section($activity, $section) {
- $sectionxpath = "//li[@id='section-" . $section . "']";
+ if ($this->getSession()->getPage()->find('css', 'body#page-site-index') && (int)$section <= 1) {
+ // We are on the frontpage.
+ if ($section) {
+ // Section 1 represents the contents on the frontpage.
+ $sectionxpath = "//body[@id='page-site-index']/descendant::div[contains(concat(' ',normalize-space(@class),' '),' sitetopic ')]";
+ } else {
+ // Section 0 represents "Site main menu" block.
+ $sectionxpath = "//div[contains(concat(' ',normalize-space(@class),' '),' block_site_main_menu ')]";
+ }
+ } else {
+ // We are inside the course.
+ $sectionxpath = "//li[@id='section-" . $section . "']";
+ }
$activityliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral(ucfirst($activity));
// Destroy the resource controller since we are done using it.
$rc->destroy();
unset($rc);
-
- // Clear the time limit, otherwise PHPUnit complains.
- set_time_limit(0);
}
/**
// Check that the course has been duplicated.
$this->assertEquals($newcourse['shortname'], $duplicate['shortname']);
-
- // Reset the timeouts.
- set_time_limit(0);
}
/**
$this->fail('Unknown CM found.');
}
}
-
- // Reset the timeout (see MDL-38989).
- set_time_limit(0);
}
/**
$this->fail('Unknown CM found.');
}
}
-
- // Reset the timeout (see MDL-38989).
- set_time_limit(0);
}
/**
// Check that course modules haven't changed, but that blocks have.
$this->assertEquals($initialcmcount, $newcmcount);
$this->assertEquals(($initialblockcount + 1), $newblockcount);
-
-
- // Reset the timeout (see MDL-38989).
- set_time_limit(0);
}
/**
$this->fail('Unknown CM found: '.$cm->name);
}
}
-
- // Reset the timeout (see MDL-38989).
- set_time_limit(0);
}
/**
}
// We may need a lot of time here.
- @set_time_limit(0);
+ core_php_time_limit::raise();
$plugin = enrol_get_plugin('category');
}
// Unfortunately this may take a long time, this script can be interrupted without problems.
- @set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_HUGE);
$trace->output('Starting user enrolment synchronisation...');
}
// We may need a lot of memory here.
- @set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_HUGE);
$table = $this->get_config('remoteenroltable');
$trace->output('Starting course synchronisation...');
// We may need a lot of memory here.
- @set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_HUGE);
if (!$extdb = $this->db_init()) {
global $CFG, $DB;
// We may need more memory here.
- @set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_HUGE);
$filelocation = $this->get_config('location');
$fileisnew = false;
if ( file_exists($filename) ) {
- @set_time_limit(0);
+ core_php_time_limit::raise();
$starttime = time();
$this->log_line('----------------------------------------------------------------------');
}
// We may need a lot of memory here
- @set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_HUGE);
// Get enrolments for each type of role.
$ldap_pagedresults = ldap_paged_results_supported($this->get_config('ldap_version'));
// we may need a lot of memory here
- @set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_HUGE);
$oneidnumber = null;
}
// Unfortunately this may take a long time, execution can be interrupted safely here.
- @set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_HUGE);
$trace->output('Verifying manual enrolment expiration...');
}
// unfortunately this may take a long time, execution can be interrupted safely
- @set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_HUGE);
if ($verbose) {
// Moodle v2.6.0 release upgrade line.
// Put any upgrade step following this.
+ if ($oldversion < 2013112100) {
+ // Set customint1 (group enrolment key) to 0 if it was not set (null).
+ $DB->execute("UPDATE {enrol} SET customint1 = 0 WHERE enrol = 'self' AND customint1 IS NULL");
+ upgrade_plugin_savepoint(true, 2013112100, 'enrol', 'self');
+ }
+
return true;
}
}
// Unfortunately this may take a long time, execution can be interrupted safely here.
- @set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_HUGE);
$trace->output('Verifying self-enrolments...');
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2013110500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version = 2013112100; // The current plugin version (Date: YYYYMMDDXX)
$plugin->requires = 2013110500; // Requires this Moodle version
$plugin->component = 'enrol_self'; // Full name of the plugin (used for diagnostics)
$plugin->cron = 600;
--- /dev/null
+<?xml version="1.0"?>
+<libraries>
+ <library>
+ <location>AlgParser.pm</location>
+ <name>WeBWorK</name>
+ <license>GPL</license>
+ <version>2.4.9+</version>
+ <licenseversion>2.0+</licenseversion>
+ </library>
+</libraries>
// Moodle v2.6.0 release upgrade line.
// Put any upgrade step following this.
+ if ($oldversion < 2013120300) {
+ $settings = array(
+ 'density', 'latexbackground', 'convertformat', 'pathlatex',
+ 'convertformat', 'pathconvert', 'pathdvips', 'latexpreamble');
+
+ // Move tex settings to config_pluins and delete entries from the config table.
+ foreach ($settings as $setting) {
+ $existingkey = 'filter_tex_'.$setting;
+ if (array_key_exists($existingkey, $CFG)) {
+ set_config($setting, $CFG->{$existingkey}, 'filter_tex');
+ unset_config($existingkey);
+ }
+ }
+
+ upgrade_plugin_savepoint(true, 2013120300, 'filter', 'tex');
+ }
+
return true;
}
$texcache->timemodified = time();
$DB->insert_record("cache_filters", $texcache, false);
}
- $filename = $md5 . ".{$CFG->filter_tex_convertformat}";
+ $convertformat = get_config('filter_tex', 'convertformat');
+ $filename = $md5.".{$convertformat}";
$text = str_replace( $matches[0][$i], filter_text_image($filename, $texexp, 0, 0, $align, $alt), $text);
}
return $text;
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
+$string['configconvertformat'] = 'If <i>latex</i>, <i>dvips</i> and <i>convert</i> are available, the images are created using the specified format. If it is not, mimeTeX will be used and it will create GIF images.';
+$string['convertformat'] = '<i>Convert</i> output format';
+$string['latexpreamble'] = 'LaTeX preamble';
+$string['latexsettings'] = 'LaTeX renderer Settings';
$string['filtername'] = 'TeX notation';
+$string['pathconvert'] = 'Path of <i>convert</i> binary';
+$string['pathdvips'] = 'Path of <i>dvips</i> binary';
+$string['pathlatex'] = 'Path of <i>latex</i> binary';
+$string['pathmimetex'] = 'Path of <i>mimetex</i> binary';
+$string['pathmimetexdesc'] = 'Moodle will use its own mimetex binary unless another valid path is specified.';
$string['source'] = 'TeX source';
// $fontsize don't affects to formula's size. $density can change size
$doc = "\\documentclass[{$fontsize}pt]{article}\n";
- $doc .= $CFG->filter_tex_latexpreamble;
+ $doc .= get_config('filter_tex', 'latexpreamble');
$doc .= "\\pagestyle{empty}\n";
$doc .= "\\begin{document}\n";
//dlnsk $doc .= "$ {$formula} $\n";
global $CFG;
// quick check - will this work?
- if (empty($CFG->filter_tex_pathlatex)) {
+ $pathlatex = get_config('filter_tex', 'pathlatex');
+ if (empty($pathlatex)) {
return false;
}
$tex = "{$this->temp_dir}/$filename.tex";
$dvi = "{$this->temp_dir}/$filename.dvi";
$ps = "{$this->temp_dir}/$filename.ps";
- $img = "{$this->temp_dir}/$filename.{$CFG->filter_tex_convertformat}";
+ $convertformat = get_config('filter_tex', 'convertformat');
+ $img = "{$this->temp_dir}/$filename.{$convertformat}";
// turn the latex doc into a .tex file in the temp area
$fh = fopen( $tex, 'w' );
fclose( $fh );
// run latex on document
- $command = "{$CFG->filter_tex_pathlatex} --interaction=nonstopmode --halt-on-error $tex";
+ $command = "{$pathlatex} --interaction=nonstopmode --halt-on-error $tex";
chdir( $this->temp_dir );
if ($this->execute($command, $log)) { // It allways False on Windows
// return false;
}
// run dvips (.dvi to .ps)
- $command = "{$CFG->filter_tex_pathdvips} -E $dvi -o $ps";
+ $pathdvips = get_config('filter_tex', 'pathdvips');
+ $command = "{$pathdvips} -E $dvi -o $ps";
if ($this->execute($command, $log )) {
return false;
}
} else {
$bg_opt = "";
}
- $command = "{$CFG->filter_tex_pathconvert} -density $density -trim $bg_opt $ps $img";
+ $pathconvert = get_config('filter_tex', 'pathconvert');
+ $command = "{$pathconvert} -density $density -trim $bg_opt $ps $img";
if ($this->execute($command, $log )) {
return false;
}
unlink( "{$this->temp_dir}/$filename.tex" );
unlink( "{$this->temp_dir}/$filename.dvi" );
unlink( "{$this->temp_dir}/$filename.ps" );
- unlink( "{$this->temp_dir}/$filename.{$CFG->filter_tex_convertformat}" );
+ $convertformat = get_config('filter_tex', 'convertformat');
+ unlink( "{$this->temp_dir}/$filename.{$convertformat}" );
unlink( "{$this->temp_dir}/$filename.aux" );
unlink( "{$this->temp_dir}/$filename.log" );
return;
return "$CFG->dirroot/filter/tex/mimetex.exe";
}
+ if ($pathmimetex = get_config('filter_tex', 'pathmimetex')) {
+ if (is_executable($pathmimetex)) {
+ return $pathmimetex;
+ } else {
+ print_error('mimetexnotexecutable', 'error');
+ }
+ }
+
$custom_commandpath = "$CFG->dirroot/filter/tex/mimetex";
if (file_exists($custom_commandpath)) {
if (is_executable($custom_commandpath)) {
$DB->delete_records('cache_filters', array('filter'=>'tex'));
$DB->delete_records('cache_filters', array('filter'=>'algebra'));
- if (!isset($CFG->filter_tex_pathlatex)) {
+ $pathlatex = get_config('filter_tex', 'pathlatex');
+ if ($pathlatex === false) {
// detailed settings not present yet
return;
}
- if (!(is_file($CFG->filter_tex_pathlatex) && is_executable($CFG->filter_tex_pathlatex) &&
- is_file($CFG->filter_tex_pathdvips) && is_executable($CFG->filter_tex_pathdvips) &&
- is_file($CFG->filter_tex_pathconvert) && is_executable($CFG->filter_tex_pathconvert))) {
+ $pathdvips = get_config('filter_tex', 'pathdvips');
+ $pathconvert = get_config('filter_tex', 'pathconvert');
+
+ if (!(is_file($pathlatex) && is_executable($pathlatex) &&
+ is_file($pathdvips) && is_executable($pathdvips) &&
+ is_file($pathconvert) && is_executable($pathconvert))) {
// LaTeX, dvips or convert are not available, and mimetex can only produce GIFs so...
- set_config('filter_tex_convertformat', 'gif');
+ set_config('convertformat', 'gif', 'filter_tex');
}
}
}
if (!file_exists($pathname)) {
- $md5 = str_replace(".{$CFG->filter_tex_convertformat}",'',$image);
+ $convertformat = get_config('filter_tex', 'convertformat');
+ $md5 = str_replace(".{$convertformat}", '', $image);
if ($texcache = $DB->get_record('cache_filters', array('filter'=>'tex', 'md5key'=>$md5))) {
if (!file_exists($CFG->dataroot.'/filter/tex')) {
make_upload_directory('filter/tex');
// try and render with latex first
$latex = new latex();
- $density = $CFG->filter_tex_density;
- $background = $CFG->filter_tex_latexbackground;
+ $density = get_config('filter_tex', 'density');
+ $background = get_config('filter_tex', 'latexbackground');
$texexp = $texcache->rawtext; // the entities are now decoded before inserting to DB
$latex_path = $latex->render($texexp, $md5, 12, $density, $background);
if ($latex_path) {
require_once($CFG->dirroot.'/filter/tex/lib.php');
$items = array();
- $items[] = new admin_setting_heading('filter_tex_latexheading', get_string('latexsettings', 'admin'), '');
- $items[] = new admin_setting_configtextarea('filter_tex_latexpreamble', get_string('latexpreamble','admin'),
+ $items[] = new admin_setting_heading('filter_tex/latexheading', get_string('latexsettings', 'filter_tex'), '');
+ $items[] = new admin_setting_configtextarea('filter_tex/latexpreamble', get_string('latexpreamble','filter_tex'),
'', "\\usepackage[latin1]{inputenc}\n\\usepackage{amsmath}\n\\usepackage{amsfonts}\n\\RequirePackage{amsmath,amssymb,latexsym}\n");
- $items[] = new admin_setting_configtext('filter_tex_latexbackground', get_string('backgroundcolour', 'admin'), '', '#FFFFFF');
- $items[] = new admin_setting_configtext('filter_tex_density', get_string('density', 'admin'), '', '120', PARAM_INT);
+ $items[] = new admin_setting_configtext('filter_tex/latexbackground', get_string('backgroundcolour', 'admin'), '', '#FFFFFF');
+ $items[] = new admin_setting_configtext('filter_tex/density', get_string('density', 'admin'), '', '120', PARAM_INT);
if (PHP_OS=='Linux') {
$default_filter_tex_pathlatex = "/usr/bin/latex";
$default_filter_tex_pathconvert = '';
}
- $items[] = new admin_setting_configexecutable('filter_tex_pathlatex', get_string('pathlatex', 'admin'), '', $default_filter_tex_pathlatex);
- $items[] = new admin_setting_configexecutable('filter_tex_pathdvips', get_string('pathdvips', 'admin'), '', $default_filter_tex_pathdvips);
- $items[] = new admin_setting_configexecutable('filter_tex_pathconvert', get_string('pathconvert', 'admin'), '', $default_filter_tex_pathconvert);
+ $items[] = new admin_setting_configexecutable('filter_tex/pathlatex', get_string('pathlatex', 'filter_tex'), '', $default_filter_tex_pathlatex);
+ $items[] = new admin_setting_configexecutable('filter_tex/pathdvips', get_string('pathdvips', 'filter_tex'), '', $default_filter_tex_pathdvips);
+ $items[] = new admin_setting_configexecutable('filter_tex/pathconvert', get_string('pathconvert', 'filter_tex'), '', $default_filter_tex_pathconvert);
+ $items[] = new admin_setting_configexecutable('filter_tex/pathmimetex', get_string('pathmimetex', 'filter_tex'), get_string('pathmimetexdesc', 'filter_tex'), '');
// Even if we offer GIF and PNG formats here, in the update callback we check whether
// all the paths actually point to executables. If they don't, we force the setting
// to GIF, as that's the only format mimeTeX can produce.
$formats = array('gif' => 'GIF', 'png' => 'PNG');
- $items[] = new admin_setting_configselect('filter_tex_convertformat', get_string('convertformat', 'admin'), get_string('configconvertformat', 'admin'), 'gif', $formats);
+ $items[] = new admin_setting_configselect('filter_tex/convertformat', get_string('convertformat', 'filter_tex'), get_string('configconvertformat', 'filter_tex'), 'gif', $formats);
foreach ($items as $item) {
$item->set_updatedcallback('filter_tex_updatedcallback');
$settings->add($item);
}
-}
\ No newline at end of file
+}
// first check if it is likely to work at all
$output .= "<h3>Checking executables</h3>\n";
$executables_exist = true;
- if (is_file($CFG->filter_tex_pathlatex)) {
- $output .= "latex executable ($CFG->filter_tex_pathlatex) is readable<br />\n";
+ $pathlatex = get_config('filter_tex', 'pathlatex');
+ if (is_file($pathlatex)) {
+ $output .= "latex executable ($pathlatex) is readable<br />\n";
}
else {
$executables_exist = false;
- $output .= "<b>Error:</b> latex executable ($CFG->filter_tex_pathlatex) is not readable<br />\n";
+ $output .= "<b>Error:</b> latex executable ($pathlatex) is not readable<br />\n";
}
- if (is_file($CFG->filter_tex_pathdvips)) {
- $output .= "dvips executable ($CFG->filter_tex_pathdvips) is readable<br />\n";
+ $pathdvips = get_config('filter_tex', 'pathdvips');
+ if (is_file($pathdvips)) {
+ $output .= "dvips executable ($pathdvips) is readable<br />\n";
}
else {
$executables_exist = false;
- $output .= "<b>Error:</b> dvips executable ($CFG->filter_tex_pathdvips) is not readable<br />\n";
+ $output .= "<b>Error:</b> dvips executable ($pathdvips) is not readable<br />\n";
}
- if (is_file($CFG->filter_tex_pathconvert)) {
- $output .= "convert executable ($CFG->filter_tex_pathconvert) is readable<br />\n";
+ $pathconvert = get_config('filter_tex', 'pathconvert');
+ if (is_file($pathconvert)) {
+ $output .= "convert executable ($pathconvert) is readable<br />\n";
}
else {
$executables_exist = false;
- $output .= "<b>Error:</b> convert executable ($CFG->filter_tex_pathconvert) is not readable<br />\n";
+ $output .= "<b>Error:</b> convert executable ($pathconvert) is not readable<br />\n";
}
// knowing that it might work..
$tex = "$latex->temp_dir/$md5.tex";
$dvi = "$latex->temp_dir/$md5.dvi";
$ps = "$latex->temp_dir/$md5.ps";
- $img = "$latex->temp_dir/$md5.{$CFG->filter_tex_convertformat}";
+ $convertformat = get_config('filter_tex', 'convertformat');
+ $img = "$latex->temp_dir/$md5.{$convertformat}";
// put the expression as a file into the temp area
$expression = html_entity_decode($expression);
chdir($latex->temp_dir);
// step 1: latex command
- $cmd = "$CFG->filter_tex_pathlatex --interaction=nonstopmode --halt-on-error $tex";
+ $cmd = "$pathlatex --interaction=nonstopmode --halt-on-error $tex";
$output .= execute($cmd);
// step 2: dvips command
- $cmd = "$CFG->filter_tex_pathdvips -E $dvi -o $ps";
+ $cmd = "$pathdvips -E $dvi -o $ps";
$output .= execute($cmd);
// step 3: convert command
- $cmd = "$CFG->filter_tex_pathconvert -density 240 -trim $ps $img ";
+ $cmd = "$pathconvert -density 240 -trim $ps $img ";
$output .= execute($cmd);
if (!$graphic) {
echo $output;
} else if (file_exists($img)){
- send_file($img, "$md5.{$CFG->filter_tex_convertformat}");
+ send_file($img, "$md5.{$convertformat}");
} else {
echo "Error creating image, see command execution output for more details.";
}
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2013110500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version = 2013120300; // The current plugin version (Date: YYYYMMDDXX)
$plugin->requires = 2013110500; // Requires this Moodle version
$plugin->component = 'filter_tex'; // Full name of the plugin (used for diagnostics)
// Large files are likely to take their time and memory. Let PHP know
// that we'll take longer, and that the process should be recycled soon
// to free up memory.
- @set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_EXTRA);
// Use current (non-conflicting) time stamp.
// Large files are likely to take their time and memory. Let PHP know
// that we'll take longer, and that the process should be recycled soon
// to free up memory.
- @set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_EXTRA);
$csvimport->init();
// Large files are likely to take their time and memory. Let PHP know
// that we'll take longer, and that the process should be recycled soon
// to free up memory.
-@set_time_limit(0);
+core_php_time_limit::raise();
raise_memory_limit(MEMORY_EXTRA);
$text = download_file_content($url);
// Large files are likely to take their time and memory. Let PHP know
// that we'll take longer, and that the process should be recycled soon
// to free up memory.
- @set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_EXTRA);
if ($text = $mform->get_file_content('userfile')) {
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-require_once '../../../config.php';
-require_once $CFG->libdir.'/gradelib.php';
-require_once $CFG->dirroot.'/grade/lib.php';
-require_once $CFG->dirroot.'/grade/report/grader/lib.php';
+require_once('../../../config.php');
+require_once($CFG->libdir.'/gradelib.php');
+require_once($CFG->dirroot.'/user/renderer.php');
+require_once($CFG->dirroot.'/grade/lib.php');
+require_once($CFG->dirroot.'/grade/report/grader/lib.php');
$courseid = required_param('id', PARAM_INT); // course id
$page = optional_param('page', 0, PARAM_INT); // active page
$move = optional_param('move', 0, PARAM_INT);
$type = optional_param('type', 0, PARAM_ALPHA);
$target = optional_param('target', 0, PARAM_ALPHANUM);
-$toggle = optional_param('toggle', NULL, PARAM_INT);
+$toggle = optional_param('toggle', null, PARAM_INT);
$toggle_type = optional_param('toggle_type', 0, PARAM_ALPHANUM);
+$graderreportsifirst = optional_param('sifirst', null, PARAM_ALPHA);
+$graderreportsilast = optional_param('silast', null, PARAM_ALPHA);
+
+// The report object is recreated each time, save search information to SESSION object for future use.
+if (isset($graderreportsifirst)) {
+ $SESSION->gradereport['filterfirstname'] = $graderreportsifirst;
+}
+if (isset($graderreportsilast)) {
+ $SESSION->gradereport['filtersurname'] = $graderreportsilast;
+}
+
$PAGE->set_url(new moodle_url('/grade/report/grader/index.php', array('id'=>$courseid)));
-/// basic access checks
+// basic access checks
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
}
require_capability('gradereport/grader:view', $context);
require_capability('moodle/grade:viewall', $context);
-/// return tracking object
+// return tracking object
$gpr = new grade_plugin_return(array('type'=>'report', 'plugin'=>'grader', 'courseid'=>$courseid, 'page'=>$page));
-/// last selected report session tracking
+// last selected report session tracking
if (!isset($USER->grade_last_report)) {
$USER->grade_last_report = array();
}
$USER->grade_last_report[$course->id] = 'grader';
-/// Build editing on/off buttons
+// Build editing on/off buttons
if (!isset($USER->gradeediting)) {
$USER->gradeediting = array();
$reportname = get_string('pluginname', 'gradereport_grader');
-/// Print header
+// Print header
print_grade_page_head($COURSE->id, 'report', 'grader', $reportname, false, $buttons);
//Initialise the grader report object that produces the table
//the class grade_report_grader_ajax was removed as part of MDL-21562
$report = new grade_report_grader($courseid, $gpr, $context, $page, $sortitemid);
+$numusers = $report->get_numusers(true, true);
// make sure separate group does not prevent view
if ($report->currentgroup == -2) {
exit;
}
-/// processing posted grades & feedback here
+// processing posted grades & feedback here
if ($data = data_submitted() and confirm_sesskey() and has_capability('moodle/grade:edit', $context)) {
$warnings = $report->process_data($data);
} else {
// final grades MUST be loaded after the processing
$report->load_users();
-$numusers = $report->get_numusers();
$report->load_final_grades();
-
echo $report->group_selector;
-echo '<div class="clearer"></div>';
+
+// User search
+$url = new moodle_url('/grade/report/grader/index.php', array('id' => $course->id));
+$firstinitial = isset($SESSION->gradereport['filterfirstname']) ? $SESSION->gradereport['filterfirstname'] : '';
+$lastinitial = isset($SESSION->gradereport['filtersurname']) ? $SESSION->gradereport['filtersurname'] : '';
+$totalusers = $report->get_numusers(true, false);
+$renderer = $PAGE->get_renderer('core_user');
+echo $renderer->user_search($url, $firstinitial, $lastinitial, $numusers, $totalusers, $report->currentgroupname);
//show warnings if any
-foreach($warnings as $warning) {
+foreach ($warnings as $warning) {
echo $OUTPUT->notification($warning);
}
echo $OUTPUT->paging_bar($numusers, $report->page, $studentsperpage, $report->pbarurl);
}
-$reporthtml = $report->get_grade_table();
+$displayaverages = true;
+if ($numusers == 0) {
+ $displayaverages = false;
+}
+
+$reporthtml = $report->get_grade_table($displayaverages);
// print submit button
if ($USER->gradeediting[$course->id] && ($report->get_pref('showquickfeedback') || $report->get_pref('quickgrading'))) {
- echo '<form action="index.php" method="post">';
+ echo '<form action="index.php" enctype="application/x-www-form-urlencoded" method="post">'; // Enforce compatibility with our max_input_vars hack.
echo '<div>';
echo '<input type="hidden" value="'.s($courseid).'" name="id" />';
echo '<input type="hidden" value="'.sesskey().'" name="sesskey" />';
/**
* Class providing an API for the grader report building and displaying.
* @uses grade_report
- * @package gradereport_grader
+ * @copyright 2007 Nicolas Connault
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class grade_report_grader extends grade_report {
/**
*/
public $gradeserror = array();
-//// SQL-RELATED
+ // SQL-RELATED
/**
* The id of the grade_item by which this report will be sorted.
/**
* Capability check caching
- * */
+ * @var boolean $canviewhidden
+ */
public $canviewhidden;
- var $preferencespage=false;
-
/**
* Length at which feedback will be truncated (to the nearest word) and an ellipsis be added.
* TODO replace this by a report preference
$this->pbarurl = new moodle_url('/grade/report/grader/index.php', array('id' => $this->courseid));
$this->setup_groups();
-
+ $this->setup_users();
$this->setup_sortitemid();
}
// always initialize all arrays
$queue = array();
+
$this->load_users();
$this->load_final_grades();
if ($this->get_pref('quickgrading')) {
$oldvalue->feedback = preg_replace("/\r\n|\r|\n/", "", $oldvalue->feedback);
}
- if (($oldvalue->feedback === $postedvalue) or ($oldvalue->feedback === NULL and empty($postedvalue))) {
+ if (($oldvalue->feedback === $postedvalue) or ($oldvalue->feedback === null and empty($postedvalue))) {
continue;
}
}
$errorstr = '';
// Warn if the grade is out of bounds.
- if (is_null($finalgrade)) {
- // ok
- } else {
+ if (!is_null($finalgrade)) {
$bounded = $gradeitem->bounded_grade($finalgrade);
if ($bounded > $finalgrade) {
$errorstr = 'lessthanmin';
$finalgrade = false;
$trimmed = trim($postedvalue);
if (empty($trimmed)) {
- $feedback = NULL;
+ $feedback = null;
} else {
$feedback = $postedvalue;
}
// note: we can not use $this->currentgroup because it would fail badly
// when having two browser windows each with different group
$sharinggroup = false;
- foreach($mygroups as $groupid) {
+ foreach ($mygroups as $groupid) {
if (groups_is_member($groupid, $userid)) {
$sharinggroup = true;
break;
if (isset($SESSION->gradeuserreport->sortitemid)) {
$this->sortitemid = $SESSION->gradeuserreport->sortitemid;
- }else{
+ } else {
$this->sortitemid = 'lastname';
}
if (!empty($this->users)) {
return;
}
+ $this->setup_users();
// Limit to users with a gradeable role.
list($gradebookrolessql, $gradebookrolesparams) = $DB->get_in_or_equal(explode(',', $this->gradebookroles), SQL_PARAMS_NAMED, 'grbr0');
// If the user has clicked one of the sort asc/desc arrows.
if (is_numeric($this->sortitemid)) {
- $params = array_merge(array('gitemid' => $this->sortitemid), $gradebookrolesparams, $this->groupwheresql_params, $enrolledparams,
- $relatedctxparams);
+ $params = array_merge(array('gitemid' => $this->sortitemid), $gradebookrolesparams, $this->userwheresql_params,
+ $this->groupwheresql_params, $enrolledparams, $relatedctxparams);
$sortjoin = "LEFT JOIN {grade_grades} g ON g.userid = u.id AND g.itemid = $this->sortitemid";
$sort = "g.finalgrade $this->sortorder";
break;
}
- $params = array_merge($gradebookrolesparams, $this->groupwheresql_params, $enrolledparams, $relatedctxparams);
+ $params = array_merge($gradebookrolesparams, $this->userwheresql_params, $this->groupwheresql_params, $enrolledparams, $relatedctxparams);
}
$sql = "SELECT $userfields
AND ra.contextid $relatedctxsql
) rainner ON rainner.userid = u.id
AND u.deleted = 0
+ $this->userwheresql
$this->groupwheresql
ORDER BY $sort";
$studentsperpage = $this->get_students_per_page();
}
}
}
-
return $this->users;
}
return;
}
+ if (empty($this->users)) {
+ return;
+ }
+
// please note that we must fetch all grade_grades fields if we want to construct grade_grade object from it!
$params = array_merge(array('courseid'=>$this->courseid), $this->userselect_params);
$sql = "SELECT g.*
$userids = array_keys($this->users);
-
if ($grades = $DB->get_records_sql($sql, $params)) {
foreach ($grades as $graderec) {
if (in_array($graderec->userid, $userids) and array_key_exists($graderec->itemid, $this->gtree->get_items())) { // some items may not be present!!
// prefil grades that do not exist yet
foreach ($userids as $userid) {
- foreach ($this->gtree->get_items() as $itemid=>$unused) {
+ foreach ($this->gtree->get_items() as $itemid => $unused) {
if (!isset($this->grades[$userid][$itemid])) {
$this->grades[$userid][$itemid] = new grade_grade();
$this->grades[$userid][$itemid]->itemid = $itemid;
}
/**
+ * Gets html toggle
* @deprecated since Moodle 2.4 as it appears not to be used any more.
*/
public function get_toggles_html() {
}
/**
+ * Prints html toggle
* @deprecated since 2.4 as it appears not to be used any more.
+ * @param unknown $type
*/
public function print_toggle($type) {
throw new coding_exception('print_toggle() can not be used any more');
* This consists of student names and icons, links to user reports and id numbers, as well
* as header cells for these columns. It also includes the fillers required for the
* categories displayed on the right side of the report.
+ * @param boolean $displayaverages whether to display average rows in the table
* @return array Array of html_table_row objects
*/
- public function get_left_rows() {
+ public function get_left_rows($displayaverages) {
global $CFG, $USER, $OUTPUT;
$rows = array();
if (empty($suspendedstring)) {
$suspendedstring = get_string('userenrolmentsuspended', 'grades');
}
- $usercell->text .= html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('i/enrolmentsuspended'), 'title'=>$suspendedstring, 'alt'=>$suspendedstring, 'class'=>'usersuspendedicon'));
+ $usercell->text .= html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('i/enrolmentsuspended'), 'title'=>$suspendedstring,
+ 'alt'=>$suspendedstring, 'class'=>'usersuspendedicon'));
}
$userrow->cells[] = $usercell;
}
$rows = $this->get_left_range_row($rows, $colspan);
- $rows = $this->get_left_avg_row($rows, $colspan, true);
- $rows = $this->get_left_avg_row($rows, $colspan);
+ if ($displayaverages) {
+ $rows = $this->get_left_avg_row($rows, $colspan, true);
+ $rows = $this->get_left_avg_row($rows, $colspan);
+ }
return $rows;
}
/**
* Builds and returns the rows that will make up the right part of the grader report
+ * @param boolean $displayaverages whether to display average rows in the table
* @return array Array of html_table_row objects
*/
- public function get_right_rows() {
+ public function get_right_rows($displayaverages) {
global $CFG, $USER, $OUTPUT, $DB, $PAGE;
$rows = array();
);
$jsscales = array();
- foreach ($this->gtree->get_levels() as $key=>$row) {
- if ($key == 0) {
- // do not display course grade category
- // continue;
- }
-
+ foreach ($this->gtree->get_levels() as $key => $row) {
$headingrow = new html_table_row();
$headingrow->attributes['class'] = 'heading_name_row';
$catlevel = '';
}
-// Element is a filler
+ // Element is a filler
if ($type == 'filler' or $type == 'fillerfirst' or $type == 'fillerlast') {
$fillercell = new html_table_cell();
$fillercell->attributes['class'] = $type . ' ' . $catlevel;
$fillercell->header = true;
$fillercell->scope = 'col';
$headingrow->cells[] = $fillercell;
- }
-// Element is a category
- else if ($type == 'category') {
+ } else if ($type == 'category') {
+ // Element is a category
$categorycell = new html_table_cell();
$categorycell->attributes['class'] = 'category ' . $catlevel;
$categorycell->colspan = $colspan;
}
$headingrow->cells[] = $categorycell;
- }
-// Element is a grade_item
- else {
- //$itemmodule = $element['object']->itemmodule;
- //$iteminstance = $element['object']->iteminstance;
-
+ } else {
+ // Element is a grade_item
if ($element['object']->id == $this->sortitemid) {
if ($this->sortorder == 'ASC') {
$arrow = $this->get_sort_arrow('up', $sortlink);
$scaleslist = array();
$tabindices = array();
- foreach ($this->gtree->get_items() as $itemid=>$item) {
+ foreach ($this->gtree->get_items() as $itemid => $item) {
$scale = null;
if (!empty($item->scaleid)) {
$scaleslist[] = $item->scaleid;
unset($hidingaffected);
}
-
$itemrow = new html_table_row();
$itemrow->id = 'user_'.$userid;
$itemrow->attributes['class'] = $rowclasses[$this->rowcount % 2];
$jsarguments['users'][$userid] = fullname($user);
- foreach ($this->gtree->items as $itemid=>$unused) {
+ foreach ($this->gtree->items as $itemid => $unused) {
$item =& $this->gtree->items[$itemid];
$grade = $this->grades[$userid][$item->id];
$gradeval = $grade->finalgrade;
}
if (!empty($grade->finalgrade)) {
- $gradevalforJS = null;
+ $gradevalforjs = null;
if ($item->scaleid && !empty($scalesarray[$item->scaleid])) {
- $gradevalforJS = (int)$gradeval;
+ $gradevalforjs = (int)$gradeval;
} else {
- $gradevalforJS = format_float($gradeval, $decimalpoints);
+ $gradevalforjs = format_float($gradeval, $decimalpoints);
}
- $jsarguments['grades'][] = array('user'=>$userid, 'item'=>$itemid, 'grade'=>$gradevalforJS);
+ $jsarguments['grades'][] = array('user'=>$userid, 'item'=>$itemid, 'grade'=>$gradevalforjs);
}
// MDL-11274
if (!$this->canviewhidden and $grade->is_hidden()) {
if (!empty($CFG->grade_hiddenasdate) and $grade->get_datesubmitted() and !$item->is_category_item() and !$item->is_course_item()) {
// the problem here is that we do not have the time when grade value was modified, 'timemodified' is general modification date for grade_grades records
- $itemcell->text = html_writer::tag('span', userdate($grade->get_datesubmitted(),get_string('strftimedatetimeshort')), array('class'=>'datesubmitted'));
+ $itemcell->text = html_writer::tag('span', userdate($grade->get_datesubmitted(), get_string('strftimedatetimeshort')), array('class'=>'datesubmitted'));
} else {
$itemcell->text = '-';
}
$itemcell->attributes['class'] .= ' overridden';
}
- if ($grade->is_excluded()) {
- // $itemcell->attributes['class'] .= ' excluded';
- }
-
if (!empty($grade->feedback)) {
//should we be truncating feedback? ie $short_feedback = shorten_text($feedback, $this->feedback_trunc_length);
- $jsarguments['feedback'][] = array('user'=>$userid, 'item'=>$itemid, 'content'=>wordwrap(trim(format_string($grade->feedback, $grade->feedbackformat)), 34, '<br/ >'));
+ $jsarguments['feedback'][] = array('user'=>$userid, 'item'=>$itemid, 'content'=>wordwrap(trim(format_string($grade->feedback, $grade->feedbackformat)),
+ 34, '<br/ >'));
}
if ($grade->is_excluded()) {
$gradepass = ' gradefail ';
if ($grade->is_passed($item)) {
$gradepass = ' gradepass ';
- } elseif (is_null($grade->is_passed($item))) {
+ } else if (is_null($grade->is_passed($item))) {
$gradepass = '';
}
$attributes = array('tabindex' => $tabindices[$item->id]['grade'], 'id'=>'grade_'.$userid.'_'.$item->id);
$itemcell->text .= html_writer::label(get_string('typescale', 'grades'), $attributes['id'], false, array('class' => 'accesshide'));
$itemcell->text .= html_writer::select($scaleopt, 'grade['.$userid.']['.$item->id.']', $gradeval, array(-1=>$nogradestr), $attributes);
- } elseif(!empty($scale)) {
+ } else if (!empty($scale)) {
$scales = explode(",", $scale->scale);
// invalid grade if gradeval < 1
$gradeval = $grade->grade_item->bounded_grade($gradeval); //just in case somebody changes scale
$itemcell->text .= html_writer::tag('span', $scales[$gradeval-1], array('class'=>"gradevalue$hidden$gradepass"));
}
- } else {
- // no such scale, throw error?
}
} else if ($item->gradetype != GRADE_TYPE_TEXT) { // Value type
}
}
-
// If quickfeedback is on, print an input element
if ($this->get_pref('showquickfeedback') and $grade->is_editable()) {
$feedbacklabel = fullname($user) . ' ' . $item->itemname;
if ($item->needsupdate) {
$itemcell->text .= html_writer::tag('span', get_string('error'), array('class'=>"gradingerror$hidden$gradepass"));
} else {
- $itemcell->text .= html_writer::tag('span', grade_format_gradevalue($gradeval, $item, true, $gradedisplaytype, null), array('class'=>"gradevalue$hidden$gradepass"));
+ $itemcell->text .= html_writer::tag('span', grade_format_gradevalue($gradeval, $item, true, $gradedisplaytype, null),
+ array('class'=>"gradevalue$hidden$gradepass"));
if ($this->get_pref('showanalysisicon')) {
$itemcell->text .= $this->gtree->get_grade_analysis_icon($grade);
}
$jsarguments['cfg']['ajaxenabled'] = true;
$jsarguments['cfg']['scales'] = array();
foreach ($jsscales as $scale) {
- $jsarguments['cfg']['scales'][$scale->id] = explode(',',$scale->scale);
+ $jsarguments['cfg']['scales'][$scale->id] = explode(',', $scale->scale);
}
$jsarguments['cfg']['feedbacktrunclength'] = $this->feedback_trunc_length;
'requires' => array('base', 'dom', 'event', 'event-mouseenter', 'event-key', 'io-queue', 'json-parse', 'overlay')
);
$PAGE->requires->js_init_call('M.gradereport_grader.init_report', $jsarguments, false, $module);
- $PAGE->requires->strings_for_js(array('addfeedback','feedback', 'grade'), 'grades');
- $PAGE->requires->strings_for_js(array('ajaxchoosescale','ajaxclicktoclose','ajaxerror','ajaxfailedupdate', 'ajaxfieldchanged'), 'gradereport_grader');
+ $PAGE->requires->strings_for_js(array('addfeedback', 'feedback', 'grade'), 'grades');
+ $PAGE->requires->strings_for_js(array('ajaxchoosescale', 'ajaxclicktoclose', 'ajaxerror', 'ajaxfailedupdate', 'ajaxfieldchanged'), 'gradereport_grader');
$rows = $this->get_right_range_row($rows);
- $rows = $this->get_right_avg_row($rows, true);
- $rows = $this->get_right_avg_row($rows);
+ if ($displayaverages) {
+ $rows = $this->get_right_avg_row($rows, true);
+ $rows = $this->get_right_avg_row($rows);
+ }
return $rows;
}
* Depending on the style of report (fixedstudents vs traditional one-table),
* arranges the rows of data in one or two tables, and returns the output of
* these tables in HTML
+ * @param boolean $displayaverages whether to display average rows in the table
* @return string HTML
*/
- public function get_grade_table() {
+ public function get_grade_table($displayaverages = false) {
global $OUTPUT;
$fixedstudents = $this->is_fixed_students();
- $leftrows = $this->get_left_rows();
- $rightrows = $this->get_right_rows();
+ $leftrows = $this->get_left_rows($displayaverages);
+ $rightrows = $this->get_right_rows($displayaverages);
$html = '';
-
if ($fixedstudents) {
$fixedcolumntable = new html_table();
$fixedcolumntable->id = 'fixed_column';
$controlscell = new html_table_cell();
$controlscell->attributes['class'] = 'header controls';
$controlscell->colspan = $colspan;
- $controlscell->text = $this->get_lang_string('controls','grades');
+ $controlscell->text = $this->get_lang_string('controls', 'grades');
$controlsrow->cells[] = $controlscell;
$rows[] = $controlsrow;
$rangecell->colspan = $colspan;
$rangecell->header = true;
$rangecell->scope = 'row';
- $rangecell->text = $this->get_lang_string('range','grades');
+ $rangecell->text = $this->get_lang_string('range', 'grades');
$rangerow->cells[] = $rangecell;
$rows[] = $rangerow;
}
$iconsrow = new html_table_row();
$iconsrow->attributes['class'] = 'controls';
- foreach ($this->gtree->items as $itemid=>$unused) {
+ foreach ($this->gtree->items as $itemid => $unused) {
// emulate grade element
$item = $this->gtree->get_item($itemid);
$rangerow = new html_table_row();
$rangerow->attributes['class'] = 'heading range';
- foreach ($this->gtree->items as $itemid=>$unused) {
+ foreach ($this->gtree->items as $itemid => $unused) {
$item =& $this->gtree->items[$itemid];
$itemcell = new html_table_cell();
$itemcell->attributes['class'] .= ' range i'. $itemid;
$avgrow = new html_table_row();
$avgrow->attributes['class'] = 'avg';
- foreach ($this->gtree->items as $itemid=>$unused) {
+ foreach ($this->gtree->items as $itemid => $unused) {
$item =& $this->gtree->items[$itemid];
if ($item->needsupdate) {
* figures out the state of the object and builds then returns a div
* with the icons needed for the grader report.
*
- * @param array $object
+ * @param array $element
* @return string HTML
*/
protected function get_icons($element) {
}
if ($this->get_pref('showeyecons')) {
- $showhideicon = $this->gtree->get_hiding_icon($element, $this->gpr);
+ $showhideicon = $this->gtree->get_hiding_icon($element, $this->gpr);
}
if ($this->get_pref('showlocks')) {
/**
* Given a category element returns collapsing +/- icon if available
- * @param object $object
+ * @param object $element
* @return string HTML
*/
protected function get_collapsing_icon($element) {
return $icon;
}
+ /**
+ * Processes a single action against a category, grade_item or grade.
+ * @param string $target eid ({type}{id}, e.g. c4 for category4)
+ * @param string $action Which action to take (edit, delete etc...)
+ * @return
+ */
public function process_action($target, $action) {
return self::do_process_action($target, $action);
}
/**
* Returns the maximum number of students to be displayed on each page
*
- * Takes into account the 'studentsperpage' user preference and the 'max_input_vars'
- * PHP setting. Too many fields is only a problem when submitting grades but
- * we respect 'max_input_vars' even when viewing grades to prevent students disappearing
- * when toggling editing on and off.
- *
* @return int The maximum number of students to display per page
*/
public function get_students_per_page() {
- global $USER;
- static $studentsperpage = null;
-
- if ($studentsperpage === null) {
- $originalstudentsperpage = $studentsperpage = $this->get_pref('studentsperpage');
-
- // Will this number of students result in more fields that we are allowed?
- $maxinputvars = ini_get('max_input_vars');
- if ($maxinputvars !== false) {
- // We can't do anything about there being more grade items than max_input_vars,
- // but we can decrease number of students per page if there are >= max_input_vars
- $fieldsperstudent = 0; // The number of fields output per student
-
- if ($this->get_pref('quickgrading') || $this->get_pref('showquickfeedback')) {
- // Each array (grade, feedback) will gain one element
- $fieldsperstudent ++;
- }
-
- $fieldsrequired = $studentsperpage * $fieldsperstudent;
- if ($fieldsrequired >= $maxinputvars) {
- $studentsperpage = $maxinputvars - 1; // Subtract one to be on the safe side
- if ($studentsperpage<1) {
- // Make sure students per page doesn't fall below 1, though if your
- // max_input_vars is only 1 you've got bigger problems!
- $studentsperpage = 1;
- }
-
- $a = new stdClass();
- $a->originalstudentsperpage = $originalstudentsperpage;
- $a->studentsperpage = $studentsperpage;
- $a->maxinputvars = $maxinputvars;
- debugging(get_string('studentsperpagereduced', 'grades', $a));
- }
- }
- }
-
- return $studentsperpage;
+ return $this->get_pref('studentsperpage');
}
}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-set_time_limit(0);
require_once '../../../config.php';
require_once $CFG->libdir . '/gradelib.php';
require_once '../../lib.php';
+core_php_time_limit::raise();
$courseid = required_param('id', PARAM_INT);
/**
* An abstract class containing variables and methods used by all or most reports.
- * @package core_grades
+ * @copyright 2007 Moodle Pty Ltd (http://moodle.com)
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class grade_report {
/**
*/
public $lang_strings = array();
-//// GROUP VARIABLES (including SQL)
+ // GROUP VARIABLES (including SQL)
/**
* The current group being displayed.
*/
public $currentgroup;
+ /**
+ * The current groupname being displayed.
+ * @var string $currentgroupname
+ */
+ public $currentgroupname;
+
/**
* Current course group mode
* @var int $groupmode
*/
- var $groupmode;
+ public $groupmode;
/**
* A HTML select element used to select the current group.
*/
protected $groupwheresql_params = array();
+ // USER VARIABLES (including SQL).
+
+ /**
+ * An SQL constraint to append to the queries used by this object to build the report.
+ * @var string $userwheresql
+ */
+ protected $userwheresql;
+
+ /**
+ * The ordered params for $userwheresql
+ * @var array $userwheresql_params
+ */
+ protected $userwheresql_params = array();
/**
* Constructor. Sets local copies of user preferences and initialises grade_tree.
print_error('norolesdefined', 'grades');
}
-
$this->courseid = $courseid;
if ($this->courseid == $COURSE->id) {
$this->course = $COURSE;
* the value of that preference. If the preference has already been fetched before,
* the saved value is returned. If the preference is not set at the User level, the $CFG equivalent
* is given (site default).
- * @static (Can be called statically, but then doesn't benefit from caching)
+ * Can be called statically, but then doesn't benefit from caching
* @param string $pref The name of the preference (do not include the grade_report_ prefix)
* @param int $objectid An optional itemid or categoryid to check for a more fine-grained preference
* @return mixed The value of the preference
if (!isset($this) OR get_class($this) != 'grade_report') {
if (!empty($objectid)) {
- $retval = get_user_preferences($fullprefname . $objectid, grade_report::get_pref($pref));
- } elseif (isset($CFG->$fullprefname)) {
+ $retval = get_user_preferences($fullprefname . $objectid, self::get_pref($pref));
+ } else if (isset($CFG->$fullprefname)) {
$retval = get_user_preferences($fullprefname, $CFG->$fullprefname);
- } elseif (isset($CFG->$shortprefname)) {
+ } else if (isset($CFG->$shortprefname)) {
$retval = get_user_preferences($fullprefname, $CFG->$shortprefname);
} else {
$retval = null;
/**
* Uses set_user_preferences() to update the value of a user preference. If 'default' is given as the value,
* the preference will be removed in favour of a higher-level preference.
- * @static
- * @param string $pref_name The name of the preference.
+ * @param string $pref The name of the preference.
* @param mixed $pref_value The value of the preference.
* @param int $itemid An optional itemid to which the preference will be assigned
* @return bool Success or failure.
* @param array $data
* @return mixed True or array of errors
*/
- abstract function process_data($data);
+ abstract public function process_data($data);
/**
* Processes a single action against a category, grade_item or grade.
* @param string $action Which action to take (edit, delete etc...)
* @return
*/
- abstract function process_action($target, $action);
+ abstract public function process_action($target, $action);
/**
* First checks the cached language strings, then returns match if found, or uses get_string()
/**
* Fetches and returns a count of all the users that will be shown on this page.
* @param boolean $groups include groups limit
+ * @param boolean $users include users limit - default false, used for searching purposes
* @return int Count of users
*/
- public function get_numusers($groups=true) {
- global $DB;
-
+ public function get_numusers($groups = true, $users = false) {
+ global $CFG, $DB;
+ $userwheresql = "";
$groupsql = "";
$groupwheresql = "";
$params = array_merge($gradebookrolesparams, $enrolledparams, $relatedctxparams);
+ if ($users) {
+ $userwheresql = $this->userwheresql;
+ $params = array_merge($params, $this->userwheresql_params);
+ }
+
if ($groups) {
$groupsql = $this->groupsql;
$groupwheresql = $this->groupwheresql;
$params = array_merge($params, $this->groupwheresql_params);
}
- $countsql = "SELECT COUNT(DISTINCT u.id)
+ $sql = "SELECT DISTINCT u.id
FROM {user} u
JOIN ($enrolledsql) je
ON je.id = u.id
$groupsql
WHERE ra.roleid $gradebookrolessql
AND u.deleted = 0
+ $userwheresql
$groupwheresql
AND ra.contextid $relatedctxsql";
- return $DB->count_records_sql($countsql, $params);
+ $selectedusers = $DB->get_records_sql($sql, $params);
+
+ $count = 0;
+ // Check if user's enrolment is active and should be displayed.
+ if (!empty($selectedusers)) {
+ $coursecontext = $this->context->get_course_context(true);
+
+ $useractiveenrolments = get_enrolled_users($coursecontext, '', 0, 'u.*', null, 0, 0, true);
+
+ $defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol);
+ $showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol);
+ $showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $coursecontext);
+
+ foreach ($selectedusers as $id => $value) {
+ if (!$showonlyactiveenrol || ($showonlyactiveenrol && array_key_exists($id, $useractiveenrolments))) {
+ $count++;
+ }
+ }
+ }
+ return $count;
}
/**
* Sets up this object's group variables, mainly to restrict the selection of users to display.
*/
protected function setup_groups() {
- /// find out current groups mode
+ // find out current groups mode
if ($this->groupmode = groups_get_course_groupmode($this->course)) {
$this->currentgroup = groups_get_course_group($this->course, true);
$this->group_selector = groups_print_course_menu($this->course, $this->pbarurl, true);
}
if ($this->currentgroup) {
+ $group = groups_get_group($this->currentgroup);
+ $this->currentgroupname = $group->name;
$this->groupsql = " JOIN {groups_members} gm ON gm.userid = u.id ";
$this->groupwheresql = " AND gm.groupid = :gr_grpid ";
$this->groupwheresql_params = array('gr_grpid'=>$this->currentgroup);
}
}
+ /**
+ * Sets up this report's user criteria to restrict the selection of users to display.
+ */
+ public function setup_users() {
+ global $SESSION, $DB;
+
+ $this->userwheresql = "";
+ $this->userwheresql_params = array();
+ if (isset($SESSION->gradereport['filterfirstname']) && !empty($SESSION->gradereport['filterfirstname'])) {
+ $this->userwheresql .= ' AND '.$DB->sql_like('u.firstname', ':firstname', false, false);
+ $this->userwheresql_params['firstname'] = $SESSION->gradereport['filterfirstname'].'%';
+ }
+ if (isset($SESSION->gradereport['filtersurname']) && !empty($SESSION->gradereport['filtersurname'])) {
+ $this->userwheresql .= ' AND '.$DB->sql_like('u.lastname', ':lastname', false, false);
+ $this->userwheresql_params['lastname'] = $SESSION->gradereport['filtersurname'].'%';
+ }
+ }
+
/**
* Returns an arrow icon inside an <a> tag, for the purpose of sorting a column.
* @param string $direction
- * @param moodle_url $sort_link
- * @param string HTML
+ * @param moodle_url $sortlink
*/
protected function get_sort_arrow($direction='move', $sortlink=null) {
global $OUTPUT;
$previous_courseid = $courseid;
}
- if( !$hiding_affected ) {
+ if (!$hiding_affected) {
$items = grade_item::fetch_all(array('courseid'=>$courseid));
$grades = array();
$sql = "SELECT g.*
}
unset($gradesrecords);
}
- foreach ($items as $itemid=>$unused) {
+ foreach ($items as $itemid => $unused) {
if (!isset($grades[$itemid])) {
$grade_grade = new grade_grade();
$grade_grade->userid = $this->user->id;
//if the item definitely depends on a hidden item
if (array_key_exists($course_item->id, $hiding_affected['altered'])) {
- if( !$this->showtotalsifcontainhidden[$courseid] ) {
+ if (!$this->showtotalsifcontainhidden[$courseid]) {
//hide the grade
$finalgrade = null;
- }
- else {
+ } else {
//use reprocessed marks that exclude hidden items
$finalgrade = $hiding_affected['altered'][$course_item->id];
}
} else if (!empty($hiding_affected['unknown'][$course_item->id])) {
//not sure whether or not this item depends on a hidden item
- if( !$this->showtotalsifcontainhidden[$courseid] ) {
+ if (!$this->showtotalsifcontainhidden[$courseid]) {
//hide the grade
$finalgrade = null;
- }
- else {
+ } else {
//use reprocessed marks that exclude hidden items
$finalgrade = $hiding_affected['unknown'][$course_item->id];
}
=== 2.6 ===
* grade_report_grader::get_toggles_html() and grade_report_grader::print_toggle()
can not be used any more
+* class grade_report get_numusers($groups = true, $users = false)
+ An extra parameter has been added to restrict count to those users being
+displayed
+* class grade_report_grader get_left_rows($displayaverages)
+ A parameter has been added to indicate whether averages are applicable and
+should be displayed on the report
+* class grade_report_grader get_right_rows($displayaverages)
+ A parameter has been added to indicate whether averages are applicable and
+should be displayed on the report
+* class grade_report_grader get_grade_table($displayaverages = false)
+ A parameter has been added to indicate whether averages are applicable and
+should be displayed on the report
=== 2.3.5, 2.4.2 ===
* class_grade_report::showtotalsifcontainhidden has been switched from a single integer value to an array.
And I fill the moodle form with:
| Grouping ID number | GG2 |
And I press "Save changes"
- And I click on "Edit" "link" in the "Grouping 1" table row
+ And I click on "Edit" "link" in the "Grouping 1" "table_row"
And I fill the moodle form with:
| Grouping ID number | GG2 |
And I press "Save changes"
$string['welcomep40'] = 'Das Paket enthält: <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
$string['welcomep50'] = 'Die Nutzung dieser Anwendungen ist lizenzrechtlich geprüft. Alle Anwendungen von <strong>{$a->installername}</strong> sind
<a href="http://www.opensource.org/docs/definition_plain.html"> Open Source </a> und unterliegen der <a href="http://www.gnu.org/copyleft/gpl.html"> GPL</a> Lizenz.';
-$string['welcomep60'] = 'Die folgenden Webseiten führen Sie in einfachen Schritten durch die Konfiguration und Installation von <strong>Moodle</strong> auf Ihrem Computer. Sie können die vorgeschlagenen Einstellungen übernehmen oder an Ihre Bedürfnisse anpassen.';
+$string['welcomep60'] = 'Die folgenden Webseiten führen Sie in einfachen Schritten durch die Installation von <strong>Moodle</strong> auf Ihrem Computer. Sie können die vorgeschlagenen Einstellungen übernehmen oder an eigene Bedürfnisse anpassen.';
$string['welcomep70'] = 'Klicken Sie auf die Taste \'Weiter\', um mit der Installation von Moodle fortzufahren.';
$string['wwwroot'] = 'Webadresse';
$string['pathserrcreatedataroot'] = 'A telepítő nem tudja létrehozni az adatkönyvtárat ({$a->dataroot}).';
$string['pathshead'] = 'Útvonalak megerősítése';
$string['pathsrodataroot'] = 'Az adatok gyökérkönyvtára nem írható.';
-$string['pathsroparentdataroot'] = 'A felettes könyvtás ({$a->parent}) nem írható. A telepítő nem tudja létrehozni az adatkönyvtárat ({$a->dataroot}).';
+$string['pathsroparentdataroot'] = 'A felettes könyvtár ({$a->parent}) nem írható. A telepítő nem tudja létrehozni az adatkönyvtárat ({$a->dataroot}).';
$string['pathssubadmindir'] = 'Egy pár webes gazdagép esetén az /admin speciális URL pl. a vezérlőpanel eléréséhez. Ez ütközik a Moodle admin oldalainak standard helyével. Javítás: a telepítésben nevezze át a rendszergazda könyvtárát, az új nevet pedig írja be ide. Például: <em>moodleadmin</em>. Ezzel helyrehozhatók a Moodle rendszergazdai ugrópontjai.';
$string['pathssubdataroot'] = 'Szüksége van egy helyre, ahol a Moodle mentheti a feltöltött állományokat. Ez a könyvtár a webszerver felhasználója (általában \'nobody\' vagy \'apache\') számára legyen mind olvasható, MIND ÍRHATÓ. Ha nem létezik, a telepítő megpróbálja létrehozni.';
$string['pathssubdirroot'] = 'Teljes útvonal a Moodle telepítéséhez. ';
$string['configclamactlikevirus'] = 'Treat files like viruses';
$string['configclamdonothing'] = 'Treat files as OK';
$string['configclamfailureonupload'] = 'If you have configured clam to scan uploaded files, but it is configured incorrectly or fails to run for some unknown reason, how should it behave? If you choose \'Treat files like viruses\', they\'ll be moved into the quarantine area, or deleted. If you choose \'Treat files as OK\', the files will be moved to the destination directory like normal. Either way, admins will be alerted that clam has failed. If you choose \'Treat files like viruses\' and for some reason clam fails to run (usually because you have entered an invalid pathtoclam), ALL files that are uploaded will be moved to the given quarantine area, or deleted. Be careful with this setting.';
-$string['configconvertformat'] = 'If <i>latex</i>, <i>dvips</i> and <i>convert</i> are available, the images are created using the specified format. If it is not, mimeTeX will be used and it will create GIF images.';
$string['configcookiehttponly'] = 'Enables new PHP 5.2.0 feature - browsers are instructed to send cookie with real http requests only, cookies should not be accessible by scripting languages. This is not supported in all browsers and it may not be fully compatible with current code. It helps to prevent some types of XSS attacks.';
$string['configcookiesecure'] = 'If server is accepting only https connections it is recommended to enable sending of secure cookies. If enabled please make sure that web server is not accepting http:// or set up permanent redirection to https:// address. When <em>wwwroot</em> address does not start with https:// this setting is turned off automatically.';
$string['configcountry'] = 'If you set a country here, then this country will be selected by default on new user accounts. To force users to choose a country, just leave this unset.';
$string['confirmation'] = 'Confirmation';
$string['confirmdeletecomments'] = 'You are about to delete comments, are you sure?';
$string['confirmed'] = 'Confirmed';
-$string['convertformat'] = '<i>convert</i> output format';
$string['cookiehttponly'] = 'Only http cookies';
$string['cookiesecure'] = 'Secure cookies only';
$string['country'] = 'Default country';
$string['langpackwillbeupdated'] = 'NOTE: Moodle will try to download updates for your language packs during the upgrade.';
$string['langstringcache'] = 'Cache all language strings';
$string['languagesettings'] = 'Language settings';
-$string['latexpreamble'] = 'LaTeX preamble';
-$string['latexsettings'] = 'LaTeX renderer Settings';
$string['latinexcelexport'] = 'Excel encoding';
$string['legacyfilesaddallowed'] = 'Allow adding to legacy course files';
$string['legacyfilesaddallowed_help'] = 'If a course has legacy course files, allow new files and folders to be added to it.';
$string['loglifetime'] = 'Keep logs for';
$string['longtimewarning'] = '<b>Please note that this process can take a long time.</b>';
$string['maintenancemode'] = 'In maintenance mode';
-$string['maintenancemodeisscheduled'] = 'Site is switching to maintenance mode in {$a} minutes';
+$string['maintenancemodeisscheduled'] = 'This site will be switched to maintenance mode in {$a->min} mins {$a->sec} secs';
$string['maintfileopenerror'] = 'Error opening maintenance files!';
$string['maintinprogress'] = 'Maintenance is in progress...';
$string['manageformats'] = 'Manage course formats';
$string['nomissingstrings'] = 'No missing strings';
$string['nonewsettings'] = 'No new settings were added during this upgrade.';
$string['nonexistentbookmark'] = 'The bookmark you requested does not exist.';
+$string['maxtimelimit'] = 'Maximum time limit';
+$string['maxtimelimit_desc'] = 'To restrict the maximum PHP execution time that Moodle will allow without any output being displayed, enter a value in seconds here. 0 means that Moodle default restrictions are used. If you have a front-end server with its own time limit, set this value lower to receive PHP errors in logs. Does not apply to CLI scripts.';
$string['noresults'] = 'No results found.';
$string['noroles'] = 'No roles';
$string['notifications'] = 'Notifications';
$string['order4'] = 'Fourth';
$string['passwordpolicy'] = 'Password policy';
$string['passwordresettime'] = 'Maximum time to validate password reset request';
-$string['pathconvert'] = 'Path of <i>convert</i> binary';
-$string['pathdvips'] = 'Path of <i>dvips</i> binary';
-$string['pathlatex'] = 'Path of <i>latex</i> binary';
$string['pathtoclam'] = 'clam AV path';
$string['pathtodot'] = 'Path to dot';
$string['pathtodot_help'] = 'Path to dot. Probably something like /usr/bin/dot. To be able to generate graphics from DOT files, you must have installed the dot executable and point to it here. Note that, for now, this only used by the profiling features (Development->Profiling) built into Moodle.';
$string['entryerrornotyours'] = 'This entry is not yours';
$string['entrysaved'] = 'Your entry has been saved';
$string['entrytitle'] = 'Entry title';
+$string['eventblogentriesviewed'] = 'Blog entries viewed';
+$string['eventblogassociationcreated'] = 'Blog association created';
$string['evententryadded'] = 'Blog entry added';
$string['evententrydeleted'] = 'Blog entry deleted';
$string['evententryupdated'] = 'Blog entry updated';
$string['ex_unmetstorerequirements'] = 'You are unable to use this store at the present time. Please refer to the documentation to determine its requirements.';
$string['gethit'] = 'Get - Hit';
$string['getmiss'] = 'Get - Miss';
+$string['inadequatestoreformapping'] = 'This store doesn\'t meet the requirements for all known definitions. Definitions for which this store is inadequate will be given the original default store instead of the selected store.';
$string['invalidlock'] = 'Invalid lock';
$string['invalidplugin'] = 'Invalid plugin';
$string['invalidstore'] = 'Invalid cache store provided';
$string['emailmessages'] = 'Email messages when I am offline';
$string['emailtagline'] = 'This is a copy of a message sent to you at "{$a->sitename}". Go to {$a->url} to reply.';
$string['emptysearchstring'] = 'You must search for something';
+$string['enabled'] = 'Enabled';
$string['errorcallingprocessor'] = 'Error calling defined output';
$string['errortranslatingdefault'] = 'Error translating default setting provided by plugin, using system defaults instead.';
$string['forced'] = 'Forced';
$string['settings'] = 'Settings';
$string['showlocal'] = 'Show local users';
$string['showremote'] = 'Show remote users';
-$string['ssl_acl_allow'] = 'SSO ACL: Allow user {$a->user} from {$a->host}';
-$string['ssl_acl_deny'] = 'SSO ACL: Deny user {$a->user} from {$a->host}';
+$string['ssl_acl_allow'] = 'SSO ACL: Allow user \'{$a->user}\' from \'{$a->host}\'';
+$string['ssl_acl_deny'] = 'SSO ACL: Deny user \'{$a->user}\' from \'{$a->host}\'';
$string['ssoaccesscontrol'] = 'SSO access control';
$string['ssoacldescr'] = 'Use this page to grant/deny access to specific users from remote MNet hosts. This is functional when you are offering SSO services to remote users. To control your <em>local</em> users\' ability to roam to other MNet hosts, use the roles system to grant them the <em>mnetlogintoremote</em> capability.';
$string['ssoaclneeds'] = 'For this functionality to work, you must have Networking on, plus the MNet authentication plugin enabled.';
$string['eventcoursemodulecreated'] = 'Course module created';
$string['eventcoursemoduledeleted'] = 'Course module deleted';
$string['eventcoursemoduleupdated'] = 'Course module updated';
+$string['eventcoursemoduleviewed'] = 'Course module viewed';
$string['eventcourseresetended'] = 'Course reset ended';
$string['eventcourseresetstarted'] = 'Course reset started';
$string['eventcourserestored'] = 'Course restored';
$string['plugindisabled'] = 'Disabled';
$string['pluginenable'] = 'Enable';
$string['pluginenabled'] = 'Enabled';
+$string['release'] = 'Release';
$string['requiredby'] = 'Required by: {$a}';
$string['requires'] = 'Requires';
$string['rootdir'] = 'Directory';
$string['commonrepositorysettings'] = 'Common repository settings';
$string['configallowexternallinks'] = 'This option enables all users to choose whether or not external media is copied into Moodle or not. If this is off then media is always copied into Moodle (this is usually best for overall data integrity and security). If this is on then users can choose each time they add media to a text.';
$string['configcacheexpire'] = 'The amount of time that file listings are cached locally (in seconds) when browsing external repositories.';
+$string['configgetfiletimeout'] = 'Timeout in seconds for downloading the external file into moodle.';
$string['configsaved'] = 'Configuration saved!';
+$string['configsyncfiletimeout'] = 'Timeout in seconds for syncronising the external file size.';
+$string['configsyncimagetimeout'] = 'Timeout in seconds for downloading an image file from external repository during syncronisation.';
$string['confirmdelete'] = 'Are you sure you want to delete this repository - {$a}? If you choose "Continue and download", file references to external contents will be downloaded to moodle, but it could take long time to process.';
$string['confirmdeletefile'] = 'Are you sure you want to delete this file?';
$string['confirmrenamefile'] = 'Are you sure you want to rename/move this file? There are {$a} alias/shortcut files that use this file as their source. If you proceed then those aliases will be converted to true copies.';
$string['foldernotfound'] = 'Folder not found';
$string['folderrecurse'] = 'Folder can not be moved to it\'s own subfolder';
$string['getfile'] = 'Select this file';
+$string['getfiletimeout'] = 'Get file timeout';
$string['hidden'] = 'Hidden';
$string['help'] = 'Help';
$string['choosealink'] = 'Choose a link...';
$string['size'] = 'Size';
$string['submit'] = 'Submit';
$string['sync'] = 'Sync';
+$string['syncfiletimeout'] = 'Sync file timeout';
+$string['syncimagetimeout'] = 'Sync image timeout';
$string['thumbview'] = 'View as icons';
$string['title'] = 'Choose a file...';
$string['type'] = 'Type';
function get_user_accessdata($userid, $preloadonly=false) {
global $CFG, $ACCESSLIB_PRIVATE, $USER;
- if (!empty($USER->acces['rdef']) and empty($ACCESSLIB_PRIVATE->rolepermissions)) {
+ if (!empty($USER->access['rdef']) and empty($ACCESSLIB_PRIVATE->rolepermissions)) {
// share rdef from USER session with rolepermissions cache in order to conserve memory
- foreach($USER->acces['rdef'] as $k=>$v) {
- $ACCESSLIB_PRIVATE->rolepermissions[$k] =& $USER->acces['rdef'][$k];
+ foreach ($USER->access['rdef'] as $k=>$v) {
+ $ACCESSLIB_PRIVATE->rolepermissions[$k] =& $USER->access['rdef'][$k];
}
- $ACCESSLIB_PRIVATE->accessdatabyuser[$USER->id] = $USER->acces;
+ $ACCESSLIB_PRIVATE->accessdatabyuser[$USER->id] = $USER->access;
}
if (!isset($ACCESSLIB_PRIVATE->accessdatabyuser[$userid])) {
global $CFG, $DB, $OUTPUT;
// This may take a long time.
- @set_time_limit(0);
+ core_php_time_limit::raise();
// Recursively uninstall all subplugins first.
$subplugintypes = core_component::get_plugin_types_with_subplugins();
'block_instances', '');
// Turn off time limits, sometimes upgrades can be slow.
- @set_time_limit(0);
+ core_php_time_limit::raise();
if (!$tables = $DB->get_tables() ) { // No tables yet at all.
return false;
die('Wrong node type passed.');
}
+// Start capturing output in case of broken plugins.
+ob_start();
+
$PAGE->set_context(context_system::instance());
$PAGE->set_url('/lib/ajax/getsiteadminbranch.php', array('type'=>$branchtype));
$sitenavigation = new settings_navigation_ajax($PAGE);
-// Set XML headers.
-header('Content-type: text/plain; charset=utf-8');
-// Convert and output the branch as XML.
+// Convert and output the branch as JSON.
$converter = new navigation_json();
$branch = $sitenavigation->get('root');
-echo $converter->convert($branch);
+
+$output = ob_get_contents();
+ob_end_clean();
+if ($CFG->debugdeveloper && !empty($output)) {
+ throw new coding_exception('Unexpected output whilst building the administration tree. ' .
+ 'This could be caused by trailing whitespace. Output received: ' .
+ var_export($output, true));
+} else {
+ echo $converter->convert($branch);
+}
*
* This method is used if can_change_password() returns true.
* This method is called only when user is logged in, it may use global $USER.
+ * If you are using a plugin config variable in this method, please make sure it is set before using it,
+ * as this method can be called even if the plugin is disabled, in which case the config values won't be set.
*
* @return moodle_url url of the profile page or null if standard used
*/
$awards = 0;
// Raise timelimit as this could take a while for big web sites.
- set_time_limit(0);
+ core_php_time_limit::raise();
raise_memory_limit(MEMORY_HUGE);
// For site level badges, get all active site users who can earn this badge and haven't got it yet.
// We don't check the PHP version if $CFG->behat_switchcompletely has been enabled.
// Here we are in CLI.
- if (empty($CFG->behat_switchcompletely) && $checkphp && version_compare(PHP_VERSION, '5.4.0', '<')) {
+ if (empty($CFG->behat_switchcompletely) && empty($CFG->behat_wwwroot) && $checkphp && version_compare(PHP_VERSION, '5.4.0', '<')) {
behat_error(BEHAT_EXITCODE_REQUIREMENT, 'PHP 5.4 is required. See config-dist.php for possible alternatives');
}
}
// Checking behat dataroot existence otherwise echo about admin/tool/behat/cli/init.php.
+ $CFG->behat_dataroot = realpath($CFG->behat_dataroot);
if (empty($CFG->behat_dataroot) || !is_dir($CFG->behat_dataroot) || !is_writable($CFG->behat_dataroot)) {
self::output_msg(get_string('runclitool', 'tool_behat', 'php admin/tool/behat/cli/init.php'));
return BEHAT_EXITCODE_CONFIG;
$features = array_values($featurespaths);
}
+ // Optionally include features from additional directories.
+ if (!empty($CFG->behat_additionalfeatures)) {
+ $features = array_merge($features, array_map("realpath", $CFG->behat_additionalfeatures));
+ }
+
// Gets all the components with steps definitions.
$stepsdefinitions = array();
$steps = self::get_components_steps_definitions();
}
}
+ // We don't want the deprecated steps definitions here.
+ if (!$testsrunner) {
+ unset($stepsdefinitions['behat_deprecated']);
+ }
+
// Behat config file specifing the main context class,
// the required Behat extensions and Moodle test wwwroot.
$contents = self::get_config_file_contents($features, $stepsdefinitions);
throw new coding_exception('This method can be only used by Behat CLI tool');
}
+ $tables = $DB->get_tables(false);
+ if (!empty($tables)) {
+ behat_error(BEHAT_EXITCODE_INSTALLED);
+ }
+
// New dataroot.
self::reset_dataroot();
define('BEHAT_EXITCODE_REINSTALL', 253);
define('BEHAT_EXITCODE_INSTALL', 254);
define('BEHAT_EXITCODE_COMPOSER', 255);
+define('BEHAT_EXITCODE_INSTALLED', 256);
/**
* Exits with an error code
$path = testing_cli_argument_path('/admin/tool/behat/cli/init.php');
$text = "Install Behat before enabling it, use:\n php ".$path;
break;
+ case BEHAT_EXITCODE_INSTALLED:
+ $text = "The Behat site is already installed";
+ break;
default:
$text = 'Unknown error ' . $errorcode . ' ' . $text;
break;
}
}
+
+/**
+ * Checks that the behat config vars are properly set.
+ *
+ * @return void Stops execution with error code if something goes wrong.
+ */
+function behat_check_config_vars() {
+ global $CFG;
+
+ // CFG->behat_prefix must be set and with value different than CFG->prefix and phpunit_prefix.
+ if (empty($CFG->behat_prefix) ||
+ ($CFG->behat_prefix == $CFG->prefix) ||
+ (!empty($CFG->phpunit_prefix) && $CFG->behat_prefix == $CFG->phpunit_prefix)) {
+ behat_error(BEHAT_EXITCODE_CONFIG,
+ 'Define $CFG->behat_prefix in config.php with a value different than $CFG->prefix and $CFG->phpunit_prefix');
+ }
+
+ // $CFG->behat_wwwroot must be different than CFG->wwwroot if it is set, it may not be set as
+ // it can take the default value and we should also consider that will have the same value than
+ // $CFG->wwwroot if $CFG->behat_switchcompletely is set.
+ if (!empty($CFG->behat_wwwroot) && $CFG->behat_wwwroot == $CFG->wwwroot && empty($CFG->behat_switchcompletely)) {
+ behat_error(BEHAT_EXITCODE_CONFIG,
+ 'Define $CFG->behat_wwwroot in config.php with a value different than $CFG->wwwroot');
+ }
+
+ // CFG->behat_dataroot must be set and with value different than CFG->dataroot and phpunit_dataroot.
+ $CFG->dataroot = realpath($CFG->dataroot);
+ if (!empty($CFG->behat_dataroot) && is_dir($CFG->behat_dataroot)) {
+ $CFG->behat_dataroot = realpath($CFG->behat_dataroot);
+ }
+ if (empty($CFG->behat_dataroot) ||
+ ($CFG->behat_dataroot == $CFG->dataroot) ||
+ (!empty($CFG->phpunit_dataroot) && is_dir($CFG->phpunit_dataroot)
+ && $CFG->behat_dataroot == realpath($CFG->phpunit_dataroot))) {
+ behat_error(BEHAT_EXITCODE_CONFIG,
+ 'Define $CFG->behat_dataroot in config.php with a value different than $CFG->dataroot and $CFG->phpunit_dataroot');
+ }
+
+}
+
+/**
+ * Returns a URL based on the priorities between $CFG->behat_* vars.
+ *
+ * 1.- Switch completely wins and overwrites behat_wwwroot
+ * 2.- behat_wwwroot alternatively
+ * 3.- http://localhost:8000 if there is nothing else
+ *
+ * @return string
+ */
+function behat_get_wwwroot() {
+ global $CFG;
+
+ if (!empty($CFG->behat_switchcompletely)) {
+ return $CFG->wwwroot;
+ } else if (!empty($CFG->behat_wwwroot)) {
+ return $CFG->behat_wwwroot;
+ }
+
+ return 'http://localhost:8000';
+}
+
+/**
+ * Checks if the URL requested by the user matches the provided argument
+ *
+ * @param string $url
+ * @return bool Returns true if it matches.
+ */
+function behat_is_requested_url($url) {
+
+ $parsedurl = parse_url($url . '/');
+ $parsedurl['port'] = isset($parsedurl['port']) ? $parsedurl['port'] : 80;
+ $parsedurl['path'] = rtrim($parsedurl['path'], '/');
+
+ // Removing the port.
+ $pos = strpos($_SERVER['HTTP_HOST'], ':');
+ if ($pos !== false) {
+ $requestedhost = substr($_SERVER['HTTP_HOST'], 0, $pos);
+ } else {
+ $requestedhost = $_SERVER['HTTP_HOST'];
+ }
+
+ // The path should also match.
+ if (empty($parsedurl['path'])) {
+ $matchespath = true;
+ } else if (strpos($_SERVER['SCRIPT_NAME'], $parsedurl['path']) === 0) {
+ $matchespath = true;
+ }
+
+ // The host and the port should match
+ if ($parsedurl['host'] == $requestedhost && $parsedurl['port'] == $_SERVER['SERVER_PORT'] && !empty($matchespath)) {
+ return true;
+ }
+
+ return false;
+}