Merge branch 'wip-mdl-34190' of git://github.com/rajeshtaneja/moodle
authorDan Poltawski <dan@moodle.com>
Tue, 29 Jan 2013 08:53:49 +0000 (16:53 +0800)
committerDan Poltawski <dan@moodle.com>
Tue, 29 Jan 2013 08:53:49 +0000 (16:53 +0800)
516 files changed:
.gitignore
admin/blocks.php
admin/cli/maintenance.php
admin/filters.php
admin/localplugins.php
admin/mnet/index.php
admin/plugins.php
admin/qtypes.php
admin/renderer.php
admin/repository.php
admin/roles/assign.php
admin/roles/lib.php
admin/roles/manage.php
admin/settings/appearance.php
admin/settings/plugins.php
admin/tool/behat/cli/util.php [new file with mode: 0644]
admin/tool/behat/index.php [new file with mode: 0644]
admin/tool/behat/lang/en/tool_behat.php [new file with mode: 0644]
admin/tool/behat/locallib.php [new file with mode: 0644]
admin/tool/behat/renderer.php [new file with mode: 0644]
admin/tool/behat/settings.php [new file with mode: 0644]
admin/tool/behat/steps_definitions_form.php [new file with mode: 0644]
admin/tool/behat/styles.css [new file with mode: 0644]
admin/tool/behat/tests/behat/list_steps.feature [new file with mode: 0644]
admin/tool/behat/tests/behat/test_environment.feature [new file with mode: 0644]
admin/tool/behat/tests/tool_behat_test.php [new file with mode: 0644]
admin/tool/behat/version.php [new file with mode: 0644]
admin/tool/customlang/filter_form.php
admin/tool/phpunit/cli/init.php
admin/tool/phpunit/cli/util.php
admin/tool/uploaduser/index.php
admin/tool/uploaduser/lang/en/tool_uploaduser.php
admin/tool/uploaduser/version.php
admin/tool/xmldb/actions/XMLDBCheckAction.class.php
admin/tool/xmldb/actions/check_bigints/check_bigints.class.php
admin/tool/xmldb/actions/check_defaults/check_defaults.class.php
admin/tool/xmldb/actions/check_foreign_keys/check_foreign_keys.class.php
admin/tool/xmldb/actions/check_indexes/check_indexes.class.php
admin/tool/xmldb/actions/check_oracle_semantics/check_oracle_semantics.class.php
admin/tool/xmldb/actions/delete_field/delete_field.class.php
admin/tool/xmldb/actions/delete_index/delete_index.class.php
admin/tool/xmldb/actions/delete_key/delete_key.class.php
admin/tool/xmldb/actions/delete_table/delete_table.class.php
admin/tool/xmldb/actions/delete_xml_file/delete_xml_file.class.php
admin/tool/xmldb/actions/main_view/main_view.class.php
admin/tool/xmldb/actions/revert_changes/revert_changes.class.php
admin/user.php
admin/webservice/forms.php
auth/cas/CAS/CAS.php
auth/cas/auth.php
auth/ldap/tests/ldap_test.php [new file with mode: 0644]
auth/tests/behat/behat_auth.php [new file with mode: 0644]
auth/tests/behat/login.feature [new file with mode: 0644]
backup/moodle2/backup_gradingform_plugin.class.php
backup/moodle2/restore_gradingform_plugin.class.php
backup/moodle2/restore_stepslib.php
backup/util/dbops/restore_dbops.class.php
backup/util/helper/backup_anonymizer_helper.class.php
backup/util/includes/restore_includes.php
behat.yml.dist [new file with mode: 0644]
blocks/calendar_month/block_calendar_month.php
blocks/completionstatus/block_completionstatus.php
blocks/completionstatus/details.php
blocks/course_overview/block_course_overview.php
blocks/course_overview/lang/en/block_course_overview.php
blocks/course_overview/module.js
blocks/course_overview/move.php
blocks/course_overview/renderer.php
blocks/course_overview/styles.css
blocks/course_overview/version.php
blocks/glossary_random/block_glossary_random.php
blocks/glossary_random/db/access.php
blocks/glossary_random/db/upgrade.php [deleted file]
blocks/glossary_random/lang/en/block_glossary_random.php
blocks/glossary_random/version.php
blocks/mentees/block_mentees.php
blocks/mentees/db/access.php
blocks/mentees/db/upgrade.php [deleted file]
blocks/mentees/lang/en/block_mentees.php
blocks/mentees/version.php
blocks/news_items/block_news_items.php
blocks/news_items/db/access.php
blocks/news_items/lang/en/block_news_items.php
blocks/news_items/version.php
blocks/online_users/block_online_users.php
blocks/online_users/db/access.php
blocks/online_users/db/upgrade.php [deleted file]
blocks/online_users/lang/en/block_online_users.php
blocks/online_users/tests/generator/lib.php
blocks/online_users/version.php
blocks/recent_activity/block_recent_activity.php
blocks/recent_activity/renderer.php [new file with mode: 0644]
blocks/recent_activity/version.php
blocks/rss_client/editfeed.php
blocks/rss_client/managefeeds.php
blocks/rss_client/viewfeed.php
blocks/section_links/block_section_links.php
blocks/section_links/config_instance.html [deleted file]
blocks/section_links/db/upgrade.php [moved from blocks/news_items/db/upgrade.php with 51% similarity]
blocks/section_links/edit_form.php [new file with mode: 0644]
blocks/section_links/lang/en/block_section_links.php
blocks/section_links/renderer.php [new file with mode: 0644]
blocks/section_links/settings.php
blocks/section_links/version.php
blocks/selfcompletion/block_selfcompletion.php
blocks/site_main_menu/block_site_main_menu.php
blocks/social_activities/block_social_activities.php
blog/locallib.php
cache/README.md
cache/admin.php
cache/classes/factory.php
cache/locallib.php
calendar/export_execute.php
calendar/externallib.php [new file with mode: 0644]
calendar/lib.php
calendar/managesubscriptions.php
calendar/managesubscriptions_form.php
calendar/renderer.php
calendar/tests/externallib_tests.php [new file with mode: 0644]
calendar/upgrade.txt
cohort/index.php
comment/comment.js
comment/locallib.php
composer.json
config-dist.php
course/category.php
course/dndupload.js
course/dndupload.php
course/dnduploadlib.php
course/edit.php
course/edit_form.php
course/editcategory.php
course/editsection_form.php
course/externallib.php
course/format/renderer.php
course/index.php
course/jumpto.php
course/lib.php
course/mod.php
course/modduplicate.php
course/modedit.php
course/moodleform_mod.php
course/renderer.php
course/rest.php
course/search.php
course/switchrole.php
course/tests/externallib_test.php
course/togglecompletion.php
course/view.php
course/yui/dragdrop/dragdrop.js
course/yui/modchooser/modchooser.js
course/yui/toolboxes/toolboxes.js
enrol/cohort/ajax.php
enrol/cohort/yui/quickenrolment/quickenrolment.js
enrol/editenrolment.php [moved from enrol/self/editenrolment.php with 61% similarity]
enrol/editenrolment_form.php [moved from enrol/self/editenrolment_form.php with 94% similarity]
enrol/flatfile/cli/sync.php [new file with mode: 0644]
enrol/flatfile/db/access.php [new file with mode: 0644]
enrol/flatfile/db/upgrade.php
enrol/flatfile/lang/en/enrol_flatfile.php
enrol/flatfile/lib.php
enrol/flatfile/settings.php
enrol/flatfile/tests/flatfile_test.php [new file with mode: 0644]
enrol/flatfile/version.php
enrol/imsenterprise/lang/en/enrol_imsenterprise.php
enrol/imsenterprise/lib.php
enrol/imsenterprise/locallib.php
enrol/imsenterprise/settings.php
enrol/imsenterprise/tests/imsenterprise_test.php [new file with mode: 0644]
enrol/ldap/cli/sync.php
enrol/ldap/lib.php
enrol/ldap/tests/ldap_test.php [new file with mode: 0644]
enrol/locallib.php
enrol/manual/editenrolment.php [deleted file]
enrol/manual/editenrolment_form.php [deleted file]
enrol/manual/lang/en/enrol_manual.php
enrol/manual/lib.php
enrol/meta/settings.php
enrol/paypal/cli/sync.php [new file with mode: 0644]
enrol/paypal/lang/en/enrol_paypal.php
enrol/paypal/lib.php
enrol/paypal/settings.php
enrol/paypal/tests/paypal_test.php [new file with mode: 0644]
enrol/paypal/version.php
enrol/self/db/upgrade.php
enrol/self/edit.php
enrol/self/edit_form.php
enrol/self/lang/en/enrol_self.php
enrol/self/lib.php
enrol/self/settings.php
enrol/self/tests/self_test.php
enrol/self/version.php
enrol/tests/externallib_test.php
enrol/upgrade.txt
enrol/yui/rolemanager/rolemanager.js
files/renderer.php
filter/manage.php
filter/tex/README.mimetex
filter/tex/mimetex.darwin
filter/tex/mimetex.exe
filter/tex/mimetex.freebsd
filter/tex/mimetex.linux
filter/tex/readme_moodle.txt
grade/grading/form/lib.php
grade/grading/form/rubric/backup/moodle2/backup_gradingform_rubric_plugin.class.php
grade/grading/form/rubric/backup/moodle2/restore_gradingform_rubric_plugin.class.php
grade/grading/form/rubric/db/upgrade.php
grade/grading/form/rubric/edit.php
grade/grading/form/rubric/edit_form.php
grade/grading/form/rubric/lang/en/gradingform_rubric.php
grade/grading/form/rubric/lib.php
grade/grading/form/rubric/renderer.php
grade/grading/form/rubric/rubriceditor.php
grade/grading/form/rubric/version.php
grade/grading/lib.php
grade/grading/manage.php
grade/grading/pick.php
grade/grading/pick_form.php
grade/grading/renderer.php
grade/grading/tests/lib_test.php
grade/report/grader/lib.php
grade/report/grader/styles.css
grade/report/user/lib.php
grade/tests/reportuser_test.php [new file with mode: 0644]
group/assign.php
group/autogroup.php
group/import.php
group/lib.php
group/tests/externallib_test.php
index.php
install/lang/he_kids/langconfig.php [new file with mode: 0644]
install/lang/tg/langconfig.php [new file with mode: 0644]
install/lang/zh_tw/install.php
lang/en/admin.php
lang/en/block.php
lang/en/cache.php
lang/en/calendar.php
lang/en/completion.php
lang/en/condition.php
lang/en/enrol.php
lang/en/error.php
lang/en/form.php
lang/en/group.php
lang/en/message.php
lang/en/question.php
lang/en/role.php
lib/accesslib.php
lib/adminlib.php
lib/behat/behat_base.php [new file with mode: 0644]
lib/behat/classes/behat_command.php [new file with mode: 0644]
lib/behat/classes/behat_config_manager.php [new file with mode: 0644]
lib/behat/classes/util.php [new file with mode: 0644]
lib/behat/features/bootstrap/behat_init_context.php [new file with mode: 0644]
lib/behat/form_field/behat_form_editor.php [new file with mode: 0644]
lib/behat/form_field/behat_form_field.php [new file with mode: 0644]
lib/behat/form_field/behat_form_select.php [new file with mode: 0644]
lib/behat/lib.php [new file with mode: 0644]
lib/blocklib.php
lib/completionlib.php
lib/conditionlib.php
lib/csslib.php
lib/db/caches.php
lib/db/events.php
lib/db/log.php
lib/db/services.php
lib/deprecatedlib.php
lib/dml/moodle_database.php
lib/dml/mssql_native_moodle_recordset.php
lib/dml/mysqli_native_moodle_database.php
lib/dml/mysqli_native_moodle_recordset.php
lib/dml/oci_native_moodle_recordset.php
lib/dml/pgsql_native_moodle_recordset.php
lib/dml/sqlsrv_native_moodle_recordset.php
lib/editor/tinymce/editor_styles.css [deleted file]
lib/editor/tinymce/lib.php
lib/editor/tinymce/styles.css [new file with mode: 0644]
lib/editor/tinymce/yui/collapse/collapse.js [new file with mode: 0644]
lib/enrollib.php
lib/external/externallib.php
lib/external/tests/externallib_test.php
lib/externallib.php
lib/filelib.php
lib/filestorage/file_archive.php
lib/filestorage/file_exceptions.php
lib/filestorage/file_packer.php
lib/filestorage/tests/fixtures/empty.zip [new file with mode: 0644]
lib/filestorage/tests/fixtures/zip_info.php
lib/filestorage/tests/zip_packer_test.php
lib/filestorage/zip_archive.php
lib/filestorage/zip_packer.php
lib/form/dndupload.js
lib/form/editor.php
lib/form/filemanager.js
lib/form/filemanager.php
lib/form/filepicker.js
lib/form/selectyesno.php
lib/grouplib.php
lib/javascript-static.js
lib/messagelib.php
lib/modinfolib.php
lib/moodlelib.php
lib/navigationlib.php
lib/outputcomponents.php
lib/outputrenderers.php
lib/phpunit/bootstrap.php
lib/phpunit/bootstraplib.php
lib/phpunit/classes/advanced_testcase.php
lib/phpunit/classes/hint_resultprinter.php
lib/phpunit/classes/util.php
lib/phpunit/generatorlib.php
lib/phpunit/lib.php
lib/phpunit/tests/advanced_test.php
lib/phpunit/tests/basic_test.php
lib/plagiarismlib.php
lib/pluginlib.php
lib/resourcelib.php
lib/sessionlib.php
lib/setup.php
lib/setuplib.php
lib/testing/classes/test_lock.php [new file with mode: 0644]
lib/testing/classes/tests_finder.php [new file with mode: 0644]
lib/testing/classes/util.php [new file with mode: 0644]
lib/testing/generator/block_generator.php [moved from lib/phpunit/classes/block_generator.php with 73% similarity]
lib/testing/generator/data_generator.php [moved from lib/phpunit/classes/data_generator.php with 94% similarity]
lib/testing/generator/lib.php [new file with mode: 0644]
lib/testing/generator/module_generator.php [moved from lib/phpunit/classes/module_generator.php with 74% similarity]
lib/testing/lib.php [new file with mode: 0644]
lib/testing/tests/generator_test.php [moved from lib/phpunit/tests/generator_test.php with 98% similarity]
lib/tests/accesslib_test.php
lib/tests/behat/behat_forms.php [new file with mode: 0644]
lib/tests/behat/behat_general.php [new file with mode: 0644]
lib/tests/behat/behat_hooks.php [new file with mode: 0644]
lib/tests/behat/behat_navigation.php [new file with mode: 0644]
lib/tests/externallib_test.php
lib/tests/grouplib_test.php
lib/tests/moodlelib_test.php
lib/tests/weblib_test.php
lib/upgrade.txt
lib/weblib.php
lib/yui/chooserdialogue/chooserdialogue.js
lib/yui/formautosubmit/formautosubmit.js
lib/yui/formchangechecker/formchangechecker.js
login/index.php
login/index_form.html
message/externallib.php
message/index.php
message/lib.php
message/tests/externallib_test.php
mod/assign/assignmentplugin.php
mod/assign/db/services.php
mod/assign/externallib.php
mod/assign/feedback/comments/locallib.php
mod/assign/feedback/file/importziplib.php
mod/assign/feedback/file/locallib.php
mod/assign/lib.php
mod/assign/locallib.php
mod/assign/submission/comments/locallib.php
mod/assign/submission/file/locallib.php
mod/assign/submission/onlinetext/locallib.php
mod/assign/tests/externallib_test.php
mod/assign/tests/generator/lib.php
mod/assign/tests/lib_test.php [new file with mode: 0644]
mod/assign/tests/upgradelib_test.php
mod/assign/upgradelib.php
mod/assign/version.php
mod/assignment/tests/generator/lib.php
mod/book/tool/importhtml/locallib.php
mod/book/tool/print/index.php
mod/book/tool/print/print.css
mod/chat/lib.php
mod/data/tests/generator/lib.php
mod/feedback/analysis.php
mod/feedback/analysis_course.php
mod/feedback/lib.php
mod/forum/backup/moodle2/restore_forum_activity_task.class.php
mod/forum/lib.php
mod/forum/tests/generator/lib.php
mod/glossary/editcategories.html
mod/glossary/editcategories.php
mod/glossary/formats.php
mod/lesson/format.php
mod/lesson/locallib.php
mod/lesson/pagetypes/essay.php
mod/lesson/pagetypes/matching.php
mod/lti/tests/generator/lib.php
mod/page/tests/generator/lib.php
mod/quiz/backup/moodle2/restore_quiz_stepslib.php
mod/quiz/cronlib.php
mod/quiz/edit.php
mod/quiz/lang/en/quiz.php
mod/quiz/locallib.php
mod/quiz/report/statistics/report.php
mod/quiz/styles.css
mod/quiz/tests/generator/lib.php
mod/quiz/tests/reportlib_test.php [moved from mod/quiz/report/tests/reportlib_test.php with 100% similarity]
mod/scorm/locallib.php
mod/scorm/module.js
mod/scorm/player.php
mod/wiki/lang/en/wiki.php
mod/wiki/lib.php
mod/wiki/pagelib.php
notes/tests/externallib_test.php
phpunit.xml.dist
question/behaviour/adaptive/tests/walkthrough_test.php
question/behaviour/adaptivenopenalty/tests/walkthrough_test.php
question/behaviour/deferredcbm/tests/walkthrough_test.php
question/behaviour/deferredfeedback/tests/walkthrough_test.php
question/behaviour/immediatecbm/tests/walkthrough_test.php
question/behaviour/immediatefeedback/tests/walkthrough_test.php
question/behaviour/informationitem/tests/walkthrough_test.php
question/behaviour/interactive/tests/walkthrough_test.php
question/behaviour/interactivecountback/tests/walkthrough_test.php
question/behaviour/manualgraded/tests/walkthrough_test.php
question/behaviour/missing/tests/missingbehaviour_test.php
question/engine/questionattempt.php
question/engine/questionattemptstep.php
question/engine/tests/helpers.php
question/engine/tests/questionattempt_test.php
question/format.php
question/format/blackboard_six/formatqti.php
question/format/blackboard_six/lang/en/qformat_blackboard_six.php
question/format/examview/format.php
question/format/gift/tests/giftformat_test.php
question/format/learnwise/format.php
question/format/missingword/format.php
question/format/missingword/lang/en/qformat_missingword.php
question/format/missingword/tests/fixtures/question.missingword1.txt [new file with mode: 0644]
question/format/missingword/tests/fixtures/question.missingword2.txt [new file with mode: 0644]
question/format/missingword/tests/fixtures/question.missingword3.txt [new file with mode: 0644]
question/format/xhtml/format.php
question/format/xml/format.php
question/format/xml/tests/fixtures/multichoice.xml [new file with mode: 0644]
question/format/xml/tests/fixtures/truefalse.xml [new file with mode: 0644]
question/format/xml/tests/xmlformat_test.php
question/previewlib.php
question/type/calculated/lang/en/qtype_calculated.php
question/type/calculated/questiontype.php
question/type/calculated/tests/walkthrough_test.php
question/type/calculatedmulti/edit_calculatedmulti_form.php
question/type/calculatedmulti/tests/walkthrough_test.php
question/type/calculatedsimple/lang/en/qtype_calculatedsimple.php
question/type/calculatedsimple/tests/walkthrough_test.php
question/type/edit_question_form.php
question/type/essay/db/upgrade.php
question/type/essay/questiontype.php
question/type/essay/version.php
question/type/match/backup/moodle1/lib.php
question/type/match/backup/moodle2/backup_qtype_match_plugin.class.php
question/type/match/backup/moodle2/restore_qtype_match_plugin.class.php
question/type/match/db/install.xml
question/type/match/db/upgrade.php
question/type/match/db/upgradelib.php
question/type/match/edit_match_form.php
question/type/match/lang/en/qtype_match.php
question/type/match/question.php
question/type/match/questiontype.php
question/type/match/renderer.php
question/type/match/tests/question_test.php
question/type/match/tests/questiontype_test.php
question/type/match/tests/upgradelibnewqe_test.php
question/type/match/tests/walkthrough_test.php
question/type/match/version.php
question/type/missingtype/tests/missingtype_test.php
question/type/multianswer/edit_multianswer_form.php
question/type/multianswer/questiontype.php
question/type/multianswer/renderer.php
question/type/multianswer/tests/walkthrough_test.php
question/type/multichoice/lang/en/qtype_multichoice.php
question/type/multichoice/tests/question_test.php
question/type/numerical/edit_numerical_form.php
question/type/numerical/lang/en/qtype_numerical.php
question/type/numerical/question.php
question/type/numerical/questiontype.php
question/type/numerical/tests/answerprocessor_test.php
question/type/numerical/tests/walkthrough_test.php
question/type/questiontypebase.php
question/type/shortanswer/backup/moodle2/backup_qtype_shortanswer_plugin.class.php
question/type/shortanswer/backup/moodle2/restore_qtype_shortanswer_plugin.class.php
question/type/shortanswer/db/install.xml
question/type/shortanswer/db/upgrade.php [new file with mode: 0644]
question/type/shortanswer/edit_shortanswer_form.php
question/type/shortanswer/question.php
question/type/shortanswer/questiontype.php
question/type/shortanswer/tests/upgradelibnewqe_test.php [moved from question/type/shortanswer/tests/tupgradelibnewqe_test.php with 100% similarity]
question/type/shortanswer/version.php
question/type/truefalse/tests/walkthrough_test.php
report/completion/index.php
report/completion/user.php
report/configlog/index.php
report/outline/index.php
report/security/index.php
repository/equella/lib.php
repository/flickr_public/lib.php
repository/wikimedia/lang/en/repository_wikimedia.php
repository/wikimedia/lib.php
repository/wikimedia/wikimedia.php
tag/manage.php
theme/base/pix/progress.gif [new file with mode: 0644]
theme/base/style/admin.css
theme/base/style/calendar.css
theme/base/style/core.css
theme/base/style/course.css
theme/base/style/filemanager.css
theme/formal_white/style/course.css
theme/formal_white/style/formal_white.css
theme/standard/style/admin.css
theme/standard/style/course.css
user/editadvanced_form.php
user/index.php
user/lib.php
user/profile/lib.php
user/tests/externallib_test.php
user/view.php
version.php
webservice/rest/locallib.php
webservice/tests/externallib_test.php

index e27bed2..e1cc233 100644 (file)
@@ -30,3 +30,4 @@ phpunit.xml
 composer.phar
 composer.lock
 /vendor/
+/behat.yml
index e703ee8..5b5c3a1 100644 (file)
     $table->define_columns(array('name', 'instances', 'version', 'hideshow', 'undeletable', 'delete', 'settings'));
     $table->define_headers(array($strname, $strcourses, $strversion, $strhide.'/'.$strshow, $strprotecthdr, $strdelete, $strsettings));
     $table->define_baseurl($CFG->wwwroot.'/'.$CFG->admin.'/blocks.php');
-    $table->set_attribute('class', 'compatibleblockstable blockstable generaltable');
+    $table->set_attribute('class', 'admintable blockstable generaltable');
+    $table->set_attribute('id', 'compatibleblockstable');
     $table->setup();
     $tablerows = array();
 
index 01bfcc6..b267a03 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
@@ -16,7 +15,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Enable or disable maintenance mode
+ * Enable or disable maintenance mode.
  *
  * @package    core
  * @subpackage cli
 
 define('CLI_SCRIPT', true);
 
-require(dirname(dirname(dirname(__FILE__))).'/config.php');
-require_once($CFG->libdir.'/clilib.php');      // cli only functions
+require(__DIR__.'/../../config.php');
+require_once("$CFG->libdir/clilib.php");
+require_once("$CFG->libdir/adminlib.php");
 
 
-// now get cli options
-list($options, $unrecognized) = cli_get_params(array('enable'=>false, 'disable'=>false, 'help'=>false),
+// Now get cli options.
+list($options, $unrecognized) = cli_get_params(array('enable'=>false, 'enablelater'=>0, 'enableold'=>false, 'disable'=>false, 'help'=>false),
                                                array('h'=>'help'));
 
 if ($unrecognized) {
@@ -45,12 +45,14 @@ if ($options['help']) {
 Current status displayed if not option specified.
 
 Options:
---enable              Enable maintenance mode
+--enable              Enable CLI maintenance mode
+--enablelater=MINUTES Number of minutes before entering CLI maintenance mode
+--enableold           Enable legacy half-maintenance mode
 --disable             Disable maintenance mode
 -h, --help            Print out this help
 
 Example:
-\$sudo -u www-data /usr/bin/php admin/cli/maintenance.php
+\$ sudo -u www-data /usr/bin/php admin/cli/maintenance.php
 "; //TODO: localize - to be translated later when everything is finished
 
     echo $help;
@@ -59,18 +61,52 @@ Example:
 
 cli_heading(get_string('sitemaintenancemode', 'admin')." ($CFG->wwwroot)");
 
-if ($options['enable']) {
+if ($options['enablelater']) {
+    if (file_exists("$CFG->dataroot/climaintenance.html")) {
+        // Already enabled, sorry.
+        echo get_string('clistatusenabled', 'admin')."\n";
+        return 1;
+    }
+
+    $time = time() + ($options['enablelater']*60);
+    set_config('maintenance_later', $time);
+
+    echo get_string('clistatusenabledlater', 'admin', userdate($time))."\n";
+    return 0;
+
+} else if ($options['enable']) {
+    if (file_exists("$CFG->dataroot/climaintenance.html")) {
+        // The maintenance is already enabled, nothing to do.
+    } else {
+        enable_cli_maintenance_mode();
+    }
+    set_config('maintenance_enabled', 0);
+    unset_config('maintenance_later');
+    echo get_string('sitemaintenanceoncli', 'admin')."\n";
+    exit(0);
+
+} else if ($options['enableold']) {
     set_config('maintenance_enabled', 1);
+    unset_config('maintenance_later');
     echo get_string('sitemaintenanceon', 'admin')."\n";
     exit(0);
+
 } else if ($options['disable']) {
     set_config('maintenance_enabled', 0);
+    unset_config('maintenance_later');
+    if (file_exists("$CFG->dataroot/climaintenance.html")) {
+        unlink("$CFG->dataroot/climaintenance.html");
+    }
     echo get_string('sitemaintenanceoff', 'admin')."\n";
     exit(0);
 }
 
-if (!empty($CFG->maintenance_enabled)) {
+if (!empty($CFG->maintenance_enabled) or file_exists("$CFG->dataroot/climaintenance.html")) {
     echo get_string('clistatusenabled', 'admin')."\n";
+
+} else if (isset($CFG->maintenance_later)) {
+    echo get_string('clistatusenabledlater', 'admin', userdate($CFG->maintenance_later))."\n";
+
 } else {
     echo get_string('clistatusdisabled', 'admin')."\n";
 }
index 64589cf..0dbb415 100644 (file)
     $table = new html_table();
     $table->head  = array(get_string('filter'), get_string('isactive', 'filters'),
             get_string('order'), get_string('applyto', 'filters'), get_string('settings'), get_string('delete'));
-    $table->align = array('left', 'left', 'center', 'left', 'left');
-    $table->width = '100%';
+    $table->colclasses = array ('leftalign', 'leftalign', 'centeralign', 'leftalign', 'leftalign', 'leftalign');
+    $table->attributes['class'] = 'admintable generaltable';
+    $table->id = 'filterssetting';
     $table->data  = array();
 
     $lastactive = null;
index 9146c82..cd2f26e 100644 (file)
@@ -77,7 +77,7 @@ $table->define_columns(array('name', 'version', 'delete'));
 $table->define_headers(array(get_string('plugin'), get_string('version'), get_string('delete')));
 $table->define_baseurl($PAGE->url);
 $table->set_attribute('id', 'localplugins');
-$table->set_attribute('class', 'generaltable generalbox boxaligncenter boxwidthwide');
+$table->set_attribute('class', 'admintable generaltable');
 $table->setup();
 
 $plugins = array();
index d81e8a9..fb4e2c4 100644 (file)
@@ -85,7 +85,7 @@
     echo $OUTPUT->header();
 ?>
 <form method="post" action="index.php">
-    <table align="center" width="635" class="generalbox" border="0" cellpadding="5" cellspacing="0">
+    <table align="center" width="635" class="generaltable" border="0" cellpadding="5" cellspacing="0">
         <tr>
             <td  class="generalboxcontent">
             <table cellpadding="9" cellspacing="0" >
     </table>
 </form>
 <form method="post" action="index.php">
-    <table align="center" width="635" class="generalbox" border="0" cellpadding="5" cellspacing="0">
+    <table align="center" width="635" class="generaltable" border="0" cellpadding="5" cellspacing="0">
         <tr>
             <td  class="generalboxcontent">
             <table cellpadding="9" cellspacing="0" >
index 4a99a29..c6738df 100644 (file)
@@ -28,8 +28,8 @@ require_once(dirname(dirname(__FILE__)) . '/config.php');
 require_once($CFG->libdir . '/adminlib.php');
 require_once($CFG->libdir . '/pluginlib.php');
 
-require_capability('moodle/site:config', context_system::instance());
 admin_externalpage_setup('pluginsoverview');
+require_capability('moodle/site:config', context_system::instance());
 
 $fetchremote = optional_param('fetchremote', false, PARAM_BOOL);
 $updatesonly = optional_param('updatesonly', false, PARAM_BOOL);
index 1b35c43..e12d3cc 100644 (file)
@@ -195,7 +195,7 @@ $table->define_headers(array(get_string('questiontype', 'question'), get_string(
         get_string('version'), get_string('requires', 'admin'), get_string('availableq', 'question'),
         get_string('delete'), get_string('settings')));
 $table->set_attribute('id', 'qtypes');
-$table->set_attribute('class', 'generaltable generalbox boxaligncenter boxwidthwide');
+$table->set_attribute('class', 'admintable generaltable');
 $table->setup();
 
 // Add a row for each question type.
index 8d49636..b39976d 100644 (file)
@@ -1245,10 +1245,9 @@ class core_admin_renderer extends plugin_renderer_base {
             get_string('report'),
             get_string('status'),
         );
-        $servertable->align = array('center', 'center', 'left', 'center');
-        $servertable->wrap  = array('nowrap', '', '', 'nowrap');
-        $servertable->size  = array('10', 10, '100%', '10');
-        $servertable->attributes['class'] = 'environmenttable generaltable';
+        $servertable->colclasses = array('centeralign name', 'centeralign status', 'leftalign report', 'centeralign info');
+        $servertable->attributes['class'] = 'admintable environmenttable generaltable';
+        $servertable->id = 'serverstatus';
 
         $serverdata = array('ok'=>array(), 'warn'=>array(), 'error'=>array());
 
@@ -1258,10 +1257,9 @@ class core_admin_renderer extends plugin_renderer_base {
             get_string('report'),
             get_string('status'),
         );
-        $othertable->align = array('center', 'left', 'center');
-        $othertable->wrap  = array('', '', 'nowrap');
-        $othertable->size  = array(10, '100%', '10');
-        $othertable->attributes['class'] = 'environmenttable generaltable';
+        $othertable->colclasses = array('aligncenter info', 'alignleft report', 'aligncenter status');
+        $othertable->attributes['class'] = 'admintable environmenttable generaltable';
+        $othertable->id = 'otherserverstatus';
 
         $otherdata = array('ok'=>array(), 'warn'=>array(), 'error'=>array());
 
index 3eb48b0..a4cdd22 100644 (file)
@@ -281,8 +281,11 @@ if (($action == 'edit') || ($action == 'new')) {
     // Table to list plug-ins
     $table = new html_table();
     $table->head = array(get_string('name'), get_string('isactive', 'repository'), get_string('order'), $settingsstr);
-    $table->align = array('left', 'center', 'center', 'center', 'center');
+
+    $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
+    $table->id = 'repositoriessetting';
     $table->data = array();
+    $table->attributes['class'] = 'admintable generaltable';
 
     // Get list of used plug-ins
     $instances = repository::get_types();
index 45ea5f8..4b7cef8 100644 (file)
@@ -189,7 +189,7 @@ $assignurl = new moodle_url($PAGE->url, array('roleid'=>$roleid));
 <form id="assignform" method="post" action="<?php echo $assignurl ?>"><div>
   <input type="hidden" name="sesskey" value="<?php echo sesskey() ?>" />
 
-  <table summary="" class="roleassigntable generaltable generalbox boxaligncenter" cellspacing="0">
+  <table id="assigningrole" summary="" class="admintable roleassigntable generaltable" cellspacing="0">
     <tr>
       <td id="existingcell">
           <p><label for="removeselect"><?php print_string('extusers', 'role'); ?></label></p>
@@ -278,15 +278,13 @@ $assignurl = new moodle_url($PAGE->url, array('roleid'=>$roleid));
 
     // Print overview table
     $table = new html_table();
-    $table->tablealign = 'center';
-    $table->width = '60%';
+    $table->id = 'assignrole';
     $table->head = array(get_string('role'), get_string('description'), get_string('userswiththisrole', 'role'));
-    $table->wrap = array('nowrap', '', 'nowrap');
-    $table->align = array('left', 'left', 'center');
+    $table->colclasses = array('leftalign role', 'leftalign', 'centeralign userrole');
+    $table->attributes['class'] = 'admintable generaltable';
     if ($showroleholders) {
         $table->headspan = array(1, 1, 2);
-        $table->wrap[] = 'nowrap';
-        $table->align[] = 'left';
+        $table->colclasses[] = 'leftalign roleholder';
     }
 
     foreach ($assignableroles as $roleid => $rolename) {
index 60acdf9..45dccf6 100644 (file)
@@ -661,7 +661,7 @@ class define_role_table_advanced extends capability_table_with_risks {
     public function make_copy() {
         $this->roleid = 0;
         unset($this->role->id);
-        $this->role->name .= ' ' . get_string('copyasnoun');
+        $this->role->name = role_get_name($this->role, null, ROLENAME_ORIGINAL) . ' ' . get_string('copyasnoun');
         $this->role->shortname .= 'copy';
     }
 
@@ -738,6 +738,56 @@ class define_role_table_advanced extends capability_table_with_risks {
         return $output;
     }
 
+    /**
+     * Returns an array of roles of the allowed type.
+     *
+     * @param string $type Must be one of: assign, switch, or override.
+     * @return array
+     */
+    protected function get_allow_roles_list($type) {
+        global $DB;
+
+        if ($type !== 'assign' and $type !== 'switch' and $type !== 'override') {
+            debugging('Invalid role allowed type specified', DEBUG_DEVELOPER);
+            return array();
+        }
+
+        if (empty($this->roleid)) {
+            return array();
+        }
+
+        $sql = "SELECT r.*
+                  FROM {role} r
+                  JOIN {role_allow_{$type}} a ON a.allow{$type} = r.id
+                 WHERE a.roleid = :roleid
+              ORDER BY r.sortorder ASC";
+        return $DB->get_records_sql($sql, array('roleid'=>$this->roleid));
+    }
+
+    /**
+     * Returns an array of roles with the allowed type.
+     *
+     * @param string $type Must be one of: assign, switch, or override.
+     * @return array Am array of role names with the allowed type
+     */
+    protected function get_allow_role_control($type) {
+        if ($roles = $this->get_allow_roles_list($type)) {
+            $roles = role_fix_names($roles, null, ROLENAME_ORIGINAL, true);
+            return implode(', ', $roles);
+        } else {
+            return get_string('none');
+        }
+    }
+
+    /**
+     * Returns information about the risks associated with a role.
+     *
+     * @return string
+     */
+    protected function get_role_risks_info() {
+        return '';
+    }
+
     protected function print_field($name, $caption, $field) {
         global $OUTPUT;
         // Attempt to generate HTML like formslib.
@@ -781,6 +831,12 @@ class define_role_table_advanced extends capability_table_with_risks {
         $this->print_field('edit-description', get_string('customroledescription', 'role').'&nbsp;'.$OUTPUT->help_icon('customroledescription', 'role'), $this->get_description_field('description'));
         $this->print_field('menuarchetype', get_string('archetype', 'role').'&nbsp;'.$OUTPUT->help_icon('archetype', 'role'), $this->get_archetype_field('archetype'));
         $this->print_field('', get_string('maybeassignedin', 'role'), $this->get_assignable_levels_control());
+        $this->print_field('', get_string('allowassign', 'role'), $this->get_allow_role_control('assign'));
+        $this->print_field('', get_string('allowoverride', 'role'), $this->get_allow_role_control('override'));
+        $this->print_field('', get_string('allowswitch', 'role'), $this->get_allow_role_control('switch'));
+        if ($risks = $this->get_role_risks_info()) {
+            $this->print_field('', get_string('rolerisks', 'role'), $risks);
+        }
         echo "</div>";
 
         $this->print_show_hide_advanced_button();
@@ -882,6 +938,57 @@ class view_role_definition_table extends define_role_table_advanced {
         // Do nothing.
     }
 
+    /**
+     * Returns HTML risk icons.
+     *
+     * @return string
+     */
+    protected function get_role_risks_info() {
+        global $OUTPUT;
+
+        if (empty($this->roleid)) {
+            return '';
+        }
+
+        $risks = array();
+        $allrisks = get_all_risks();
+        foreach ($this->capabilities as $capability) {
+            $perm = $this->permissions[$capability->name];
+            if ($perm != CAP_ALLOW) {
+                continue;
+            }
+            foreach ($allrisks as $type=>$risk) {
+                if ($risk & (int)$capability->riskbitmask) {
+                    $risks[$type] = $risk;
+                }
+            }
+        }
+
+        $risksurl = new moodle_url(get_docs_url(s(get_string('risks', 'role'))));
+        foreach ($risks as $type=>$risk) {
+            $pixicon = new pix_icon('/i/' . str_replace('risk', 'risk_', $type), get_string($type . 'short', 'admin'));
+            $risks[$type] = $OUTPUT->action_icon($risksurl, $pixicon, new popup_action('click', $risksurl));
+        }
+
+        return implode(' ', $risks);
+    }
+
+    /**
+     * Returns true if the row should be skipped.
+     *
+     * @param string $capability
+     * @return bool
+     */
+    protected function skip_row($capability) {
+        $perm = $this->permissions[$capability->name];
+        if ($perm == CAP_INHERIT) {
+            // Do not print empty rows in role overview, admins need to know quickly what is allowed and prohibited,
+            // if they want to see the list of all capabilities they can go to edit role page.
+            return true;
+        }
+        parent::skip_row($capability);
+    }
+
     protected function add_permission_cells($capability) {
         $perm = $this->permissions[$capability->name];
         $permname = $this->allpermissions[$perm];
index 745681e..c7a4f69 100644 (file)
 
 /// Initialise table.
     $table = new html_table();
-    $table->tablealign = 'center';
-    $table->align = array('left', 'left', 'left', 'left');
-    $table->wrap = array('nowrap', '', 'nowrap','nowrap');
-    $table->width = '90%';
+    $table->colclasses = array('leftalign', 'leftalign', 'leftalign', 'leftalign');
+    $table->id = 'roles';
+    $table->attributes['class'] = 'admintable generaltable';
     $table->head = array(
         get_string('role') . ' ' . $OUTPUT->help_icon('roles', 'role'),
         get_string('description'),
index 99a5eea..da078d7 100644 (file)
@@ -67,7 +67,21 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     }
     $temp->add(new admin_setting_configselect('calendar_maxevents',new lang_string('configmaxevents','admin'),new lang_string('helpupcomingmaxevents', 'admin'),10,$options));
     $temp->add(new admin_setting_configcheckbox('enablecalendarexport', new lang_string('enablecalendarexport', 'admin'), new lang_string('configenablecalendarexport','admin'), 1));
+
+    // Calendar custom export settings.
+    $days = array(365 => new lang_string('numdays', '', 365),
+            180 => new lang_string('numdays', '', 180),
+            150 => new lang_string('numdays', '', 150),
+            120 => new lang_string('numdays', '', 120),
+            90  => new lang_string('numdays', '', 90),
+            60  => new lang_string('numdays', '', 60),
+            30  => new lang_string('numdays', '', 30),
+            5  => new lang_string('numdays', '', 5));
+    $temp->add(new admin_setting_configcheckbox('calendar_customexport', new lang_string('configcalendarcustomexport', 'admin'), new lang_string('helpcalendarcustomexport','admin'), 1));
+    $temp->add(new admin_setting_configselect('calendar_exportlookahead', new lang_string('configexportlookahead','admin'), new lang_string('helpexportlookahead', 'admin'), 365, $days));
+    $temp->add(new admin_setting_configselect('calendar_exportlookback', new lang_string('configexportlookback','admin'), new lang_string('helpexportlookback', 'admin'), 5, $days));
     $temp->add(new admin_setting_configtext('calendar_exportsalt', new lang_string('calendarexportsalt','admin'), new lang_string('configcalendarexportsalt', 'admin'), random_string(60)));
+    $temp->add(new admin_setting_configcheckbox('calendar_showicalsource', new lang_string('configshowicalsource', 'admin'), new lang_string('helpshowicalsource','admin'), 1));
     $ADMIN->add('appearance', $temp);
 
     // blog
index b7fa57e..f2d6f58 100644 (file)
@@ -316,6 +316,7 @@ if ($hassiteconfig || has_capability('moodle/question:config', $systemcontext))
         require_once("$CFG->libdir/pluginlib.php");
         $allplugins = plugin_manager::instance()->get_plugins();
     }
+
     // Question behaviour settings.
     $ADMIN->add('modules', new admin_category('qbehavioursettings', new lang_string('questionbehaviours', 'admin')));
     $ADMIN->add('qbehavioursettings', new admin_page_manageqbehaviours());
@@ -323,6 +324,54 @@ if ($hassiteconfig || has_capability('moodle/question:config', $systemcontext))
     // Question type settings.
     $ADMIN->add('modules', new admin_category('qtypesettings', new lang_string('questiontypes', 'admin')));
     $ADMIN->add('qtypesettings', new admin_page_manageqtypes());
+
+    // Question preview defaults.
+    $settings = new admin_settingpage('qdefaultsetting',
+            get_string('questionpreviewdefaults', 'question'),
+            'moodle/question:config');
+    $ADMIN->add('qtypesettings', $settings);
+
+    $settings->add(new admin_setting_heading('qdefaultsetting_preview_options',
+            '', get_string('questionpreviewdefaults_desc', 'question')));
+
+    // These keys are question_display_options::HIDDEN and VISIBLE.
+    $hiddenofvisible = array(
+        0 => get_string('notshown', 'question'),
+        1 => get_string('shown', 'question'),
+    );
+
+    $settings->add(new admin_setting_question_behaviour('question_preview/behaviour',
+            get_string('howquestionsbehave', 'question'), '',
+                    'deferredfeedback'));
+
+    $settings->add(new admin_setting_configselect('question_preview/correctness',
+            get_string('whethercorrect', 'question'), '', 1, $hiddenofvisible));
+
+    // These keys are question_display_options::HIDDEN, MARK_ONLY and MARK_AND_MAX.
+    $marksoptions = array(
+        0 => get_string('notshown', 'question'),
+        1 => get_string('showmaxmarkonly', 'question'),
+        2 => get_string('showmarkandmax', 'question'),
+    );
+    $settings->add(new admin_setting_configselect('question_preview/marks',
+            get_string('marks', 'question'), '', 1, $marksoptions));
+
+    $settings->add(new admin_setting_configselect('question_preview/markdp',
+            get_string('decimalplacesingrades', 'question'), '', 2, array(0, 1, 2, 3, 4, 5, 6, 7)));
+
+    $settings->add(new admin_setting_configselect('question_preview/feedback',
+            get_string('specificfeedback', 'question'), '', 1, $hiddenofvisible));
+
+    $settings->add(new admin_setting_configselect('question_preview/generalfeedback',
+            get_string('generalfeedback', 'question'), '', 1, $hiddenofvisible));
+
+    $settings->add(new admin_setting_configselect('question_preview/rightanswer',
+            get_string('rightanswer', 'question'), '', 1, $hiddenofvisible));
+
+    $settings->add(new admin_setting_configselect('question_preview/history',
+            get_string('responsehistory', 'question'), '', 0, $hiddenofvisible));
+
+    // Settings for particular question types.
     foreach ($allplugins['qtype'] as $qtype) {
         $qtype->load_settings($ADMIN, 'qtypesettings', $hassiteconfig);
     }
diff --git a/admin/tool/behat/cli/util.php b/admin/tool/behat/cli/util.php
new file mode 100644 (file)
index 0000000..4fd147f
--- /dev/null
@@ -0,0 +1,182 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * CLI tool with utilities to manage Behat integration in Moodle
+ *
+ * All CLI utilities uses $CFG->behat_dataroot and $CFG->prefix_dataroot as
+ * $CFG->dataroot and $CFG->prefix
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+if (isset($_SERVER['REMOTE_ADDR'])) {
+    die(); // No access from web!.
+}
+
+// Basic functions.
+require_once(__DIR__ . '/../../../../lib/clilib.php');
+require_once(__DIR__ . '/../../../../lib/behat/lib.php');
+
+
+// CLI options.
+list($options, $unrecognized) = cli_get_params(
+    array(
+        'help'    => false,
+        'install' => false,
+        'drop'    => false,
+        'enable'  => false,
+        'disable' => false,
+    ),
+    array(
+        'h' => 'help'
+    )
+);
+
+
+// Checking util.php CLI script usage.
+$help = "
+Behat utilities to manage the test environment
+
+Options:
+--install  Installs the test environment for acceptance tests
+--drop     Drops the database tables and the dataroot contents
+--enable   Enables test environment and updates tests list
+--disable  Disables test environment
+
+-h, --help     Print out this help
+
+Example from Moodle root directory:
+\$ php admin/tool/behat/cli/util.php --enable
+
+More info in http://docs.moodle.org/dev/Acceptance_testing#Running_tests
+";
+
+if (!empty($options['help'])) {
+    echo $help;
+    exit(0);
+}
+
+
+// Checking $CFG->behat_* vars and values.
+define('BEHAT_UTIL', true);
+define('CLI_SCRIPT', true);
+define('ABORT_AFTER_CONFIG', true);
+define('NO_OUTPUT_BUFFERING', true);
+
+error_reporting(E_ALL | E_STRICT);
+ini_set('display_errors', '1');
+ini_set('log_errors', '1');
+
+require_once(__DIR__ . '/../../../../config.php');
+
+// CFG->behat_prefix must be set and with value different than CFG->prefix and phpunit_prefix.
+if (!isset($CFG->behat_prefix) ||
+   (isset($CFG->behat_prefix) &&
+       ($CFG->behat_prefix == $CFG->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 (!isset($CFG->behat_dataroot) ||
+   (isset($CFG->behat_dataroot) &&
+       ($CFG->behat_dataroot == $CFG->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');
+}
+
+// Create behat_dataroot if it doesn't exists.
+if (!file_exists($CFG->behat_dataroot)) {
+    if (!mkdir($CFG->behat_dataroot, $CFG->directorypermissions)) {
+        behat_error(BEHAT_EXITCODE_PERMISSIONS, '$CFG->behat_dataroot directory can not be created');
+    }
+}
+if (!is_dir($CFG->behat_dataroot) || !is_writable($CFG->behat_dataroot)) {
+    behat_error(BEHAT_EXITCODE_PERMISSIONS, '$CFG->behat_dataroot directory has no permissions or is not a directory');
+}
+
+// Check that the directory does not contains other things.
+if (!file_exists("$CFG->behat_dataroot/behattestdir.txt")) {
+    if ($dh = opendir($CFG->behat_dataroot)) {
+        while (($file = readdir($dh)) !== false) {
+            if ($file === 'behat' or $file === '.' or $file === '..' or $file === '.DS_Store') {
+                continue;
+            }
+            behat_error(BEHAT_EXITCODE_CONFIG, '$CFG->behat_dataroot directory is not empty, ensure this is the directory where you want to install behat test dataroot');
+        }
+        closedir($dh);
+        unset($dh);
+        unset($file);
+    }
+
+    // Now we create dataroot directory structure for behat tests.
+    testing_initdataroot($CFG->behat_dataroot, 'behat');
+}
+
+// Overrides vars with behat-test ones.
+$vars = array('wwwroot', 'prefix', 'dataroot');
+foreach ($vars as $var) {
+    $CFG->{$var} = $CFG->{'behat_' . $var};
+}
+
+$CFG->noemailever = true;
+$CFG->passwordsaltmain = 'moodle';
+
+// Continues setup.
+define('ABORT_AFTER_CONFIG_CANCEL', true);
+require("$CFG->dirroot/lib/setup.php");
+
+require_once($CFG->libdir.'/adminlib.php');
+require_once($CFG->libdir.'/upgradelib.php');
+require_once($CFG->libdir.'/clilib.php');
+require_once($CFG->libdir.'/pluginlib.php');
+require_once($CFG->libdir.'/installlib.php');
+
+if ($unrecognized) {
+    $unrecognized = implode("\n  ", $unrecognized);
+    cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
+}
+
+// Behat utilities.
+require_once($CFG->libdir . '/behat/classes/util.php');
+require_once($CFG->libdir . '/behat/classes/behat_command.php');
+
+// Run command (only one per time).
+if ($options['install']) {
+    behat_util::install_site();
+    mtrace("Acceptance tests site installed");
+} else if ($options['drop']) {
+    behat_util::drop_site();
+    mtrace("Acceptance tests site dropped");
+} else if ($options['enable']) {
+    behat_util::start_test_mode();
+    $runtestscommand = behat_command::get_behat_command() . ' --config '
+        . $CFG->behat_dataroot . DIRECTORY_SEPARATOR . 'behat' . DIRECTORY_SEPARATOR . 'behat.yml';
+    mtrace("Acceptance tests environment enabled, to run the tests use:\n " . $runtestscommand);
+} else if ($options['disable']) {
+    behat_util::stop_test_mode();
+    mtrace("Acceptance tests environment disabled");
+} else {
+    echo $help;
+}
+
+exit(0);
diff --git a/admin/tool/behat/index.php b/admin/tool/behat/index.php
new file mode 100644 (file)
index 0000000..f68ec13
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Web interface to list and filter steps
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require(__DIR__ . '/../../../config.php');
+require_once($CFG->libdir.'/adminlib.php');
+require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/behat/locallib.php');
+require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
+
+$filter = optional_param('filter', '', PARAM_ALPHANUMEXT);
+$type = optional_param('type', false, PARAM_ALPHAEXT);
+$component = optional_param('component', '', PARAM_ALPHAEXT);
+
+admin_externalpage_setup('toolbehat');
+
+// Getting available steps definitions from behat.
+$steps = tool_behat::stepsdefinitions($type, $component, $filter);
+
+// Form.
+$componentswithsteps = array('' => get_string('allavailablesteps', 'tool_behat'));
+
+// Complete the components list with the moodle steps definitions.
+$components = behat_config_manager::get_components_steps_definitions();
+if ($components) {
+    foreach ($components as $component => $filepath) {
+        // TODO Use a class static attribute instead of the class name.
+        $componentswithsteps[$component] = 'Moodle ' . substr($component, 6);
+    }
+}
+$form = new steps_definitions_form(null, array('components' => $componentswithsteps));
+
+// Output contents.
+$renderer = $PAGE->get_renderer('tool_behat');
+echo $renderer->render_stepsdefinitions($steps, $form);
+
diff --git a/admin/tool/behat/lang/en/tool_behat.php b/admin/tool/behat/lang/en/tool_behat.php
new file mode 100644 (file)
index 0000000..8bb1f1d
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for tool_behat
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['allavailablesteps'] = 'All the available steps definitions';
+$string['giveninfo'] = 'Given. Processes to set up the environment';
+$string['installinfo'] = 'Read {$a} for installation and tests execution info';
+$string['moreinfoin'] = 'More info in {$a}';
+$string['newstepsinfo'] = 'Read {$a} for info about how to add new steps definitions';
+$string['newtestsinfo'] = 'Read {$a} for info about how to write new tests';
+$string['nostepsdefinitions'] = 'There aren\'t steps definitions matching this filters';
+$string['pluginname'] = 'Acceptance testing';
+$string['runclitool'] = 'To list the steps definitions you need to run the Behat CLI tool to create the $CFG->behat_dataroot directory. Go to your moodle dirroot and run "{$a}"';
+$string['stepsdefinitionscomponent'] = 'Area';
+$string['stepsdefinitionscontains'] = 'Contains';
+$string['stepsdefinitionsfilters'] = 'Steps definitions';
+$string['stepsdefinitionstype'] = 'Type';
+$string['theninfo'] = 'Then. Checkings to ensure the outcomes are the expected ones';
+$string['viewsteps'] = 'Filter';
+$string['wheninfo'] = 'When. Actions that provokes an event';
+$string['wrongbehatsetup'] = 'Something is wrong with the setup, ensure you ran the composer installer and vendor/bin/behat file has execution permissions';
diff --git a/admin/tool/behat/locallib.php b/admin/tool/behat/locallib.php
new file mode 100644 (file)
index 0000000..33a5fd8
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Behat commands
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->libdir . '/behat/classes/behat_command.php');
+require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
+require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/behat/steps_definitions_form.php');
+
+/**
+ * Behat commands manager
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class tool_behat {
+
+    /**
+     * Lists the available steps definitions
+     *
+     * @param string $type
+     * @param string $component
+     * @param string $filter
+     * @return string
+     */
+    public static function stepsdefinitions($type, $component, $filter) {
+
+        // We don't require the test environment to be enabled to list the steps definitions
+        // so test writers can more easily set up the environment.
+        behat_command::check_behat_setup();
+
+        // The loaded steps depends on the component specified.
+        behat_config_manager::update_config_file($component, false);
+
+        // The Moodle\BehatExtension\HelpPrinter\MoodleDefinitionsPrinter will parse this search format.
+        if ($type) {
+            $filter .= '&&' . $type;
+        }
+
+        if ($filter) {
+            $filteroption = ' -d "' . $filter . '"';
+        } else {
+            $filteroption = ' -di';
+        }
+
+        // Get steps definitions from Behat.
+        $options = ' --config="'.behat_config_manager::get_steps_list_config_filepath(). '" '.$filteroption;
+        list($steps, $code) = behat_command::run($options);
+
+        if ($steps) {
+            $stepshtml = implode('', $steps);
+        }
+
+        if (empty($stepshtml)) {
+            $stepshtml = get_string('nostepsdefinitions', 'tool_behat');
+        }
+
+        return $stepshtml;
+    }
+
+}
diff --git a/admin/tool/behat/renderer.php b/admin/tool/behat/renderer.php
new file mode 100644 (file)
index 0000000..1a70fce
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Behat tool renderer
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->libdir . '/behat/classes/behat_command.php');
+
+/**
+ * Renderer for behat tool web features
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class tool_behat_renderer extends plugin_renderer_base {
+
+    /**
+     * Renders the list of available steps according to the submitted filters
+     *
+     * @param string     $stepsdefinitions HTML from behat with the available steps
+     * @param moodleform $form
+     * @return string HTML code
+     */
+    public function render_stepsdefinitions($stepsdefinitions, $form) {
+
+        $title = get_string('pluginname', 'tool_behat');
+
+        // Header.
+        $html = $this->output->header();
+        $html .= $this->output->heading($title);
+
+        // Info.
+        $installurl = behat_command::DOCS_URL . '#Installation';
+        $installlink = html_writer::tag('a', $installurl, array('href' => $installurl, 'target' => '_blank'));
+        $writetestsurl = behat_command::DOCS_URL . '#Writting_features';
+        $writetestslink = html_writer::tag('a', $writetestsurl, array('href' => $writetestsurl, 'target' => '_blank'));
+        $writestepsurl = behat_command::DOCS_URL . '#Adding_steps_definitions';
+        $writestepslink = html_writer::tag('a', $writestepsurl, array('href' => $writestepsurl, 'target' => '_blank'));
+        $infos = array(
+            get_string('installinfo', 'tool_behat', $installlink),
+            get_string('newtestsinfo', 'tool_behat', $writetestslink),
+            get_string('newstepsinfo', 'tool_behat', $writestepslink)
+        );
+
+        // List of steps
+        $html .= $this->output->box_start();
+        $html .= html_writer::tag('h1', 'Info');
+        $html .= html_writer::empty_tag('div');
+        $html .= html_writer::empty_tag('ul');
+        $html .= html_writer::empty_tag('li');
+        $html .= implode(html_writer::end_tag('li') . html_writer::empty_tag('li'), $infos);
+        $html .= html_writer::end_tag('li');
+        $html .= html_writer::end_tag('ul');
+        $html .= html_writer::end_tag('div');
+        $html .= $this->output->box_end();
+
+        // Form.
+        ob_start();
+        $form->display();
+        $html .= ob_get_contents();
+        ob_end_clean();
+
+        // Steps definitions.
+        $html .= html_writer::tag('div', $stepsdefinitions, array('class' => 'steps-definitions'));
+
+        $html .= $this->output->footer();
+
+        return $html;
+    }
+}
diff --git a/admin/tool/behat/settings.php b/admin/tool/behat/settings.php
new file mode 100644 (file)
index 0000000..7f4b5a0
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Adds behat tests link in admin tree
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+defined('MOODLE_INTERNAL') || die();
+
+if ($hassiteconfig) {
+    $url = $CFG->wwwroot . '/' . $CFG->admin . '/tool/behat/index.php';
+    $ADMIN->add('development', new admin_externalpage('toolbehat', get_string('pluginname', 'tool_behat'), $url));
+}
diff --git a/admin/tool/behat/steps_definitions_form.php b/admin/tool/behat/steps_definitions_form.php
new file mode 100644 (file)
index 0000000..c6b06f3
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Steps definitions form
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->libdir.'/formslib.php');
+
+/**
+ * Form to display the available steps definitions
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class steps_definitions_form extends moodleform {
+
+    /**
+     * Form definition
+     * @return void
+     */
+    public function definition() {
+
+        $mform = $this->_form;
+
+        $mform->addElement('header', 'filters', get_string('stepsdefinitionsfilters', 'tool_behat'));
+
+        $types = array(
+            '' => get_string('allavailablesteps', 'tool_behat'),
+            'given' => get_string('giveninfo', 'tool_behat'),
+            'when' => get_string('wheninfo', 'tool_behat'),
+            'then' => get_string('theninfo', 'tool_behat')
+        );
+        $mform->addElement('select', 'type', get_string('stepsdefinitionstype', 'tool_behat'), $types);
+
+        $mform->addElement(
+            'select',
+            'component',
+            get_string('stepsdefinitionscomponent', 'tool_behat'),
+            $this->_customdata['components']
+        );
+
+        $mform->addElement('text', 'filter', get_string('stepsdefinitionscontains', 'tool_behat'));
+
+        $mform->addElement('submit', 'submit', get_string('viewsteps', 'tool_behat'));
+    }
+}
diff --git a/admin/tool/behat/styles.css b/admin/tool/behat/styles.css
new file mode 100644 (file)
index 0000000..d7ca4d1
--- /dev/null
@@ -0,0 +1,5 @@
+.steps-definitions{border-style:solid;border-width:1px;border-color:#BBB;padding:5px;margin:auto;width:50%;}
+.steps-definitions .step{margin: 10px 0px 10px 0px;}
+.steps-definitions .stepdescription{color:#bf8c12;}
+.steps-definitions .steptype{color:#1467a6;margin-right: 5px;}
+.steps-definitions .stepregex{color:#060;}
diff --git a/admin/tool/behat/tests/behat/list_steps.feature b/admin/tool/behat/tests/behat/list_steps.feature
new file mode 100644 (file)
index 0000000..264c754
--- /dev/null
@@ -0,0 +1,31 @@
+@tool_behat
+Feature: List the system steps definitions
+  In order to create new tests
+  As a tests writer
+  I need to list and filter the system steps definitions
+
+  Background:
+    Given I am on homepage
+    And I log in as "admin"
+    And I expand "Site administration" node
+    And I expand "Development" node
+    And  I follow "Acceptance testing"
+
+  @javascript
+  Scenario: Accessing the list
+    Then I should see "Steps definitions"
+    And I should not see "There aren't steps definitions matching this filter"
+
+  @javascript
+  Scenario: Filtering by type
+    Given I select "Then. Checkings to ensure the outcomes are the expected ones" from "Type"
+    When I press "Filter"
+    Then I should see "Checks, that page contains specified text."
+    And I should not see "Opens Moodle homepage."
+
+  @javascript
+  Scenario: Filtering by keyword
+    Given I fill in "Contains" with "homepage"
+    When I press "Filter"
+    Then I should see "Opens Moodle homepage."
+
diff --git a/admin/tool/behat/tests/behat/test_environment.feature b/admin/tool/behat/tests/behat/test_environment.feature
new file mode 100644 (file)
index 0000000..53d9ee8
--- /dev/null
@@ -0,0 +1,9 @@
+@tool_behat
+Feature: Set up the testing environment
+  In order to execute automated acceptance tests
+  As a moodle developer
+  I need to use the test environment instead of the regular environment
+
+  Scenario: Accessing the site
+    When I am on homepage
+    Then I should see "Acceptance test site"
diff --git a/admin/tool/behat/tests/tool_behat_test.php b/admin/tool/behat/tests/tool_behat_test.php
new file mode 100644 (file)
index 0000000..4c9ae8f
--- /dev/null
@@ -0,0 +1,181 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for admin/tool/behat.
+ *
+ * @package   tool_behat
+ * @copyright  2012 David Monllaó
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/' . $CFG->admin .'/tool/behat/locallib.php');
+require_once($CFG->libdir . '/behat/classes/util.php');
+require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
+
+/**
+ * Allows access to internal methods without exposing them.
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class testable_behat_config_manager extends behat_config_manager {
+
+    /**
+     * Allow access to protected method
+     * @see parent::merge_config()
+     * @param mixed $config
+     * @param mixed $localconfig
+     * @return mixed
+     */
+    public static function merge_config($config, $localconfig) {
+        return parent::merge_config($config, $localconfig);
+    }
+
+    /**
+     * Allow access to protected method
+     * @see parent::get_config_file_contents()
+     * @param string $prefix
+     * @param array $features
+     * @param array $stepsdefinitions
+     * @return string
+     */
+    public static function get_config_file_contents($features, $stepsdefinitions) {
+        return parent::get_config_file_contents($features, $stepsdefinitions);
+    }
+}
+
+/**
+ * Tool behat tests.
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class tool_behat_testcase extends advanced_testcase {
+
+    /**
+     * behat_config_manager tests.
+     */
+    public function test_merge_configs() {
+
+        // Simple default config.
+        $array1 = array(
+            'the' => 'same',
+            'simple' => 'value',
+            'array' => array(
+                'one' => 'arrayvalue1',
+                'two' => 'arrayvalue2'
+            )
+        );
+
+        // Simple override.
+        $array2 = array(
+            'simple' => 'OVERRIDDEN1',
+            'array' => array(
+                'one' => 'OVERRIDDEN2'
+            ),
+            'newprofile' => array(
+                'anotherlevel' => array(
+                    'andanotherone' => array(
+                        'list1',
+                        'list2'
+                    )
+                )
+            )
+        );
+
+        $array = testable_behat_config_manager::merge_config($array1, $array2);
+
+        // Overriddes are applied.
+        $this->assertEquals('OVERRIDDEN1', $array['simple']);
+        $this->assertEquals('OVERRIDDEN2', $array['array']['one']);
+
+        // Other values are respected.
+        $this->assertNotEmpty($array['array']['two']);
+
+        // Completely new nodes are added.
+        $this->assertNotEmpty($array['newprofile']);
+        $this->assertNotEmpty($array['newprofile']['anotherlevel']['andanotherone']);
+        $this->assertEquals('list1', $array['newprofile']['anotherlevel']['andanotherone'][0]);
+        $this->assertEquals('list2', $array['newprofile']['anotherlevel']['andanotherone'][1]);
+
+        // Complex override changing vectors to scalars and scalars to vectors.
+        $array2 = array(
+            'simple' => array(
+                'simple' => 'should',
+                'be' => 'overridden',
+                'by' => 'this-array'
+            ),
+            'array' => 'one'
+        );
+
+        $array = testable_behat_config_manager::merge_config($array1, $array2);
+
+        // Overrides applied.
+        $this->assertNotEmpty($array['simple']);
+        $this->assertNotEmpty($array['array']);
+        $this->assertTrue(is_array($array['simple']));
+        $this->assertFalse(is_array($array['array']));
+
+        // Other values are maintained.
+        $this->assertEquals('same', $array['the']);
+    }
+
+    /**
+     * behat_config_manager tests.
+     */
+    public function test_config_file_contents() {
+        global $CFG;
+
+        // Skip tests if behat is not installed.
+        $vendorpath = $CFG->dirroot . '/vendor';
+        if (!file_exists($vendorpath . '/autoload.php') || !is_dir($vendorpath . '/behat')) {
+            $this->markTestSkipped('Behat not installed.');
+        }
+
+        // To avoid user value at config.php level.
+        unset($CFG->behat_config);
+
+        // List.
+        $features = array(
+            'feature1',
+            'feature2',
+            'feature3'
+        );
+
+        // Associative array.
+        $stepsdefinitions = array(
+            'micarro' => '/me/lo/robaron',
+            'anoche' => '/cuando/yo/dormia'
+        );
+
+        $contents = testable_behat_config_manager::get_config_file_contents($features, $stepsdefinitions);
+
+        $this->assertContains('features: ' . $CFG->dirroot . '/lib/behat/features', $contents);
+        $this->assertContains('micarro: /me/lo/robaron', $contents);
+        $this->assertContains('base_url: \'' . $CFG->behat_wwwroot . '\'', $contents);
+        $this->assertContains('class: behat_init_context', $contents);
+        $this->assertContains('- feature1', $contents);
+        $this->assertContains('- feature3', $contents);
+    }
+
+}
+
diff --git a/admin/tool/behat/version.php b/admin/tool/behat/version.php
new file mode 100644 (file)
index 0000000..a5ddb15
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * tool_behat version info
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2012120700;
+$plugin->requires  = 2012120300; // Requires Moodle 2.5.
+$plugin->component = 'tool_behat';
index 4bfcd58..547a8a4 100644 (file)
@@ -60,8 +60,8 @@ class tool_customlang_filter_form extends moodleform {
 
         // Modified only
         $mform->addElement('advcheckbox', 'modified', get_string('filtermodified', 'tool_customlang'));
-        $mform->setType('filtermodified', PARAM_BOOL);
-        $mform->setDefault('filtermodified', 0);
+        $mform->setType('modified', PARAM_BOOL);
+        $mform->setDefault('modified', 0);
 
         // Substring
         $mform->addElement('text', 'substring', get_string('filtersubstring', 'tool_customlang'));
index ca00d56..bf026a4 100644 (file)
@@ -28,6 +28,7 @@ if (isset($_SERVER['REMOTE_ADDR'])) {
 
 require_once(__DIR__.'/../../../../lib/clilib.php');
 require_once(__DIR__.'/../../../../lib/phpunit/bootstraplib.php');
+require_once(__DIR__.'/../../../../lib/testing/lib.php');
 
 echo "Initialising Moodle PHPUnit test environment...\n";
 
index 5cfd128..111be5d 100644 (file)
@@ -30,6 +30,7 @@ if (isset($_SERVER['REMOTE_ADDR'])) {
 
 require_once(__DIR__.'/../../../../lib/clilib.php');
 require_once(__DIR__.'/../../../../lib/phpunit/bootstraplib.php');
+require_once(__DIR__.'/../../../../lib/testing/lib.php');
 
 // now get cli options
 list($options, $unrecognized) = cli_get_params(
@@ -110,7 +111,7 @@ Options:
 -h, --help     Print out this help
 
 Example:
-\$ php ".phpunit_bootstrap_cli_argument_path('/admin/tool/phpunit/cli/util.php')." --install
+\$ php ".testing_cli_argument_path('/admin/tool/phpunit/cli/util.php')." --install
 ";
     echo $help;
     exit(0);
@@ -136,7 +137,7 @@ if ($diag) {
 
 } else if ($drop) {
     // make sure tests do not run in parallel
-    phpunit_util::acquire_test_lock();
+    test_lock::acquire('phpunit');
     phpunit_util::drop_site(true);
     // note: we must stop here because $CFG is messed up and we can not reinstall, sorry
     exit(0);
index 9a6a104..f249f1d 100644 (file)
@@ -94,6 +94,7 @@ $STD_FIELDS = array('id', 'firstname', 'lastname', 'username', 'email',
         'oldusername', // use when renaming users - this is the original username
         'suspended',   // 1 means suspend user account, 0 means activate user account, nothing means keep as is for existing users
         'deleted',     // 1 means delete user
+        'mnethostid',  // Can not be used for adding, updating or deleting of users - only for enrolments, groups, cohorts and suspending.
     );
 
 $PRF_FIELDS = array();
@@ -285,19 +286,58 @@ if ($formdata = $mform2->is_cancelled()) {
             $userserrors++;
             continue;
         }
+
         if ($user->username !== clean_param($user->username, PARAM_USERNAME)) {
             $upt->track('status', get_string('invalidusername', 'error', 'username'), 'error');
             $upt->track('username', $errorstr, 'error');
             $userserrors++;
         }
-        if ($existinguser = $DB->get_record('user', array('username'=>$user->username, 'mnethostid'=>$CFG->mnet_localhost_id))) {
+
+        if (empty($user->mnethostid)) {
+            $user->mnethostid = $CFG->mnet_localhost_id;
+        }
+
+        if ($existinguser = $DB->get_record('user', array('username'=>$user->username, 'mnethostid'=>$user->mnethostid))) {
             $upt->track('id', $existinguser->id, 'normal', false);
         }
 
-        // find out in username incrementing required
-        if ($existinguser and $optype == UU_USER_ADDINC) {
-            $user->username = uu_increment_username($user->username);
-            $existinguser = false;
+        if ($user->mnethostid == $CFG->mnet_localhost_id) {
+            $remoteuser = false;
+
+            // Find out if username incrementing required.
+            if ($existinguser and $optype == UU_USER_ADDINC) {
+                $user->username = uu_increment_username($user->username);
+                $existinguser = false;
+            }
+
+        } else {
+            if (!$existinguser or $optype == UU_USER_ADDINC) {
+                $upt->track('status', get_string('errormnetadd', 'tool_uploaduser'), 'error');
+                $userserrors++;
+                continue;
+            }
+
+            $remoteuser = true;
+
+            // Make sure there are no changes of existing fields except the suspended status.
+            foreach ((array)$existinguser as $k => $v) {
+                if ($k === 'suspended') {
+                    continue;
+                }
+                if (property_exists($user, $k)) {
+                    $user->$k = $v;
+                }
+                if (in_array($k, $upt->columns)) {
+                    if ($k === 'password' or $k === 'oldusername' or $k === 'deleted') {
+                        $upt->track($k, '', 'normal', false);
+                    } else {
+                        $upt->track($k, s($v), 'normal', false);
+                    }
+                }
+            }
+            unset($user->oldusername);
+            unset($user->password);
+            $user->auth = $existinguser->auth;
         }
 
         // notify about nay username changes
@@ -337,7 +377,7 @@ if ($formdata = $mform2->is_cancelled()) {
 
         // delete user
         if (!empty($user->deleted)) {
-            if (!$allowdeletes) {
+            if (!$allowdeletes or $remoteuser) {
                 $usersskipped++;
                 $upt->track('status', $strusernotdeletedoff, 'warning');
                 continue;
@@ -475,7 +515,7 @@ if ($formdata = $mform2->is_cancelled()) {
             $doupdate = false;
             $dologout = false;
 
-            if ($updatetype != UU_UPDATE_NOCHANGES) {
+            if ($updatetype != UU_UPDATE_NOCHANGES and !$remoteuser) {
                 if (!empty($user->auth) and $user->auth !== $existinguser->auth) {
                     $upt->track('auth', s($existinguser->auth).'-->'.s($user->auth), 'info', false);
                     $existinguser->auth = $user->auth;
@@ -527,6 +567,16 @@ if ($formdata = $mform2->is_cancelled()) {
                             }
                         }
 
+                        if ($column === 'lang') {
+                            if (empty($user->lang)) {
+                                // Do not change to not-set value.
+                                continue;
+                            } else if (clean_param($user->lang, PARAM_LANG) === '') {
+                                $upt->track('status', get_string('cannotfindlang', 'error', $user->lang), 'warning');
+                                continue;
+                            }
+                        }
+
                         if (in_array($column, $upt->columns)) {
                             $upt->track($column, s($existinguser->$column).'-->'.s($user->$column), 'info', false);
                         }
@@ -563,7 +613,11 @@ if ($formdata = $mform2->is_cancelled()) {
             // changing of passwords is a special case
             // do not force password changes for external auth plugins!
             $oldpw = $existinguser->password;
-            if (!$isinternalauth) {
+
+            if ($remoteuser) {
+                // Do not mess with passwords of remote users.
+
+            } else if (!$isinternalauth) {
                 $existinguser->password = 'not cached';
                 $upt->track('password', '-', 'normal', false);
                 // clean up prefs
@@ -599,10 +653,13 @@ if ($formdata = $mform2->is_cancelled()) {
 
                 $upt->track('status', $struserupdated);
                 $usersupdated++;
-                // pre-process custom profile menu fields data from csv file
-                $existinguser = uu_pre_process_custom_profile_data($existinguser);
-                // save custom profile fields data from csv file
-                profile_save_data($existinguser);
+
+                if (!$remoteuser) {
+                    // pre-process custom profile menu fields data from csv file
+                    $existinguser = uu_pre_process_custom_profile_data($existinguser);
+                    // save custom profile fields data from csv file
+                    profile_save_data($existinguser);
+                }
 
                 events_trigger('user_updated', $existinguser);
 
@@ -682,6 +739,13 @@ if ($formdata = $mform2->is_cancelled()) {
                 $upt->track('email', get_string('invalidemail'), 'warning');
             }
 
+            if (empty($user->lang)) {
+                $user->lang = '';
+            } else if (clean_param($user->lang, PARAM_LANG) === '') {
+                $upt->track('status', get_string('cannotfindlang', 'error', $user->lang), 'warning');
+                $user->lang = '';
+            }
+
             $forcechangepassword = false;
 
             if ($isinternalauth) {
index 74bb55e..13e5992 100644 (file)
@@ -30,6 +30,7 @@ $string['csvdelimiter'] = 'CSV delimiter';
 $string['defaultvalues'] = 'Default values';
 $string['deleteerrors'] = 'Delete errors';
 $string['encoding'] = 'Encoding';
+$string['errormnetadd'] = 'Can not add remote users';
 $string['errors'] = 'Errors';
 $string['nochanges'] = 'No changes';
 $string['pluginname'] = 'User upload';
index 25e0749..8645f1c 100644 (file)
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012112900; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012120700; // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2012112900; // Requires this Moodle version
 $plugin->component = 'tool_uploaduser'; // Full name of the plugin (used for diagnostics)
 
index 06787a6..2514c61 100644 (file)
@@ -90,7 +90,7 @@ abstract class XMLDBCheckAction extends XMLDBAction {
 
         // If  not confirmed, show confirmation box
         if (!$confirmed) {
-            $o = '<table class="generalbox" border="0" cellpadding="5" cellspacing="0" id="notice">';
+            $o = '<table class="generaltable" border="0" cellpadding="5" cellspacing="0" id="notice">';
             $o.= '  <tr><td class="generalboxcontent">';
             $o.= '    <p class="centerpara">' . $this->str[$this->introstr] . '</p>';
             $o.= '    <table class="boxaligncenter" cellpadding="20"><tr><td>';
index 69bfb84..1118906 100644 (file)
@@ -99,7 +99,7 @@ class check_bigints extends XMLDBCheckAction {
         $dbman = $DB->get_manager();
 
         $s = '';
-        $r = '<table class="generalbox boxaligncenter boxwidthwide" border="0" cellpadding="5" cellspacing="0" id="results">';
+        $r = '<table class="generaltable boxaligncenter boxwidthwide" border="0" cellpadding="5" cellspacing="0" id="results">';
         $r.= '  <tr><td class="generalboxcontent">';
         $r.= '    <h2 class="main">' . $this->str['searchresults'] . '</h2>';
         $r.= '    <p class="centerpara">' . $this->str['wrongints'] . ': ' . count($wrong_fields) . '</p>';
index 15a9365..73306ea 100644 (file)
@@ -111,7 +111,7 @@ class check_defaults extends XMLDBCheckAction {
         $dbman = $DB->get_manager();
 
         $s = '';
-        $r = '<table class="generalbox boxaligncenter boxwidthwide" border="0" cellpadding="5" cellspacing="0" id="results">';
+        $r = '<table class="generaltable boxaligncenter boxwidthwide" border="0" cellpadding="5" cellspacing="0" id="results">';
         $r.= '  <tr><td class="generalboxcontent">';
         $r.= '    <h2 class="main">' . $this->str['searchresults'] . '</h2>';
         $r.= '    <p class="centerpara">' . $this->str['wrongdefaults'] . ': ' . count($wrong_fields) . '</p>';
index cd897d4..67e886f 100644 (file)
@@ -130,7 +130,7 @@ class check_foreign_keys extends XMLDBCheckAction {
     }
 
     protected function display_results(array $violatedkeys) {
-        $r = '<table class="generalbox boxaligncenter boxwidthwide" border="0" cellpadding="5" cellspacing="0" id="results">';
+        $r = '<table class="generaltable boxaligncenter boxwidthwide" border="0" cellpadding="5" cellspacing="0" id="results">';
         $r.= '  <tr><td class="generalboxcontent">';
         $r.= '    <h2 class="main">' . $this->str['searchresults'] . '</h2>';
         $r.= '    <p class="centerpara">' . $this->str['violatedforeignkeys'] . ': ' . count($violatedkeys) . '</p>';
index dc6ec90..ba03bac 100644 (file)
@@ -130,7 +130,7 @@ class check_indexes extends XMLDBCheckAction {
         $dbman = $DB->get_manager();
 
         $s = '';
-        $r = '<table class="generalbox boxaligncenter boxwidthwide" border="0" cellpadding="5" cellspacing="0" id="results">';
+        $r = '<table class="generaltable boxaligncenter boxwidthwide" border="0" cellpadding="5" cellspacing="0" id="results">';
         $r.= '  <tr><td class="generalboxcontent">';
         $r.= '    <h2 class="main">' . $this->str['searchresults'] . '</h2>';
         $r.= '    <p class="centerpara">' . $this->str['missingindexes'] . ': ' . count($missing_indexes) . '</p>';
index f7488c1..8041672 100644 (file)
@@ -110,7 +110,7 @@ class check_oracle_semantics extends XMLDBCheckAction {
         $dbman = $DB->get_manager();
 
         $s = '';
-        $r = '<table class="generalbox boxaligncenter boxwidthwide" border="0" cellpadding="5" cellspacing="0" id="results">';
+        $r = '<table class="generaltable boxaligncenter boxwidthwide" border="0" cellpadding="5" cellspacing="0" id="results">';
         $r.= '  <tr><td class="generalboxcontent">';
         $r.= '    <h2 class="main">' . $this->str['searchresults'] . '</h2>';
         $r.= '    <p class="centerpara">' . $this->str['wrongoraclesemantics'] . ': ' . count($wrong_fields) . '</p>';
index 1d8d414..66096f4 100644 (file)
@@ -73,7 +73,7 @@ class delete_field extends XMLDBAction {
 
         // If  not confirmed, show confirmation box
         if (!$confirmed) {
-            $o = '<table width="60" class="generalbox" border="0" cellpadding="5" cellspacing="0" id="notice">';
+            $o = '<table width="60" class="generaltable" border="0" cellpadding="5" cellspacing="0" id="notice">';
             $o.= '  <tr><td class="generalboxcontent">';
             $o.= '    <p class="centerpara">' . $this->str['confirmdeletefield'] . '<br /><br />' . $fieldparam . '</p>';
             $o.= '    <table class="boxaligncenter" cellpadding="20"><tr><td>';
index 7dadedc..ad6f801 100644 (file)
@@ -73,7 +73,7 @@ class delete_index extends XMLDBAction {
 
         // If  not confirmed, show confirmation box
         if (!$confirmed) {
-            $o = '<table width="60" class="generalbox" border="0" cellpadding="5" cellspacing="0" id="notice">';
+            $o = '<table width="60" class="generaltable" border="0" cellpadding="5" cellspacing="0" id="notice">';
             $o.= '  <tr><td class="generalboxcontent">';
             $o.= '    <p class="centerpara">' . $this->str['confirmdeleteindex'] . '<br /><br />' . $indexparam . '</p>';
             $o.= '    <table class="boxaligncenter" cellpadding="20"><tr><td>';
index 3c1b232..ea55010 100644 (file)
@@ -73,7 +73,7 @@ class delete_key extends XMLDBAction {
 
         // If  not confirmed, show confirmation box
         if (!$confirmed) {
-            $o = '<table width="60" class="generalbox" border="0" cellpadding="5" cellspacing="0" id="notice">';
+            $o = '<table width="60" class="generaltable" border="0" cellpadding="5" cellspacing="0" id="notice">';
             $o.= '  <tr><td class="generalboxcontent">';
             $o.= '    <p class="centerpara">' . $this->str['confirmdeletekey'] . '<br /><br />' . $keyparam . '</p>';
             $o.= '    <table class="boxaligncenter" cellpadding="20"><tr><td>';
index 9d32eec..e577b96 100644 (file)
@@ -72,7 +72,7 @@ class delete_table extends XMLDBAction {
 
         // If  not confirmed, show confirmation box
         if (!$confirmed) {
-            $o = '<table width="60" class="generalbox" border="0" cellpadding="5" cellspacing="0" id="notice">';
+            $o = '<table width="60" class="generaltable" border="0" cellpadding="5" cellspacing="0" id="notice">';
             $o.= '  <tr><td class="generalboxcontent">';
             $o.= '    <p class="centerpara">' . $this->str['confirmdeletetable'] . '<br /><br />' . $tableparam . '</p>';
             $o.= '    <table class="boxaligncenter" cellpadding="20"><tr><td>';
index 02a2bc4..05cdd79 100644 (file)
@@ -71,7 +71,7 @@ class delete_xml_file extends XMLDBAction {
 
         // If  not confirmed, show confirmation box
         if (!$confirmed) {
-            $o = '<table width="60" class="generalbox" border="0" cellpadding="5" cellspacing="0" id="notice">';
+            $o = '<table width="60" class="generaltable" border="0" cellpadding="5" cellspacing="0" id="notice">';
             $o.= '  <tr><td class="generalboxcontent">';
             $o.= '    <p class="centerpara">' . $this->str['confirmdeletexmlfile'] . '<br /><br />' . $dirpath . '/install.php</p>';
             $o.= '    <table class="boxaligncenter" cellpadding="20"><tr><td>';
index 9d4e002..5ac58fc 100644 (file)
@@ -120,7 +120,7 @@ class main_view extends XMLDBAction {
         $result = $this->launch('get_db_directories');
         // Display list of DB directories if everything is ok
         if ($result && !empty($XMLDB->dbdirs)) {
-            $o .= '<table id="listdirectories" border="0" cellpadding="5" cellspacing="1" class="boxaligncenter flexible">';
+            $o .= '<table id="listdirectories" border="0" cellpadding="5" cellspacing="1" class="admintable generaltable">';
             $row = 0;
             foreach ($XMLDB->dbdirs as $key => $dbdir) {
                 // Detect if this is the lastused dir
index a9d1ef9..1649d36 100644 (file)
@@ -71,7 +71,7 @@ class revert_changes extends XMLDBAction {
 
         // If  not confirmed, show confirmation box
         if (!$confirmed) {
-            $o = '<table width="60" class="generalbox boxaligncenter" border="0" cellpadding="5" cellspacing="0" id="notice">';
+            $o = '<table width="60" class="generaltable boxaligncenter" border="0" cellpadding="5" cellspacing="0" id="notice">';
             $o.= '  <tr><td class="generalboxcontent">';
             $o.= '    <p class="centerpara">' . $this->str['confirmrevertchanges'] . '<br /><br />' . $dirpath . '</p>';
             $o.= '    <table class="boxaligncenter" cellpadding="20"><tr><td>';
index aac7112..a52db6c 100644 (file)
         $$column = "<a href=\"user.php?sort=$column&amp;dir=$columndir\">".$string[$column]."</a>$columnicon";
     }
 
-    if ($sort == "name") {
-        $sort = "firstname";
+    $override = new stdClass();
+    $override->firstname = 'firstname';
+    $override->lastname = 'lastname';
+    $fullnamelanguage = get_string('fullnamedisplay', '', $override);
+    if (($CFG->fullnamedisplay == 'firstname lastname') or
+        ($CFG->fullnamedisplay == 'firstname') or
+        ($CFG->fullnamedisplay == 'language' and $fullnamelanguage == 'firstname lastname' )) {
+        $fullnamedisplay = "$firstname / $lastname";
+        if ($sort == "name") { // If sort has already been set to something else then ignore.
+            $sort = "firstname";
+        }
+    } else { // ($CFG->fullnamedisplay == 'language' and $fullnamelanguage == 'lastname firstname').
+        $fullnamedisplay = "$lastname / $firstname";
+        if ($sort == "name") { // This should give the desired sorting based on fullnamedisplay.
+            $sort = "lastname";
+        }
     }
 
     list($extrasql, $params) = $ufiltering->get_sql_filter();
             $users = $nusers;
         }
 
-        $override = new stdClass();
-        $override->firstname = 'firstname';
-        $override->lastname = 'lastname';
-        $fullnamelanguage = get_string('fullnamedisplay', '', $override);
-        if (($CFG->fullnamedisplay == 'firstname lastname') or
-            ($CFG->fullnamedisplay == 'firstname') or
-            ($CFG->fullnamedisplay == 'language' and $fullnamelanguage == 'firstname lastname' )) {
-            $fullnamedisplay = "$firstname / $lastname";
-        } else { // ($CFG->fullnamedisplay == 'language' and $fullnamelanguage == 'lastname firstname')
-            $fullnamedisplay = "$lastname / $firstname";
-        }
-
         $table = new html_table();
         $table->head = array ();
-        $table->align = array();
+        $table->colclasses = array();
         $table->head[] = $fullnamedisplay;
-        $table->align[] = 'left';
+        $table->attributes['class'] = 'admintable generaltable';
+        $table->colclasses[] = 'leftalign';
         foreach ($extracolumns as $field) {
             $table->head[] = ${$field};
-            $table->align[] = 'left';
+            $table->colclasses[] = 'leftalign';
         }
         $table->head[] = $city;
-        $table->align[] = 'left';
+        $table->colclasses[] = 'leftalign';
         $table->head[] = $country;
-        $table->align[] = 'left';
+        $table->colclasses[] = 'leftalign';
         $table->head[] = $lastaccess;
-        $table->align[] = 'left';
+        $table->colclasses[] = 'leftalign';
         $table->head[] = get_string('edit');
-        $table->align[] = 'center';
+        $table->colclasses[] = 'centeralign';
         $table->head[] = "";
-        $table->align[] = 'center';
+        $table->colclasses[] = 'centeralign';
 
-        $table->width = "95%";
+        $table->id = "users";
         foreach ($users as $user) {
             if (isguestuser($user)) {
                 continue; // do not display guest here
index 289dcc4..745e9e1 100644 (file)
@@ -163,6 +163,7 @@ class external_service_functions_form extends moodleform {
 
         $mform->addElement('searchableselector', 'fids', get_string('name'),
                 $functions, array('multiple'));
+        $mform->addRule('fids', get_string('required'), 'required', null, 'client');
 
         $mform->addElement('hidden', 'id');
         $mform->setType('id', PARAM_INT);
index e6bae3f..975c0e5 100644 (file)
@@ -339,7 +339,7 @@ class phpCAS {
         *\r
         * @return a newly created CASClient object\r
         */\r
-       function client($server_version, $server_hostname, $server_port, $server_uri, $start_session = true) {\r
+       public static function client($server_version, $server_hostname, $server_port, $server_uri, $start_session = true) {\r
                global $PHPCAS_CLIENT, $PHPCAS_INIT_CALL;\r
 \r
                phpCAS :: traceBegin();\r
@@ -388,7 +388,7 @@ class phpCAS {
         *\r
         * @return a newly created CASClient object\r
         */\r
-       function proxy($server_version, $server_hostname, $server_port, $server_uri, $start_session = true) {\r
+       public static function proxy($server_version, $server_hostname, $server_port, $server_uri, $start_session = true) {\r
                global $PHPCAS_CLIENT, $PHPCAS_INIT_CALL;\r
 \r
                phpCAS :: traceBegin();\r
@@ -438,7 +438,7 @@ class phpCAS {
         *\r
         * @param $filename the name of the file used for logging, or FALSE to stop debugging.\r
         */\r
-       function setDebug($filename = '') {\r
+       public static function setDebug($filename = '') {\r
                global $PHPCAS_DEBUG;\r
 \r
                if ($filename != FALSE && gettype($filename) != 'string') {\r
@@ -480,7 +480,7 @@ class phpCAS {
         * This method is a wrapper for debug_backtrace() that is not available \r
         * in all PHP versions (>= 4.3.0 only)\r
         */\r
-       function backtrace() {\r
+       public static function backtrace() {\r
                if (function_exists('debug_backtrace')) {\r
                        return debug_backtrace();\r
                } else {\r
@@ -496,7 +496,7 @@ class phpCAS {
         *\r
         * @private\r
         */\r
-       function log($str) {\r
+       public static function log($str) {\r
                $indent_str = ".";\r
                global $PHPCAS_DEBUG;\r
 \r
@@ -517,7 +517,7 @@ class phpCAS {
         *\r
         * @private\r
         */\r
-       function error($msg) {\r
+       public static function error($msg) {\r
                $dbg = phpCAS :: backtrace();\r
                $function = '?';\r
                $file = '?';\r
@@ -542,7 +542,7 @@ class phpCAS {
        /**\r
         * This method is used to log something in debug mode.\r
         */\r
-       function trace($str) {\r
+       public static function trace($str) {\r
                $dbg = phpCAS :: backtrace();\r
                phpCAS :: log($str . ' [' . basename($dbg[1]['file']) . ':' . $dbg[1]['line'] . ']');\r
        }\r
@@ -550,7 +550,7 @@ class phpCAS {
        /**\r
         * This method is used to indicate the start of the execution of a function in debug mode.\r
         */\r
-       function traceBegin() {\r
+       public static function traceBegin() {\r
                global $PHPCAS_DEBUG;\r
 \r
                $dbg = phpCAS :: backtrace();\r
@@ -577,7 +577,7 @@ class phpCAS {
         *\r
         * @param $res the result of the function\r
         */\r
-       function traceEnd($res = '') {\r
+       public static function traceEnd($res = '') {\r
                global $PHPCAS_DEBUG;\r
 \r
                $PHPCAS_DEBUG['indent']--;\r
@@ -590,7 +590,7 @@ class phpCAS {
        /**\r
         * This method is used to indicate the end of the execution of the program\r
         */\r
-       function traceExit() {\r
+       public static function traceExit() {\r
                global $PHPCAS_DEBUG;\r
 \r
                phpCAS :: log('exit()');\r
@@ -617,7 +617,7 @@ class phpCAS {
         *\r
         * @sa PHPCAS_LANG_FRENCH, PHPCAS_LANG_ENGLISH\r
         */\r
-       function setLang($lang) {\r
+       public static function setLang($lang) {\r
                global $PHPCAS_CLIENT;\r
                if (!is_object($PHPCAS_CLIENT)) {\r
                        phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
@@ -642,7 +642,7 @@ class phpCAS {
         *\r
         * @return the phpCAS version.\r
         */\r
-       function getVersion() {\r
+       public static function getVersion() {\r
                return PHPCAS_VERSION;\r
        }\r
 \r
@@ -660,7 +660,7 @@ class phpCAS {
         *\r
         * @param $header the HTML header.\r
         */\r
-       function setHTMLHeader($header) {\r
+       public static function setHTMLHeader($header) {\r
                global $PHPCAS_CLIENT;\r
                if (!is_object($PHPCAS_CLIENT)) {\r
                        phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
@@ -676,7 +676,7 @@ class phpCAS {
         *\r
         * @param $footer the HTML footer.\r
         */\r
-       function setHTMLFooter($footer) {\r
+       public static function setHTMLFooter($footer) {\r
                global $PHPCAS_CLIENT;\r
                if (!is_object($PHPCAS_CLIENT)) {\r
                        phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
@@ -703,7 +703,7 @@ class phpCAS {
         * @param $format the format used to store the PGT's (`plain' and `xml' allowed)\r
         * @param $path the path where the PGT's should be stored\r
         */\r
-       function setPGTStorageFile($format = '', $path = '') {\r
+       public static function setPGTStorageFile($format = '', $path = '') {\r
                global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
 \r
                phpCAS :: traceBegin();\r
@@ -749,7 +749,7 @@ class phpCAS {
         * @return TRUE on success, FALSE otherwise (in this later case, $err_code\r
         * gives the reason why it failed and $output contains an error message).\r
         */\r
-       function serviceWeb($url, & $err_code, & $output) {\r
+       public static function serviceWeb($url, & $err_code, & $output) {\r
                global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
 \r
                phpCAS :: traceBegin();\r
@@ -792,7 +792,7 @@ class phpCAS {
         * @return an IMAP stream on success, FALSE otherwise (in this later case, $err_code\r
         * gives the reason why it failed and $err_msg contains an error message).\r
         */\r
-       function serviceMail($url, $service, $flags, & $err_code, & $err_msg, & $pt) {\r
+       public static function serviceMail($url, $service, $flags, & $err_code, & $err_msg, & $pt) {\r
                global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
 \r
                phpCAS :: traceBegin();\r
@@ -839,7 +839,7 @@ class phpCAS {
         *\r
         * @param $n an integer.\r
         */\r
-       function setCacheTimesForAuthRecheck($n) {\r
+       public static function setCacheTimesForAuthRecheck($n) {\r
                global $PHPCAS_CLIENT;\r
                if (!is_object($PHPCAS_CLIENT)) {\r
                        phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
@@ -854,7 +854,7 @@ class phpCAS {
         * This method is called to check if the user is authenticated (use the gateway feature).\r
         * @return TRUE when the user is authenticated; otherwise FALSE.\r
         */\r
-       function checkAuthentication() {\r
+       public static function checkAuthentication() {\r
                global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
 \r
                phpCAS :: traceBegin();\r
@@ -882,7 +882,7 @@ class phpCAS {
         * authenticated. If the user is not authenticated, halt by redirecting to \r
         * the CAS server.\r
         */\r
-       function forceAuthentication() {\r
+       public static function forceAuthentication() {\r
                global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
 \r
                phpCAS :: traceBegin();\r
@@ -916,7 +916,7 @@ class phpCAS {
        /**\r
         * This method is called to renew the authentication.\r
         **/\r
-       function renewAuthentication() {\r
+       public static function renewAuthentication() {\r
                global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
 \r
                phpCAS :: traceBegin();\r
@@ -941,7 +941,7 @@ class phpCAS {
        /**\r
         * This method has been left from version 0.4.1 for compatibility reasons.\r
         */\r
-       function authenticate() {\r
+       public static function authenticate() {\r
                phpCAS :: error('this method is deprecated. You should use ' . __CLASS__ . '::forceAuthentication() instead');\r
        }\r
 \r
@@ -951,7 +951,7 @@ class phpCAS {
         *\r
         * @return TRUE when the user is authenticated.\r
         */\r
-       function isAuthenticated() {\r
+       public static function isAuthenticated() {\r
                global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
 \r
                phpCAS :: traceBegin();\r
@@ -981,7 +981,7 @@ class phpCAS {
         * @return true if authenticated, false otherwise.\r
         * @since 0.4.22 by Brendan Arnold\r
         */\r
-       function isSessionAuthenticated() {\r
+       public static function isSessionAuthenticated() {\r
                global $PHPCAS_CLIENT;\r
                if (!is_object($PHPCAS_CLIENT)) {\r
                        phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
@@ -996,7 +996,7 @@ class phpCAS {
         *\r
         * @return the login name of the authenticated user\r
         */\r
-       function getUser() {\r
+       public static function getUser() {\r
                global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
                if (!is_object($PHPCAS_CLIENT)) {\r
                        phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
@@ -1017,7 +1017,7 @@ class phpCAS {
         *\r
         * @return the login name of the authenticated user\r
         */\r
-       function getAttributes() {\r
+       public static function getAttributes() {\r
                global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
                if (!is_object($PHPCAS_CLIENT)) {\r
                        phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
@@ -1033,7 +1033,7 @@ class phpCAS {
        /**\r
         * Handle logout requests.\r
         */\r
-       function handleLogoutRequests($check_client = true, $allowed_clients = false) {\r
+       public static function handleLogoutRequests($check_client = true, $allowed_clients = false) {\r
                global $PHPCAS_CLIENT;\r
                if (!is_object($PHPCAS_CLIENT)) {\r
                        phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
@@ -1047,7 +1047,7 @@ class phpCAS {
         *\r
         * @return the login name of the authenticated user\r
         */\r
-       function getServerLoginURL() {\r
+       public static function getServerLoginURL() {\r
                global $PHPCAS_CLIENT;\r
                if (!is_object($PHPCAS_CLIENT)) {\r
                        phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
@@ -1060,7 +1060,7 @@ class phpCAS {
         * @param $url the login URL\r
         * @since 0.4.21 by Wyman Chan\r
         */\r
-       function setServerLoginURL($url = '') {\r
+       public static function setServerLoginURL($url = '') {\r
                global $PHPCAS_CLIENT;\r
                phpCAS :: traceBegin();\r
                if (!is_object($PHPCAS_CLIENT)) {\r
@@ -1081,7 +1081,7 @@ class phpCAS {
         * @param $url the serviceValidate URL\r
         * @since 1.1.0 by Joachim Fritschi\r
         */\r
-       function setServerServiceValidateURL($url = '') {\r
+       public static function setServerServiceValidateURL($url = '') {\r
                global $PHPCAS_CLIENT;\r
                phpCAS :: traceBegin();\r
                if (!is_object($PHPCAS_CLIENT)) {\r
@@ -1102,7 +1102,7 @@ class phpCAS {
         * @param $url the proxyValidate URL\r
         * @since 1.1.0 by Joachim Fritschi\r
         */\r
-       function setServerProxyValidateURL($url = '') {\r
+       public static function setServerProxyValidateURL($url = '') {\r
                global $PHPCAS_CLIENT;\r
                phpCAS :: traceBegin();\r
                if (!is_object($PHPCAS_CLIENT)) {\r
@@ -1122,7 +1122,7 @@ class phpCAS {
         * @param $url the samlValidate URL\r
         * @since 1.1.0 by Joachim Fritschi\r
         */\r
-       function setServerSamlValidateURL($url = '') {\r
+       public static function setServerSamlValidateURL($url = '') {\r
                global $PHPCAS_CLIENT;\r
                phpCAS :: traceBegin();\r
                if (!is_object($PHPCAS_CLIENT)) {\r
@@ -1143,7 +1143,7 @@ class phpCAS {
         *\r
         * @return the login name of the authenticated user\r
         */\r
-       function getServerLogoutURL() {\r
+       public static function getServerLogoutURL() {\r
                global $PHPCAS_CLIENT;\r
                if (!is_object($PHPCAS_CLIENT)) {\r
                        phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
@@ -1156,7 +1156,7 @@ class phpCAS {
         * @param $url the logout URL\r
         * @since 0.4.21 by Wyman Chan\r
         */\r
-       function setServerLogoutURL($url = '') {\r
+       public static function setServerLogoutURL($url = '') {\r
                global $PHPCAS_CLIENT;\r
                phpCAS :: traceBegin();\r
                if (!is_object($PHPCAS_CLIENT)) {\r
@@ -1176,7 +1176,7 @@ class phpCAS {
         * @params $params an array that contains the optional url and service parameters that will be passed to the CAS server\r
         * @public\r
         */\r
-       function logout($params = "") {\r
+       public static function logout($params = "") {\r
                global $PHPCAS_CLIENT;\r
                phpCAS :: traceBegin();\r
                if (!is_object($PHPCAS_CLIENT)) {\r
@@ -1206,7 +1206,7 @@ class phpCAS {
         * This method is used to logout from CAS. Halts by redirecting to the CAS server.\r
         * @param $service a URL that will be transmitted to the CAS server\r
         */\r
-       function logoutWithRedirectService($service) {\r
+       public static function logoutWithRedirectService($service) {\r
                global $PHPCAS_CLIENT;\r
                phpCAS :: traceBegin();\r
                if (!is_object($PHPCAS_CLIENT)) {\r
@@ -1226,7 +1226,7 @@ class phpCAS {
         * This method is used to logout from CAS. Halts by redirecting to the CAS server.\r
         * @param $url a URL that will be transmitted to the CAS server\r
         */\r
-       function logoutWithUrl($url) {\r
+       public static function logoutWithUrl($url) {\r
                global $PHPCAS_CLIENT;\r
                phpCAS :: traceBegin();\r
                if (!is_object($PHPCAS_CLIENT)) {\r
@@ -1247,7 +1247,7 @@ class phpCAS {
         * @param $service a URL that will be transmitted to the CAS server\r
         * @param $url a URL that will be transmitted to the CAS server\r
         */\r
-       function logoutWithRedirectServiceAndUrl($service, $url) {\r
+       public static function logoutWithRedirectServiceAndUrl($service, $url) {\r
                global $PHPCAS_CLIENT;\r
                phpCAS :: traceBegin();\r
                if (!is_object($PHPCAS_CLIENT)) {\r
@@ -1273,7 +1273,7 @@ class phpCAS {
         *\r
         * @param $url the URL\r
         */\r
-       function setFixedCallbackURL($url = '') {\r
+       public static function setFixedCallbackURL($url = '') {\r
                global $PHPCAS_CLIENT;\r
                phpCAS :: traceBegin();\r
                if (!is_object($PHPCAS_CLIENT)) {\r
@@ -1295,7 +1295,7 @@ class phpCAS {
         *\r
         * @param $url the URL\r
         */\r
-       function setFixedServiceURL($url) {\r
+       public static function setFixedServiceURL($url) {\r
                global $PHPCAS_CLIENT;\r
                phpCAS :: traceBegin();\r
                if (!is_object($PHPCAS_CLIENT)) {\r
@@ -1311,7 +1311,7 @@ class phpCAS {
        /**\r
         * Get the URL that is set as the CAS service parameter.\r
         */\r
-       function getServiceURL() {\r
+       public static function getServiceURL() {\r
                global $PHPCAS_CLIENT;\r
                if (!is_object($PHPCAS_CLIENT)) {\r
                        phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');\r
@@ -1322,7 +1322,7 @@ class phpCAS {
        /**\r
         * Retrieve a Proxy Ticket from the CAS server.\r
         */\r
-       function retrievePT($target_service, & $err_code, & $err_msg) {\r
+       public static function retrievePT($target_service, & $err_code, & $err_msg) {\r
                global $PHPCAS_CLIENT;\r
                if (!is_object($PHPCAS_CLIENT)) {\r
                        phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');\r
@@ -1338,7 +1338,7 @@ class phpCAS {
         *\r
         * @param $cert the PEM certificate\r
         */\r
-       function setCasServerCert($cert) {\r
+       public static function setCasServerCert($cert) {\r
                global $PHPCAS_CLIENT;\r
                phpCAS :: traceBegin();\r
                if (!is_object($PHPCAS_CLIENT)) {\r
@@ -1356,7 +1356,7 @@ class phpCAS {
         *\r
         * @param $cert the CA certificate\r
         */\r
-       function setCasServerCACert($cert) {\r
+       public static function setCasServerCACert($cert) {\r
                global $PHPCAS_CLIENT;\r
                phpCAS :: traceBegin();\r
                if (!is_object($PHPCAS_CLIENT)) {\r
@@ -1372,7 +1372,7 @@ class phpCAS {
        /**\r
         * Set no SSL validation for the CAS server.\r
         */\r
-       function setNoCasServerValidation() {\r
+       public static function setNoCasServerValidation() {\r
                global $PHPCAS_CLIENT;\r
                phpCAS :: traceBegin();\r
                if (!is_object($PHPCAS_CLIENT)) {\r
@@ -1390,7 +1390,7 @@ class phpCAS {
         * @param $key the option key\r
         * @param $value the value to set\r
         */\r
-       function setExtraCurlOption($key, $value) {\r
+       public static function setExtraCurlOption($key, $value) {\r
                global $PHPCAS_CLIENT;\r
                phpCAS :: traceBegin();\r
                if (!is_object($PHPCAS_CLIENT)) {\r
index c0bcd50..ccd1021 100644 (file)
@@ -104,12 +104,14 @@ class auth_plugin_cas extends auth_plugin_ldap {
         $this->connectCAS();
 
         if (phpCAS::checkAuthentication()) {
+            $frm = new stdClass();
             $frm->username = phpCAS::getUser();
             $frm->password = 'passwdCas';
             return;
         }
 
         if (isset($_GET['loginguest']) && ($_GET['loginguest'] == true)) {
+            $frm = new stdClass();
             $frm->username = 'guest';
             $frm->password = 'guest';
             return;
diff --git a/auth/ldap/tests/ldap_test.php b/auth/ldap/tests/ldap_test.php
new file mode 100644 (file)
index 0000000..fdf3384
--- /dev/null
@@ -0,0 +1,283 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * LDAP authentication plugin tests.
+ *
+ * NOTE: in order to execute this test you need to set up
+ *       OpenLDAP server with core, cosine, nis and internet schemas
+ *       and add configuration constants to config.php or phpunit.xml configuration file:
+ *
+ * define('TEST_AUTH_LDAP_HOST_URL', 'ldap://127.0.0.1');
+ * define('TEST_AUTH_LDAP_BIND_DN', 'cn=someuser,dc=example,dc=local');
+ * define('TEST_AUTH_LDAP_BIND_PW', 'somepassword');
+ * define('TEST_AUTH_LDAP_DOMAIN', 'dc=example,dc=local');
+ *
+ * @package    auth_ldap
+ * @category   phpunit
+ * @copyright  2013 Petr Skoda {@link http://skodak.org}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+class auth_ldap_testcase extends advanced_testcase {
+
+    public function test_auth_ldap() {
+        global $CFG, $DB;
+
+        if (!extension_loaded('ldap')) {
+            $this->markTestSkipped('LDAP extension is not loaded.');
+        }
+
+        $this->resetAfterTest();
+
+        require_once($CFG->dirroot.'/auth/ldap/auth.php');
+        require_once($CFG->libdir.'/ldaplib.php');
+
+        if (!defined('TEST_AUTH_LDAP_HOST_URL') or !defined('TEST_AUTH_LDAP_BIND_DN') or !defined('TEST_AUTH_LDAP_BIND_PW') or !defined('TEST_AUTH_LDAP_DOMAIN')) {
+            $this->markTestSkipped('External LDAP test server not configured.');
+        }
+
+        // Make sure we can connect the server.
+        $debuginfo = '';
+        if (!$connection = ldap_connect_moodle(TEST_AUTH_LDAP_HOST_URL, 3, 'rfc2307', TEST_AUTH_LDAP_BIND_DN, TEST_AUTH_LDAP_BIND_PW, LDAP_DEREF_NEVER, $debuginfo, false)) {
+            $this->markTestSkipped('Can not connect to LDAP test server: '.$debuginfo);
+        }
+
+        $this->enable_plugin();
+
+        // Create new empty test container.
+        $topdn = 'dc=moodletest,'.TEST_AUTH_LDAP_DOMAIN;
+
+        $this->recursive_delete($connection, TEST_AUTH_LDAP_DOMAIN, 'dc=moodletest');
+
+        $o = array();
+        $o['objectClass'] = array('dcObject', 'organizationalUnit');
+        $o['dc']         = 'moodletest';
+        $o['ou']         = 'MOODLETEST';
+        if (!ldap_add($connection, 'dc=moodletest,'.TEST_AUTH_LDAP_DOMAIN, $o)) {
+            $this->markTestSkipped('Can not create test LDAP container.');
+        }
+
+        // Create a few users.
+        $o = array();
+        $o['objectClass'] = array('organizationalUnit');
+        $o['ou']          = 'users';
+        ldap_add($connection, 'ou='.$o['ou'].','.$topdn, $o);
+
+        for ($i=1; $i<=5; $i++) {
+            $this->create_ldap_user($connection, $topdn, $i);
+        }
+
+        // Set up creators group.
+        $o = array();
+        $o['objectClass'] = array('posixGroup');
+        $o['cn']          = 'creators';
+        $o['gidNumber']   = 1;
+        $o['memberUid']   = array('username1', 'username2');
+        ldap_add($connection, 'cn='.$o['cn'].','.$topdn, $o);
+
+        $creatorrole = $DB->get_record('role', array('shortname'=>'coursecreator'));
+        $this->assertNotEmpty($creatorrole);
+
+
+        // Configure the plugin a bit.
+        set_config('host_url', TEST_AUTH_LDAP_HOST_URL, 'auth/ldap');
+        set_config('start_tls', 0, 'auth/ldap');
+        set_config('ldap_version', 3, 'auth/ldap');
+        set_config('ldapencoding', 'utf-8', 'auth/ldap');
+        set_config('pagesize', '2', 'auth/ldap');
+        set_config('bind_dn', TEST_AUTH_LDAP_BIND_DN, 'auth/ldap');
+        set_config('bind_pw', TEST_AUTH_LDAP_BIND_PW, 'auth/ldap');
+        set_config('user_type', 'rfc2307', 'auth/ldap');
+        set_config('contexts', 'ou=users,'.$topdn, 'auth/ldap');
+        set_config('search_sub', 0, 'auth/ldap');
+        set_config('opt_deref', LDAP_DEREF_NEVER, 'auth/ldap');
+        set_config('user_attribute', 'cn', 'auth/ldap');
+        set_config('memberattribute', 'memberuid', 'auth/ldap');
+        set_config('memberattribute_isdn', 0, 'auth/ldap');
+        set_config('creators', 'cn=creators,'.$topdn, 'auth/ldap');
+        set_config('removeuser', AUTH_REMOVEUSER_KEEP, 'auth/ldap');
+
+        set_config('field_map_email', 'mail', 'auth/ldap');
+        set_config('field_updatelocal_email', 'oncreate', 'auth/ldap');
+        set_config('field_updateremote_email', '0', 'auth/ldap');
+        set_config('field_lock_email', 'unlocked', 'auth/ldap');
+
+        set_config('field_map_firstname', 'givenName', 'auth/ldap');
+        set_config('field_updatelocal_firstname', 'oncreate', 'auth/ldap');
+        set_config('field_updateremote_firstname', '0', 'auth/ldap');
+        set_config('field_lock_firstname', 'unlocked', 'auth/ldap');
+
+        set_config('field_map_lastname', 'sn', 'auth/ldap');
+        set_config('field_updatelocal_lastname', 'oncreate', 'auth/ldap');
+        set_config('field_updateremote_lastname', '0', 'auth/ldap');
+        set_config('field_lock_lastname', 'unlocked', 'auth/ldap');
+
+
+        $this->assertEquals(2, $DB->count_records('user'));
+        $this->assertEquals(0, $DB->count_records('role_assignments'));
+
+        /** @var auth_plugin_ldap $auth */
+        $auth = get_auth_plugin('ldap');
+
+        ob_start();
+        $auth->sync_users(true);
+        ob_end_clean();
+
+        $this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
+        $this->assertEquals(2, $DB->count_records('role_assignments'));
+        $this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$creatorrole->id)));
+
+        for ($i=1; $i<=5; $i++) {
+            $this->assertTrue($DB->record_exists('user', array('username'=>'username'.$i, 'email'=>'user'.$i.'@example.com', 'firstname'=>'Firstname'.$i, 'lastname'=>'Lastname'.$i)));
+        }
+
+        $this->delete_ldap_user($connection, $topdn, 1);
+
+        ob_start();
+        $auth->sync_users(true);
+        ob_end_clean();
+
+        $this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
+        $this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
+        $this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
+        $this->assertEquals(2, $DB->count_records('role_assignments'));
+        $this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$creatorrole->id)));
+
+
+        set_config('removeuser', AUTH_REMOVEUSER_SUSPEND, 'auth/ldap');
+
+        /** @var auth_plugin_ldap $auth */
+        $auth = get_auth_plugin('ldap');
+
+        ob_start();
+        $auth->sync_users(true);
+        ob_end_clean();
+
+        $this->assertEquals(4, $DB->count_records('user', array('auth'=>'ldap')));
+        $this->assertEquals(1, $DB->count_records('user', array('auth'=>'nologin', 'username'=>'username1')));
+        $this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
+        $this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
+        $this->assertEquals(2, $DB->count_records('role_assignments'));
+        $this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$creatorrole->id)));
+
+        $this->create_ldap_user($connection, $topdn, 1);
+
+        ob_start();
+        $auth->sync_users(true);
+        ob_end_clean();
+
+        $this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
+        $this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
+        $this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
+        $this->assertEquals(2, $DB->count_records('role_assignments'));
+        $this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$creatorrole->id)));
+
+
+        set_config('removeuser', AUTH_REMOVEUSER_FULLDELETE, 'auth/ldap');
+
+        /** @var auth_plugin_ldap $auth */
+        $auth = get_auth_plugin('ldap');
+
+        $this->delete_ldap_user($connection, $topdn, 1);
+
+        ob_start();
+        $auth->sync_users(true);
+        ob_end_clean();
+
+        $this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
+        $this->assertEquals(0, $DB->count_records('user', array('username'=>'username1')));
+        $this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
+        $this->assertEquals(1, $DB->count_records('user', array('deleted'=>1)));
+        $this->assertEquals(1, $DB->count_records('role_assignments'));
+        $this->assertEquals(1, $DB->count_records('role_assignments', array('roleid'=>$creatorrole->id)));
+
+        $this->create_ldap_user($connection, $topdn, 1);
+
+        ob_start();
+        $auth->sync_users(true);
+        ob_end_clean();
+
+        $this->assertEquals(6, $DB->count_records('user', array('auth'=>'ldap')));
+        $this->assertEquals(1, $DB->count_records('user', array('username'=>'username1')));
+        $this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
+        $this->assertEquals(1, $DB->count_records('user', array('deleted'=>1)));
+        $this->assertEquals(2, $DB->count_records('role_assignments'));
+        $this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$creatorrole->id)));
+
+
+        $this->recursive_delete($connection, TEST_AUTH_LDAP_DOMAIN, 'dc=moodletest');
+        ldap_close($connection);
+    }
+
+    protected function create_ldap_user($connection, $topdn, $i) {
+        $o = array();
+        $o['objectClass']   = array('inetOrgPerson', 'organizationalPerson', 'person', 'posixAccount');
+        $o['cn']            = 'username'.$i;
+        $o['sn']            = 'Lastname'.$i;
+        $o['givenName']     = 'Firstname'.$i;
+        $o['uid']           = $o['cn'];
+        $o['uidnumber']     = 2000+$i;
+        $o['gidNumber']     = 1000+$i;
+        $o['homeDirectory'] = '/';
+        $o['mail']          = 'user'.$i.'@example.com';
+        $o['userPassword']  = 'pass'.$i;
+        ldap_add($connection, 'cn='.$o['cn'].',ou=users,'.$topdn, $o);
+    }
+
+    protected function delete_ldap_user($connection, $topdn, $i) {
+        ldap_delete($connection, 'cn=username'.$i.',ou=users,'.$topdn);
+    }
+
+    protected function enable_plugin() {
+        $auths = get_enabled_auth_plugins(true);
+        if (!in_array('ldap', $auths)) {
+            $auths[] = 'ldap';
+
+        }
+        set_config('auth', implode(',', $auths));
+    }
+
+    protected function recursive_delete($connection, $dn, $filter) {
+        if ($res = ldap_list($connection, $dn, $filter, array('dn'))) {
+            $info = ldap_get_entries($connection, $res);
+            ldap_free_result($res);
+            if ($info['count'] > 0) {
+                if ($res = ldap_search($connection, "$filter,$dn", 'cn=*', array('dn'))) {
+                    $info = ldap_get_entries($connection, $res);
+                    ldap_free_result($res);
+                    foreach ($info as $i) {
+                        if (isset($i['dn'])) {
+                            ldap_delete($connection, $i['dn']);
+                        }
+                    }
+                }
+                if ($res = ldap_search($connection, "$filter,$dn", 'ou=*', array('dn'))) {
+                    $info = ldap_get_entries($connection, $res);
+                    ldap_free_result($res);
+                    foreach ($info as $i) {
+                        if (isset($i['dn']) and $info[0]['dn'] != $i['dn']) {
+                            ldap_delete($connection, $i['dn']);
+                        }
+                    }
+                }
+                ldap_delete($connection, "$filter,$dn");
+            }
+        }
+    }
+}
diff --git a/auth/tests/behat/behat_auth.php b/auth/tests/behat/behat_auth.php
new file mode 100644 (file)
index 0000000..eab0062
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Basic authentication steps definitions.
+ *
+ * @package    core
+ * @category   test
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
+
+require_once(__DIR__ . '/../../../lib/behat/behat_base.php');
+
+use Behat\Behat\Context\Step\Given as Given;
+use Behat\Behat\Context\Step\When as When;
+
+/**
+ * Log in log out steps definitions.
+ *
+ * @package    core
+ * @category   test
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_auth extends behat_base {
+
+    /**
+     * Logs in the user. There should exist a user with the same value as username and password.
+     *
+     * @Given /^I log in as "(?P<username_string>(?:[^"]|\\")*)"$/
+     */
+    public function i_log_in_as($username) {
+
+        return array(new Given('I am on homepage'),
+            new Given('I follow "Login"'),
+            new Given('I fill in "Username" with "'.$username.'"'),
+            new Given('I fill in "Password" with "'.$username.'"'),
+            new When('I press "Login"'),
+            new Given('I should see "You are logged in as"'));
+    }
+
+    /**
+     * Logs out of the system.
+     *
+     * @Given /^I log out$/
+     */
+    public function i_log_out() {
+        return new When('I follow "Logout"');
+    }
+
+}
diff --git a/auth/tests/behat/login.feature b/auth/tests/behat/login.feature
new file mode 100644 (file)
index 0000000..d731f8c
--- /dev/null
@@ -0,0 +1,13 @@
+@auth
+Feature: Authentication
+  In order to validate my credentials in the system
+  As a moodle user
+  I need to log into the system
+
+  Scenario: Login with the predefined admin user
+    Given I log in as "admin"
+
+  Scenario: Logout
+    Given I log in as "admin"
+    When I log out
+    Then I should see "You are not logged in"
index 7fd4029..aba56d4 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Defines backup_gradingform_plugin class
+ * Contains class backup_gradingform_plugin responsible for advanced grading form plugin backup
  *
  * @package     core_backup
  * @subpackage  moodle2
- * @category    backup
  * @copyright   2011 David Mudrak <david@moodle.com>
  * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 defined('MOODLE_INTERNAL') || die();
 
 /**
- * Base class for all advanced grading form plugins
+ * Base class for backup all advanced grading form plugins
+ *
+ * As an example of implementation see {@link backup_gradingform_rubric_plugin}
+ *
+ * @copyright  2011 David Mudrak <david@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @category   backup
  */
 abstract class backup_gradingform_plugin extends backup_plugin {
 }
index 6caa7dc..320967f 100644 (file)
@@ -1,5 +1,4 @@
 <?php
-
 // This file is part of Moodle - http://moodle.org/
 //
 // Moodle is free software: you can redistribute it and/or modify
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Defines restore_gradingform_plugin class
- * @package     core_backup
+ * Contains class restore_gradingform_plugin responsible for advanced grading form plugin backup
+ *
+ * @package    core_backup
  * @subpackage  moodle2
- * @category    backup
- * @copyright   2011 David Mudrak <david@moodle.com>
- * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @copyright  2011 David Mudrak <david@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
 defined('MOODLE_INTERNAL') || die();
 
 /**
- * Base class for all advanced grading form plugins
+ * Base class for restoring all advanced grading form plugins
+ *
+ * As an example of implementation see {@link restore_gradingform_rubric_plugin}
+ *
+ * @copyright  2011 David Mudrak <david@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @category   backup
  */
 abstract class restore_gradingform_plugin extends restore_plugin {
 
index b7da2d3..f254475 100644 (file)
@@ -778,6 +778,8 @@ class restore_groups_structure_step extends restore_structure_step {
         }
         // Save the id mapping
         $this->set_mapping('group', $oldid, $newitemid, $restorefiles);
+        // Invalidate the course group data cache just in case.
+        cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($data->courseid));
     }
 
     public function process_grouping($data) {
@@ -821,23 +823,17 @@ class restore_groups_structure_step extends restore_structure_step {
         }
         // Save the id mapping
         $this->set_mapping('grouping', $oldid, $newitemid, $restorefiles);
+        // Invalidate the course group data cache just in case.
+        cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($data->courseid));
     }
 
     public function process_grouping_group($data) {
-        global $DB;
-
-        $data = (object)$data;
-
-        $data->groupingid = $this->get_new_parentid('grouping'); // Use new parentid
-        $data->groupid    = $this->get_mappingid('group', $data->groupid); // Get from mappings
+        global $CFG;
 
-        $params = array();
-        $params['groupingid'] = $data->groupingid;
-        $params['groupid']    = $data->groupid;
+        require_once($CFG->dirroot.'/group/lib.php');
 
-        if (!$DB->record_exists('groupings_groups', $params)) {
-            $DB->insert_record('groupings_groups', $data);  // No need to set this mapping (no child info nor files)
-        }
+        $data = (object)$data;
+        groups_assign_grouping($this->get_new_parentid('grouping'), $this->get_mappingid('group', $data->groupid), $data->timeadded);
     }
 
     protected function after_execute() {
@@ -846,6 +842,8 @@ class restore_groups_structure_step extends restore_structure_step {
         $this->add_related_files('group', 'description', 'group');
         // Add grouping related files, matching with "grouping" mappings
         $this->add_related_files('grouping', 'description', 'grouping');
+        // Invalidate the course group data.
+        cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($this->get_courseid()));
     }
 
 }
index a906801..82c4897 100644 (file)
@@ -1147,14 +1147,16 @@ abstract class restore_dbops {
     *
     *  If restoring users from same site backup:
     *      1A - Normal check: If match by id and username and mnethost  => ok, return target user
-    *      1B - Handle users deleted in DB and "alive" in backup file:
+    *      1B - If restoring an 'anonymous' user (created via the 'Anonymize user information' option) try to find a
+    *           match by username only => ok, return target user MDL-31484
+    *      1C - Handle users deleted in DB and "alive" in backup file:
     *           If match by id and mnethost and user is deleted in DB and
     *           (match by username LIKE 'backup_email.%' or by non empty email = md5(username)) => ok, return target user
-    *      1C - Handle users deleted in backup file and "alive" in DB:
+    *      1D - Handle users deleted in backup file and "alive" in DB:
     *           If match by id and mnethost and user is deleted in backup file
     *           and match by email = email_without_time(backup_email) => ok, return target user
-    *      1D - Conflict: If match by username and mnethost and doesn't match by id => conflict, return false
-    *      1E - None of the above, return true => User needs to be created
+    *      1E - Conflict: If match by username and mnethost and doesn't match by id => conflict, return false
+    *      1F - None of the above, return true => User needs to be created
     *
     *  if restoring from another site backup (cannot match by id here, replace it by email/firstaccess combination):
     *      2A - Normal check: If match by username and mnethost and (email or non-zero firstaccess) => ok, return target user
@@ -1186,7 +1188,16 @@ abstract class restore_dbops {
                 return $rec; // Matching user found, return it
             }
 
-            // 1B - Handle users deleted in DB and "alive" in backup file
+            // 1B - If restoring an 'anonymous' user (created via the 'Anonymize user information' option) try to find a
+            // match by username only => ok, return target user MDL-31484
+            // This avoids username / id mis-match problems when restoring subsequent anonymized backups.
+            if (backup_anonymizer_helper::is_anonymous_user($user)) {
+                if ($rec = $DB->get_record('user', array('username' => $user->username))) {
+                    return $rec; // Matching anonymous user found - return it
+                }
+            }
+
+            // 1C - Handle users deleted in DB and "alive" in backup file
             // Note: for DB deleted users email is stored in username field, hence we
             //       are looking there for emails. See delete_user()
             // Note: for DB deleted users md5(username) is stored *sometimes* in the email field,
@@ -1209,7 +1220,7 @@ abstract class restore_dbops {
                 return $rec; // Matching user, deleted in DB found, return it
             }
 
-            // 1C - Handle users deleted in backup file and "alive" in DB
+            // 1D - Handle users deleted in backup file and "alive" in DB
             // If match by id and mnethost and user is deleted in backup file
             // and match by email = email_without_time(backup_email) => ok, return target user
             if ($user->deleted) {
@@ -1227,7 +1238,7 @@ abstract class restore_dbops {
                 }
             }
 
-            // 1D - If match by username and mnethost and doesn't match by id => conflict, return false
+            // 1E - If match by username and mnethost and doesn't match by id => conflict, return false
             if ($rec = $DB->get_record('user', array('username'=>$user->username, 'mnethostid'=>$user->mnethostid))) {
                 if ($user->id != $rec->id) {
                     return false; // Conflict, username already exists and belongs to another id
index be56d2c..04a9d2d 100644 (file)
  */
 class backup_anonymizer_helper {
 
+    /**
+     * Determine if the given user is an 'anonymous' user, based on their username, firstname, lastname
+     * and email address.
+     * @param stdClass $user the user record to test
+     * @return bool true if this is an 'anonymous' user
+     */
+    public static function is_anonymous_user($user) {
+        if (preg_match('/^anon\d*$/', $user->username)) {
+            $match = preg_match('/^anonfirstname\d*$/', $user->firstname);
+            $match = $match && preg_match('/^anonlastname\d*$/', $user->lastname);
+            $match = $match && preg_match('/^anon\d*@doesntexist\.com$/', $user->email);
+            if ($match) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     public static function process_user_auth($value) {
         return 'manual'; // Set them to manual always
     }
index 8cbe681..ae01911 100644 (file)
@@ -34,6 +34,7 @@ require_once($CFG->dirroot . '/backup/util/interfaces/executable.class.php');
 require_once($CFG->dirroot . '/backup/util/interfaces/processable.class.php');
 require_once($CFG->dirroot . '/backup/backup.class.php');
 require_once($CFG->dirroot . '/backup/util/structure/restore_path_element.class.php');
+require_once($CFG->dirroot . '/backup/util/helper/backup_anonymizer_helper.class.php');
 require_once($CFG->dirroot . '/backup/util/helper/backup_file_manager.class.php');
 require_once($CFG->dirroot . '/backup/util/helper/restore_prechecks_helper.class.php');
 require_once($CFG->dirroot . '/backup/util/helper/restore_moodlexml_parser_processor.class.php');
diff --git a/behat.yml.dist b/behat.yml.dist
new file mode 100644 (file)
index 0000000..60cf807
--- /dev/null
@@ -0,0 +1,14 @@
+default:
+  paths:
+    features: lib/behat/features
+    bootstrap: lib/behat/features/bootstrap
+  context:
+    class: behat_init_context
+  extensions:
+    Behat\MinkExtension\Extension:
+      base_url: 'http://localhost:8000'
+      goutte: null
+      selenium2: null
+    Moodle\BehatExtension\Extension:
+      features: {  }
+      steps_definitions: {  }
index 2e395ce..abe2808 100644 (file)
@@ -42,13 +42,11 @@ class block_calendar_month extends block_base {
         list($courses, $group, $user) = calendar_set_filters($filtercourse);
         if ($issite) {
             // For the front page
-            $this->content->text .= calendar_top_controls('frontpage', array('id' => $courseid, 'm' => $cal_m, 'y' => $cal_y));
-            $this->content->text .= calendar_get_mini($courses, $group, $user, $cal_m, $cal_y);
+            $this->content->text .= calendar_get_mini($courses, $group, $user, $cal_m, $cal_y, 'frontpage', $courseid);
             // No filters for now
         } else {
             // For any other course
-            $this->content->text .= calendar_top_controls('course', array('id' => $courseid, 'm' => $cal_m, 'y' => $cal_y));
-            $this->content->text .= calendar_get_mini($courses, $group, $user, $cal_m, $cal_y);
+            $this->content->text .= calendar_get_mini($courses, $group, $user, $cal_m, $cal_y, 'course', $courseid);
             $this->content->text .= '<h3 class="eventskey">'.get_string('eventskey', 'calendar').'</h3>';
             $this->content->text .= '<div class="filters calendar_filters">'.calendar_filter_controls($this->page->url).'</div>';
         }
index 12f0ea1..b2cb803 100644 (file)
@@ -220,7 +220,7 @@ class block_completionstatus extends block_base {
             $this->content->footer = '<br><a href="'.$details->out().'">'.get_string('moredetails', 'completion').'</a>';
         } else {
             // If user is not enrolled, show error
-            $this->content->text = get_string('notenroled', 'completion');
+            $this->content->text = get_string('nottracked', 'completion');
         }
 
         if (has_capability('report/completion:view', $context)) {
index bb1b051..2b2525a 100644 (file)
@@ -46,25 +46,9 @@ if ($userid) {
 
 
 // Check permissions
-require_login($course);
-
-$coursecontext   = context_course::instance($course->id);
-$personalcontext = context_user::instance($user->id);
-
-$can_view = false;
-
-// Can view own report
-if ($USER->id == $user->id) {
-    $can_view = true;
-} else if (has_capability('moodle/user:viewuseractivitiesreport', $personalcontext)) {
-    $can_view = true;
-} else if (has_capability('report/completion:view', $coursecontext)) {
-    $can_view = true;
-} else if (has_capability('report/completion:view', $personalcontext)) {
-    $can_view = true;
-}
+require_login();
 
-if (!$can_view) {
+if (!completion_can_view_data($user->id, $course)) {
     print_error('cannotviewreport');
 }
 
@@ -107,7 +91,7 @@ echo $OUTPUT->header();
 
 
 // Display completion status
-echo '<table class="generalbox boxaligncenter"><tbody>';
+echo '<table class="generaltable boxaligncenter"><tbody>';
 
 // If not display logged in user, show user name
 if ($USER->id != $user->id) {
@@ -164,7 +148,7 @@ if (empty($completions)) {
     echo '</td></tr></tbody></table>';
 
     // Generate markup for criteria statuses
-    echo '<table class="generalbox logtable boxaligncenter" id="criteriastatus" width="100%"><tbody>';
+    echo '<table class="generaltable logtable boxaligncenter" id="criteriastatus" width="100%"><tbody>';
     echo '<tr class="ccheader">';
     echo '<th class="c0 header" scope="col">'.get_string('criteriagroup', 'block_completionstatus').'</th>';
     echo '<th class="c1 header" scope="col">'.get_string('criteria', 'completion').'</th>';
index 55e0764..775391f 100644 (file)
@@ -85,9 +85,6 @@ class block_course_overview extends block_base {
             // For each course, build category cache.
             $this->content->text .= $renderer->course_overview($sortedcourses, $overviews);
             $this->content->text .= $renderer->hidden_courses($totalcourses - count($sortedcourses));
-            if ($this->page->user_is_editing() && ajaxenabled()) {
-                $this->page->requires->js_init_call('M.block_course_overview.add_handles');
-            }
         }
 
         return $this->content;
index 3535110..36350d9 100644 (file)
@@ -37,7 +37,11 @@ $string['hiddencoursecount'] = 'You have {$a} hidden course';
 $string['hiddencoursecountplural'] = 'You have {$a} hidden courses';
 $string['message'] = 'message';
 $string['messages'] = 'messages';
+$string['movecourse'] = 'Move course: {$a}';
 $string['movecoursehere'] = 'Move course here';
+$string['movetofirst'] = 'Move {$a} course to top';
+$string['moveafterhere'] = 'Move {$a->movingcoursename} course after {$a->currentcoursename}';
+$string['movingcourse'] = 'You are moving: {$a->fullname} ({$a->cancellink})';
 $string['numtodisplay'] = 'Number of courses to display: ';
 $string['otherexpanded'] = 'Other Courses Expanded';
 $string['pluginname'] = 'Course overview';
index 6a6536d..e900df8 100644 (file)
@@ -2,12 +2,23 @@ M.block_course_overview = {}
 
 M.block_course_overview.add_handles = function(Y) {
     M.block_course_overview.Y = Y;
+    var MOVEICON = {
+        pix: "i/move_2d",
+        component: 'moodle'
+    };
+
     YUI().use('dd-constrain', 'dd-proxy', 'dd-drop', 'dd-plugin', function(Y) {
         //Static Vars
         var goingUp = false, lastY = 0;
 
-        var list = Y.Node.all('#course_list .coursebox');
+        var list = Y.Node.all('.course_list .coursebox');
         list.each(function(v, k) {
+            // Replace move link and image with move_2d image.
+            var imagenode = v.one('.course_title .move a img');
+            imagenode.setAttribute('src', M.util.image_url(MOVEICON.pix, MOVEICON.component));
+            imagenode.addClass('cursor');
+            v.one('.course_title .move a').replace(imagenode);
+
             var dd = new Y.DD.Drag({
                 node: v,
                 target: {
@@ -16,18 +27,11 @@ M.block_course_overview.add_handles = function(Y) {
             }).plug(Y.Plugin.DDProxy, {
                 moveOnEnd: false
             }).plug(Y.Plugin.DDConstrained, {
-                constrain2node: '#course_list'
+                constrain2node: '.course_list'
             });
             dd.addHandle('.course_title .move');
         });
 
-        var drops = Y.Node.all('#coursebox');
-        drops.each(function(v, k) {
-            var tar = new Y.DD.Drop({
-                node: v
-            });
-        });
-
         Y.DD.DDM.on('drag:start', function(e) {
             //Get our drag object
             var drag = e.target;
@@ -101,7 +105,7 @@ M.block_course_overview.add_handles = function(Y) {
 
 M.block_course_overview.save = function() {
     var Y = M.block_course_overview.Y;
-    var sortorder = Y.one('#course_list').get('children').getAttribute('id');
+    var sortorder = Y.one('.course_list').get('children').getAttribute('id');
     for (var i = 0; i < sortorder.length; i++) {
         sortorder[i] = sortorder[i].substring(7);
     }
index 8cb7b1b..2b5e74d 100644 (file)
@@ -27,47 +27,34 @@ require_once(dirname(__FILE__) . '/locallib.php');
 require_sesskey();
 require_login();
 
-$source = required_param('source', PARAM_INT);
-$move = required_param('move', PARAM_INT);
-
-list($courses_sorted, $sitecourses, $coursecount) = block_course_overview_get_sorted_courses();
-$sortorder = array_keys($courses_sorted);
-// Now resort based on new weight for chosen course.
-$neworder = array();
-
-$sourcekey = array_search($source, $sortorder);
-if ($sourcekey === false) {
-    print_error("invalidcourseid", null, null, $source);
+$coursetomove = required_param('courseid', PARAM_INT);
+$moveto = required_param('moveto', PARAM_INT);
+
+list($courses, $sitecourses, $coursecount) = block_course_overview_get_sorted_courses();
+$sortedcourses = array_keys($courses);
+
+$currentcourseindex = array_search($coursetomove, $sortedcourses);
+// If coursetomove is not found or moveto < 0 or > count($sortedcourses) then throw error.
+if ($currentcourseindex === false) {
+    print_error("invalidcourseid", null, null, $coursetomove);
+} else if (($moveto < 0) || ($moveto >= count($sortedcourses))) {
+    print_error("invalidaction");
 }
 
-$destination = $sourcekey + $move;
-if ($destination < 0) {
-    print_error("listcantmoveup");
-} else if ($destination >= count($courses_sorted)) {
-    print_error("listcantmovedown");
+// If current course index is same as destination index then don't do anything.
+if ($currentcourseindex === $moveto) {
+    redirect(new moodle_url('/my/index.php'));
 }
 
 // Create neworder list for courses.
-unset($sortorder[$sourcekey]);
-if ($move == -1) {
-    if ($destination > 0) {
-        $neworder = array_slice($sortorder, 0, $destination, true);
-    }
-    $neworder[] = $source;
-    $remaningcourses = array_slice($sortorder, $destination);
-    foreach ($remaningcourses as $courseid) {
-        $neworder[] = $courseid;
-    }
-} else if (($move == 1)) {
-    $neworder = array_slice($sortorder, 0, $destination);
-    $neworder[] = $source;
-    if (($destination) < count($courses_sorted)) {
-        $remaningcourses = array_slice($sortorder, $destination);
-        foreach ($remaningcourses as $courseid) {
-            $neworder[] = $courseid;
-        }
-    }
-}
+$neworder = array();
 
-block_course_overview_update_myorder($neworder);
+unset($sortedcourses[$currentcourseindex]);
+$neworder = array_slice($sortedcourses, 0, $moveto, true);
+$neworder[] = $coursetomove;
+$remaningcourses = array_slice($sortedcourses, $moveto);
+foreach ($remaningcourses as $courseid) {
+    $neworder[] = $courseid;
+}
+block_course_overview_update_myorder(array_values($neworder));
 redirect(new moodle_url('/my/index.php'));
index 8c42428..b0b4507 100644 (file)
@@ -41,67 +41,64 @@ class block_course_overview_renderer extends plugin_renderer_base {
     public function course_overview($courses, $overviews) {
         $html = '';
         $config = get_config('block_course_overview');
-
-        $html .= html_writer::start_tag('div', array('id' => 'course_list'));
+        $ismovingcourse = false;
         $courseordernumber = 0;
         $maxcourses = count($courses);
-        // Intialize string/icon etc if user is editing.
-        $url = null;
-        $moveicon = null;
-        $moveup[] = null;
-        $movedown[] = null;
-        if ($this->page->user_is_editing()) {
+        $userediting = false;
+        // Intialise string/icon etc if user is editing and courses > 1
+        if ($this->page->user_is_editing() && (count($courses) > 1)) {
+            $userediting = true;
+            // If ajaxenabled then include DND JS and replace link with move image.
             if (ajaxenabled()) {
-                $moveicon = html_writer::tag('div',
-                    html_writer::empty_tag('img',
-                        array('src' => $this->pix_url('i/move_2d')->out(false),
-                            'alt' => get_string('move'), 'class' => 'cursor',
-                            'title' => get_string('move'))
-                    ), array('class' => 'move')
-                );
-            } else {
-                $url = new moodle_url('/blocks/course_overview/move.php', array('sesskey' => sesskey()));
-                $moveup['str'] = get_string('moveup');
-                $moveup['icon'] = $this->pix_url('t/up');
-                $movedown['str'] =  get_string('movedown');
-                $movedown['icon'] = $this->pix_url('t/down');
+                $this->page->requires->js_init_call('M.block_course_overview.add_handles');
             }
+
+            // Check if course is moving
+            $ismovingcourse = optional_param('movecourse', FALSE, PARAM_BOOL);
+            $movingcourseid = optional_param('courseid', 0, PARAM_INT);
+        }
+
+        // Render first movehere icon.
+        if ($ismovingcourse) {
+            // Remove movecourse param from url.
+            $this->page->ensure_param_not_in_url('movecourse');
+
+            // Show moving course notice, so user knows what is being moved.
+            $html .= $this->output->box_start('notice');
+            $a = new stdClass();
+            $a->fullname = $courses[$movingcourseid]->fullname;
+            $a->cancellink = html_writer::link($this->page->url, get_string('cancel'));
+            $html .= get_string('movingcourse', 'block_course_overview', $a);
+            $html .= $this->output->box_end();
+
+            $moveurl = new moodle_url('/blocks/course_overview/move.php',
+                        array('sesskey' => sesskey(), 'moveto' => 0, 'courseid' => $movingcourseid));
+            // Create move icon, so it can be used.
+            $movetofirsticon = html_writer::empty_tag('img',
+                    array('src' => $this->output->pix_url('movehere'),
+                        'alt' => get_string('movetofirst', 'block_course_overview', $courses[$movingcourseid]->fullname),
+                        'title' => get_string('movehere')));
+            $moveurl = html_writer::link($moveurl, $movetofirsticon);
+            $html .= html_writer::tag('div', $moveurl, array('class' => 'movehere'));
         }
 
         foreach ($courses as $key => $course) {
+            // If moving course, then don't show course which needs to be moved.
+            if ($ismovingcourse && ($course->id == $movingcourseid)) {
+                continue;
+            }
             $html .= $this->output->box_start('coursebox', "course-{$course->id}");
             $html .= html_writer::start_tag('div', array('class' => 'course_title'));
-            // Ajax enabled then add moveicon html
-            if (!is_null($moveicon)) {
-                $html .= $moveicon;
-            } else if (!is_null($url)) {
-                // Add course id to move link
-                $url->param('source', $course->id);
-                $html .= html_writer::start_tag('div', array('class' => 'moveicons'));
-                // Add an arrow to move course up.
-                if ($courseordernumber > 0) {
-                    $url->param('move', -1);
-                    $html .= html_writer::link($url,
-                    html_writer::empty_tag('img', array('src' => $moveup['icon'],
-                        'class' => 'up', 'alt' => $moveup['str'])),
-                        array('title' => $moveup['str'], 'class' => 'moveup'));
-                } else {
-                    // Add a spacer to keep keep down arrow icons at right position.
-                    $html .= html_writer::empty_tag('img', array('src' => $this->pix_url('spacer'),
-                        'class' => 'movedownspacer'));
-                }
-                // Add an arrow to move course down.
-                if ($courseordernumber <= $maxcourses-2) {
-                    $url->param('move', 1);
-                    $html .= html_writer::link($url, html_writer::empty_tag('img',
-                        array('src' => $movedown['icon'], 'class' => 'down', 'alt' => $movedown['str'])),
-                        array('title' => $movedown['str'], 'class' => 'movedown'));
-                } else {
-                    // Add a spacer to keep keep up arrow icons at right position.
-                    $html .= html_writer::empty_tag('img', array('src' => $this->pix_url('spacer'),
-                        'class' => 'moveupspacer'));
-                }
-                $html .= html_writer::end_tag('div');
+            // If user is editing, then add move icons.
+            if ($userediting && !$ismovingcourse) {
+                $moveicon = html_writer::empty_tag('img',
+                        array('src' => $this->pix_url('t/move')->out(false),
+                            'alt' => get_string('movecourse', 'block_course_overview', $course->fullname),
+                            'title' => get_string('move')));
+                $moveurl = new moodle_url($this->page->url, array('sesskey' => sesskey(), 'movecourse' => 1, 'courseid' => $course->id));
+                $moveurl = html_writer::link($moveurl, $moveicon);
+                $html .= html_writer::tag('div', $moveurl, array('class' => 'move'));
+
             }
 
             $attributes = array('title' => s($course->fullname));
@@ -125,17 +122,30 @@ class block_course_overview_renderer extends plugin_renderer_base {
                 }
             }
 
-            if (isset($overviews[$course->id])) {
+            // If user is moving courses, then down't show overview.
+            if (isset($overviews[$course->id]) && !$ismovingcourse) {
                 $html .= $this->activity_display($course->id, $overviews[$course->id]);
             }
 
             $html .= $this->output->box('', 'flush');
             $html .= $this->output->box_end();
             $courseordernumber++;
+            if ($ismovingcourse) {
+                $moveurl = new moodle_url('/blocks/course_overview/move.php',
+                            array('sesskey' => sesskey(), 'moveto' => $courseordernumber, 'courseid' => $movingcourseid));
+                $a = new stdClass();
+                $a->movingcoursename = $courses[$movingcourseid]->fullname;
+                $a->currentcoursename = $course->fullname;
+                $movehereicon = html_writer::empty_tag('img',
+                        array('src' => $this->output->pix_url('movehere'),
+                            'alt' => get_string('moveafterhere', 'block_course_overview', $a),
+                            'title' => get_string('movehere')));
+                $moveurl = html_writer::link($moveurl, $movehereicon);
+                $html .= html_writer::tag('div', $moveurl, array('class' => 'movehere'));
+            }
         }
-        $html .= html_writer::end_tag('div');
-
-        return $html;
+        // Wrap course list in a div and return.
+        return html_writer::tag('div', $html, array('class' => 'course_list'));
     }
 
     /**
index 6718d06..69905d7 100644 (file)
     padding: 2px 10px;
 }
 
-.editing .block_course_overview .moveicons {
-    display: block;
-    float: left;
-    padding-right: 5px;
-}
-.dir-rtl.editing .block_course_overview .moveicons {
-    float:right;
-}
-
-.editing .block_course_overview .moveup {
-    padding-right: 5px;
-}
-
-.editing .block_course_overview .movedownspacer {
-    float: left;
-    width: 14px;
-}
-.dir-rtl.editing .block_course_overview .movedownspacer {
-    float:right;
-}
-
-.editing .block_course_overview .moveupspacer {
-    float: right;
-    width: 14px;
-}
-.dir-rtl.editing .block_course_overview .moveupspacer {
-    float:left;
-}
-
-.block_course_overview #course_list {
+.block_course_overview .course_list {
     width: 100%;
 }
 
     text-align: right;
 }
 
-.block_course_overview .coursemovetarget {
-    display: block;
-    height: 1em;
-    margin-bottom: 1em;
-    border-width: 2px;
-    border-style: dashed;
+.block_course_overview .content .course_list .movehere{
+    margin-bottom: 15px;
 }
index 40abe52..47d0d36 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012121000;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2013012300;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2012112900;        // Requires this Moodle version
 $plugin->component = 'block_course_overview'; // Full name of the plugin (used for diagnostics)
index 8dfa97f..884c909 100644 (file)
@@ -11,10 +11,6 @@ class block_glossary_random extends block_base {
         $this->title = get_string('pluginname','block_glossary_random');
     }
 
-    function applicable_formats() {
-        return array('all' => true, 'mod' => false, 'tag' => false, 'my' => false);
-    }
-
     function specialization() {
         global $CFG, $DB;
 
index e7bb687..0c1acd6 100644 (file)
@@ -26,6 +26,16 @@ defined('MOODLE_INTERNAL') || die();
 
 $capabilities = array(
 
+    'block/glossary_random:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
     'block/glossary_random:addinstance' => array(
         'riskbitmask' => RISK_SPAM | RISK_XSS,
 
diff --git a/blocks/glossary_random/db/upgrade.php b/blocks/glossary_random/db/upgrade.php
deleted file mode 100644 (file)
index 81aeabe..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * This file keeps track of upgrades to the glossary random block
- *
- * Sometimes, changes between versions involve alterations to database structures
- * and other major things that may break installations.
- *
- * The upgrade function in this file will attempt to perform all the necessary
- * actions to upgrade your older installation to the current version.
- *
- * If there's something it cannot do itself, it will tell you what you need to do.
- *
- * The commands in here will all be database-neutral, using the methods of
- * database_manager class
- *
- * Please do not forget to use upgrade_set_timeout()
- * before any action that may take longer time to finish.
- *
- * @since 2.0
- * @package blocks
- * @copyright 2012 Mark Nelson <markn@moodle.com>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-/**
- * Handles upgrading instances of this block.
- *
- * @param int $oldversion
- * @param object $block
- */
-function xmldb_block_glossary_random_upgrade($oldversion, $block) {
-    global $DB;
-
-    // Moodle v2.4.0 release upgrade line
-    // Put any upgrade step following this.
-
-    if ($oldversion < 2012112901) {
-        // Get the instances of this block.
-        if ($blocks = $DB->get_records('block_instances', array('blockname' => 'glossary_random', 'pagetypepattern' => 'my-index'))) {
-            // Loop through and remove them from the My Moodle page.
-            foreach ($blocks as $block) {
-                blocks_delete_instance($block);
-            }
-
-        }
-
-        // Savepoint reached.
-        upgrade_block_savepoint(true, 2012112901, 'glossary_random');
-    }
-
-
-    return true;
-}
\ No newline at end of file
index 0147f00..6366bd4 100644 (file)
@@ -28,6 +28,7 @@ $string['askaddentry'] = 'When users can add entries to the glossary, show a lin
 $string['askinvisible'] = 'When users cannot edit or view the glossary, show this text (without link)';
 $string['askviewglossary'] = 'When users can view the glossary but not add entries, show a link with this text';
 $string['glossary_random:addinstance'] = 'Add a new random glossary entry block';
+$string['glossary_random:myaddinstance'] = 'Add a new random glossary entry block to the My Moodle page';
 $string['intro'] = 'Make sure you have at least one glossary with at least one entry added to this course. Then you can adjust the following settings';
 $string['invisible'] = '(to be continued)';
 $string['lastmodified'] = 'Last modified entry';
index 061ec44..a5d21fa 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012112901;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012112902;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2012112900;        // Requires this Moodle version
 $plugin->component = 'block_glossary_random'; // Full name of the plugin (used for diagnostics)
index 85f48f3..aa340af 100644 (file)
@@ -7,7 +7,7 @@ class block_mentees extends block_base {
     }
 
     function applicable_formats() {
-        return array('all' => true, 'tag' => false, 'my' => false);
+        return array('all' => true, 'tag' => false);
     }
 
     function specialization() {
index 489ceb3..ba14b07 100644 (file)
@@ -26,6 +26,16 @@ defined('MOODLE_INTERNAL') || die();
 
 $capabilities = array(
 
+    'block/mentees:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
     'block/mentees:addinstance' => array(
         'riskbitmask' => RISK_SPAM | RISK_XSS,
 
diff --git a/blocks/mentees/db/upgrade.php b/blocks/mentees/db/upgrade.php
deleted file mode 100644 (file)
index e8aba71..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * This file keeps track of upgrades to the mentees block
- *
- * Sometimes, changes between versions involve alterations to database structures
- * and other major things that may break installations.
- *
- * The upgrade function in this file will attempt to perform all the necessary
- * actions to upgrade your older installation to the current version.
- *
- * If there's something it cannot do itself, it will tell you what you need to do.
- *
- * The commands in here will all be database-neutral, using the methods of
- * database_manager class
- *
- * Please do not forget to use upgrade_set_timeout()
- * before any action that may take longer time to finish.
- *
- * @since 2.0
- * @package blocks
- * @copyright 2012 Mark Nelson <markn@moodle.com>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-/**
- * Handles upgrading instances of this block.
- *
- * @param int $oldversion
- * @param object $block
- */
-function xmldb_block_mentees_upgrade($oldversion, $block) {
-    global $DB;
-
-    // Moodle v2.4.0 release upgrade line
-    // Put any upgrade step following this.
-
-    if ($oldversion < 2012112901) {
-        // Get the instances of this block.
-        if ($blocks = $DB->get_records('block_instances', array('blockname' => 'mentees', 'pagetypepattern' => 'my-index'))) {
-            // Loop through and remove them from the My Moodle page.
-            foreach ($blocks as $block) {
-                blocks_delete_instance($block);
-            }
-
-        }
-
-        // Savepoint reached.
-        upgrade_block_savepoint(true, 2012112901, 'mentees');
-    }
-
-
-    return true;
-}
\ No newline at end of file
index 1c0cdab..3a22057 100644 (file)
@@ -27,5 +27,6 @@ $string['configtitle'] = 'Block title';
 $string['configtitleblankhides'] = 'Block title (no title if blank)';
 $string['leaveblanktohide'] = 'leave blank to hide the title';
 $string['mentees:addinstance'] = 'Add a new mentees block';
+$string['mentees:myaddinstance'] = 'Add a new mentees block to the My Moodle page';
 $string['newmenteesblock'] = '(new Mentees block)';
 $string['pluginname'] = 'Mentees';
index c3a8db3..7f9e179 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012112901;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012112902;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2012112900;        // Requires this Moodle version
 $plugin->component = 'block_mentees';   // Full name of the plugin (used for diagnostics)
index e803c6e..5ecbec2 100644 (file)
@@ -5,10 +5,6 @@ class block_news_items extends block_base {
         $this->title = get_string('pluginname', 'block_news_items');
     }
 
-    function applicable_formats() {
-        return array('all' => true, 'mod' => false, 'tag' => false, 'my' => false);
-    }
-
     function get_content() {
         global $CFG, $USER;
 
index 452158e..86bb1b7 100644 (file)
@@ -26,6 +26,16 @@ defined('MOODLE_INTERNAL') || die();
 
 $capabilities = array(
 
+    'block/news_items:myaddinstance' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'user' => CAP_ALLOW
+        ),
+
+        'clonepermissionsfrom' => 'moodle/my:manageblocks'
+    ),
+
     'block/news_items:addinstance' => array(
         'riskbitmask' => RISK_SPAM | RISK_XSS,
 
index 1de6507..7d76b9c 100644 (file)
@@ -24,4 +24,5 @@
  */
 
 $string['news_items:addinstance'] = 'Add a new latest news block';
+$string['news_items:myaddinstance'] = 'Add a new latest news block to the My Moodle page';
 $string['pluginname'] = 'Latest news';
index 11d74ca..ba6e931 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2012112901;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2012112902;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2012112900;        // Requires this Moodle version
 $plugin->component = 'block_news_items'; // Full name of the plugin (used for diagnostics)
index 6d14ebb..50ff41a 100644 (file)
@@ -10,10 +10,6 @@ class block_online_users extends block_base {
         $this->title = get_string('pluginname','block_online_users');
     }
 
-    function applicable_formats() {
-        return array('all' => true, 'mod' => false, 'tag' => false, 'my' => false);
-    }
-
     function has_config() {
         return true;
     }