Merge branch 'MDL-35211_M23' of git://github.com/kordan/moodle into MOODLE_23_STABLE
authorSam Hemelryk <sam@moodle.com>
Sun, 7 Oct 2012 22:02:33 +0000 (11:02 +1300)
committerSam Hemelryk <sam@moodle.com>
Sun, 7 Oct 2012 22:02:33 +0000 (11:02 +1300)
518 files changed:
admin/environment.xml
admin/filters.php
admin/mnet/access_control.php
admin/portfolio.php
admin/repository.php
admin/roles/lib.php
admin/roles/usersroles.php
admin/settings/appearance.php
admin/settings/courses.php
admin/settings/location.php
admin/settings/users.php
admin/timezone.php
admin/tool/assignmentupgrade/module.js
admin/tool/langimport/index.php
admin/tool/phpunit/cli/util.php
admin/tool/spamcleaner/index.php
admin/tool/spamcleaner/lang/en/tool_spamcleaner.php
admin/tool/uploaduser/index.php
admin/tool/xmldb/actions/new_table_from_mysql/new_table_from_mysql.class.php
admin/tool/xmldb/actions/view_structure_php/view_structure_php.class.php
admin/tool/xmldb/actions/view_table_php/view_table_php.class.php
auth/cas/config.html
auth/db/auth.php
auth/email/auth.php
auth/fc/config.html
auth/imap/config.html
auth/ldap/auth.php
auth/ldap/config.html
auth/manual/auth.php
auth/mnet/config.html
auth/nntp/config.html
auth/pop3/config.html
auth/radius/config.html
auth/shibboleth/config.html
auth/shibboleth/index_form.html
backup/moodle2/backup_custom_fields.php
backup/moodle2/restore_activity_task.class.php
backup/moodle2/restore_qtype_plugin.class.php
backup/moodle2/restore_section_task.class.php
backup/moodle2/restore_stepslib.php
backup/upgrade.txt [new file with mode: 0644]
backup/util/dbops/backup_plan_dbops.class.php
backup/util/dbops/restore_dbops.class.php
backup/util/helper/backup_cron_helper.class.php
backup/util/helper/tests/cronhelper_test.php [new file with mode: 0644]
backup/util/plan/backup_structure_step.class.php
backup/util/plan/restore_structure_step.class.php
backup/util/structure/backup_nested_element.class.php
backup/util/ui/backup_ui_stage.class.php
backup/util/ui/base_moodleform.class.php
backup/util/ui/restore_ui_stage.class.php
backup/util/ui/yui/backupselectall/backupselectall.js [new file with mode: 0644]
blocks/community/block_community.php
blocks/community/yui/comments/comments.js
blocks/completionstatus/block_completionstatus.php
blocks/completionstatus/details.php
blocks/completionstatus/lang/en/block_completionstatus.php
blocks/course_overview/block_course_overview.php
blocks/dock.js
blocks/navigation/renderer.php
blocks/navigation/yui/navigation/navigation.js
blocks/news_items/block_news_items.php
blocks/rss_client/block_rss_client.php
blocks/section_links/config_instance.html
blocks/settings/renderer.php
blocks/tags/block_tags.php
blocks/tags/lang/en/block_tags.php
blog/edit_form.php
blog/external_blogs.php
blog/lib.php
blog/locallib.php
calendar/event.php
calendar/lib.php
calendar/renderer.php
calendar/yui/eventmanager/eventmanager.js
comment/comment.js
comment/lib.php
course/category.php
course/edit_form.php
course/editsection.php
course/editsection_form.php
course/format/renderer.php
course/format/topics/format.php
course/format/topics/renderer.php
course/format/weeks/format.js
course/format/weeks/format.php
course/index.php
course/lib.php
course/mod.php
course/modduplicate.php
course/modedit.php
course/recent_form.php
course/reset.php
course/reset_form.php
course/rest.php
course/scales.php
course/search.php
course/tests/externallib_test.php
course/view.php
course/yui/dragdrop/dragdrop.js
course/yui/toolboxes/toolboxes.js
enrol/authorize/locallib.php
enrol/category/cli/sync.php
enrol/category/db/access.php
enrol/category/db/events.php
enrol/category/db/install.php
enrol/category/lang/en/enrol_category.php
enrol/category/lib.php
enrol/category/locallib.php
enrol/category/settings.php
enrol/category/tests/sync_test.php [new file with mode: 0644]
enrol/category/version.php
enrol/cohort/lib.php
enrol/cohort/locallib.php
enrol/database/lib.php
enrol/externallib.php
enrol/imsenterprise/lib.php
enrol/ldap/lang/en/enrol_ldap.php
enrol/ldap/settingslib.php
enrol/locallib.php
enrol/manual/lib.php
enrol/manual/locallib.php
enrol/manual/manage.php
enrol/manual/yui/quickenrolment/quickenrolment.js
enrol/paypal/ipn.php
enrol/self/edit_form.php
enrol/self/lang/en/enrol_self.php
enrol/self/lib.php
files/renderer.php
filter/algebra/algebradebug.php
filter/algebra/filter.php
filter/algebra/lang/en/filter_algebra.php
filter/algebra/tests/filter_test.php [new file with mode: 0644]
filter/manage.php
filter/mediaplugin/tests/filter_test.php
grade/edit/outcome/edit.php
grade/edit/tree/calculation.php
grade/edit/tree/category_form.php
grade/edit/tree/index.php
grade/edit/tree/lib.php
grade/grading/form/guide/lib.php
grade/grading/form/guide/preview.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/lib.php
grade/grading/form/rubric/renderer.php
grade/lib.php
grade/report/grader/lib.php
grade/report/user/lib.php
group/lib.php
index.php
install/lang/cs/install.php
install/lang/es/install.php
install/lang/es_mx/install.php
install/lang/es_mx/langconfig.php
install/lang/eu/admin.php
install/lang/fi/admin.php
install/lang/fi/error.php
install/lang/fi/install.php
install/lang/fo/langconfig.php
install/lang/fo/moodle.php [new file with mode: 0644]
install/lang/ga/error.php [new file with mode: 0644]
install/lang/is/admin.php
install/lang/ko/install.php
install/lang/lt/admin.php
install/lang/lt/moodle.php
install/lang/nl/langconfig.php
install/lang/no/install.php
install/lang/pl/admin.php
install/lang/pl/install.php
install/lang/pt/admin.php
install/lang/pt/error.php
install/lang/pt/install.php
install/lang/ru/install.php
install/lang/uk/install.php [new file with mode: 0644]
install/lang/zh_cn/install.php
iplookup/index.php
iplookup/module.js
lang/en/admin.php
lang/en/backup.php
lang/en/block.php
lang/en/calendar.php
lang/en/completion.php
lang/en/message.php
lang/en/moodle.php
lang/en/notes.php
lang/en/repository.php
lang/en/table.php
lib/accesslib.php
lib/adminlib.php
lib/blocklib.php
lib/boxlib.php
lib/completion/completion_completion.php
lib/completionlib.php
lib/conditionlib.php
lib/cronlib.php
lib/datalib.php
lib/db/services.php
lib/db/upgrade.php
lib/db/upgradelib.php
lib/dml/moodle_database.php
lib/dml/mysqli_native_moodle_database.php
lib/dml/tests/dml_test.php
lib/dtl/database_exporter.php
lib/editor/tinymce/lang/en/editor_tinymce.php
lib/editor/tinymce/tiny_mce/3.5.1.1/plugins/moodlemedia/js/media.js
lib/editor/tinymce/tiny_mce/3.5.1.1/plugins/moodlemedia/preview.php
lib/filelib.php
lib/filestorage/file_storage.php
lib/filestorage/stored_file.php
lib/form/editor.php
lib/form/form.js
lib/form/tests/dateselector_test.php
lib/form/tests/datetimeselector_test.php
lib/formslib.php
lib/googleapi.php
lib/grade/grade_category.php
lib/grade/grade_item.php
lib/grade/tests/grade_category_test.php
lib/javascript-static.js
lib/listlib.php
lib/medialib.php
lib/messagelib.php
lib/modinfolib.php
lib/moodlelib.php
lib/navigationlib.php
lib/oauthlib.php
lib/outputcomponents.php
lib/outputrenderers.php
lib/pagelib.php
lib/phpunit/bootstraplib.php
lib/phpunit/classes/data_generator.php
lib/phpunit/classes/hint_resultprinter.php
lib/phpunit/classes/util.php
lib/phpunit/tests/generator_test.php
lib/pluginlib.php
lib/portfoliolib.php
lib/questionlib.php
lib/tablelib.php
lib/tests/backup_test.php [deleted file]
lib/tests/completionlib_test.php
lib/tests/medialib_test.php
lib/tests/moodlelib_test.php
lib/tests/outputcomponents_test.php
lib/tests/pluginlib_test.php
lib/tests/questionlib_test.php
lib/webdavlib.php
lib/yui/blocks/blocks.js
lib/yui/dragdrop/dragdrop.js
lib/yui/formchangechecker/formchangechecker.js
login/index.php
login/token.php
message/edit.php
message/index.php
message/lib.php
message/search.html
mod/assign/backup/moodle2/backup_assign_stepslib.php
mod/assign/feedback/comments/locallib.php
mod/assign/gradingoptionsform.php
mod/assign/gradingtable.php
mod/assign/index.php
mod/assign/lang/en/assign.php
mod/assign/lib.php
mod/assign/locallib.php
mod/assign/mod_form.php
mod/assign/module.js
mod/assign/renderer.php
mod/assignment/assignment.js
mod/assignment/lang/en/assignment.php
mod/assignment/lib.php
mod/assignment/mod_form.php
mod/assignment/type/upload/assignment.class.php
mod/book/backup/moodle2/restore_book_activity_task.class.php
mod/book/lang/en/book.php
mod/book/lib.php
mod/book/tool/print/index.php
mod/book/tool/print/locallib.php
mod/book/version.php
mod/book/view.php
mod/chat/chatd.php
mod/chat/gui_ajax/index.php
mod/chat/gui_header_js/chatinput.php
mod/chat/gui_sockets/chatinput.php
mod/chat/gui_sockets/index.php
mod/chat/lang/en/chat.php
mod/chat/lib.php
mod/choice/backup/moodle2/backup_choice_stepslib.php
mod/choice/backup/moodle2/restore_choice_stepslib.php
mod/data/field.php
mod/data/field/checkbox/mod.html
mod/data/field/file/field.class.php
mod/data/field/latlong/field.class.php
mod/data/field/menu/field.class.php
mod/data/field/menu/mod.html
mod/data/field/multimenu/field.class.php
mod/data/field/multimenu/mod.html
mod/data/field/number/field.class.php
mod/data/field/picture/field.class.php
mod/data/field/picture/mod.html
mod/data/field/radiobutton/field.class.php
mod/data/field/radiobutton/mod.html
mod/data/field/text/field.class.php
mod/data/field/textarea/field.class.php
mod/data/field/textarea/mod.html
mod/data/field/url/field.class.php
mod/data/field/url/mod.html
mod/data/lib.php
mod/data/styles.css
mod/data/templates.php
mod/feedback/analysis_course.php
mod/feedback/edit_form.php
mod/feedback/item/multichoice/lib.php
mod/feedback/item/multichoicerated/lib.php
mod/feedback/item/numeric/lib.php
mod/feedback/lang/en/feedback.php
mod/feedback/lib.php
mod/feedback/mapcourse.php
mod/feedback/show_nonrespondents.php
mod/folder/renderer.php
mod/forum/db/access.php
mod/forum/db/events.php
mod/forum/lang/en/forum.php
mod/forum/lib.php
mod/forum/post.php
mod/forum/version.php
mod/glossary/editcategories.html
mod/glossary/formats.php
mod/glossary/lib.php
mod/glossary/locallib.php
mod/lesson/format.php
mod/lesson/lib.php
mod/lesson/pagetypes/matching.php
mod/lesson/pagetypes/truefalse.php
mod/lesson/report.php
mod/quiz/attempt.php
mod/quiz/attemptlib.php
mod/quiz/backup/moodle1/lib.php
mod/quiz/cronlib.php
mod/quiz/db/install.xml
mod/quiz/db/upgrade.php
mod/quiz/lib.php
mod/quiz/locallib.php
mod/quiz/module.js
mod/quiz/processattempt.php
mod/quiz/renderer.php
mod/quiz/report/attemptsreport_table.php
mod/quiz/report/overview/overviewgraph.php
mod/quiz/report/reportlib.php
mod/quiz/report/responses/responses_table.php
mod/quiz/report/upgrade.txt
mod/quiz/review.php
mod/quiz/styles.css
mod/quiz/tests/locallib_test.php
mod/quiz/version.php
mod/resource/lib.php
mod/scorm/lib.php
mod/scorm/loadSCO.php
mod/scorm/locallib.php
mod/scorm/view.js
mod/wiki/backup/moodle1/lib.php
mod/wiki/db/upgrade.php
mod/wiki/editors/wikieditor.php
mod/wiki/lang/en/wiki.php
mod/wiki/lib.php
mod/wiki/pagelib.php
mod/wiki/parser/markups/wikimarkup.php
mod/wiki/renderer.php
mod/wiki/version.php
mod/workshop/form/comments/backup/moodle1/lib.php
mod/workshop/form/numerrors/backup/moodle1/lib.php
mod/workshop/form/rubric/backup/moodle1/lib.php
my/index.php
phpunit.xml.dist
question/behaviour/behaviourbase.php
question/behaviour/rendererbase.php
question/category_class.php
question/edit.php
question/editlib.php
question/engine/bank.php
question/engine/datalib.php
question/engine/lib.php
question/engine/questionattempt.php
question/engine/questionattemptstep.php
question/engine/questionusage.php
question/engine/tests/questionutils_test.php
question/format.php
question/format/aiken/format.php
question/format/blackboard/format.php
question/format/blackboard/lang/en/qformat_blackboard.php
question/format/blackboard/tests/blackboardformat_test.php [new file with mode: 0644]
question/format/blackboard/tests/fixtures/sample_blackboard.dat [new file with mode: 0644]
question/format/blackboard/version.php
question/format/blackboard_six/format.php
question/format/blackboard_six/formatbase.php [new file with mode: 0644]
question/format/blackboard_six/formatpool.php [new file with mode: 0644]
question/format/blackboard_six/formatqti.php [new file with mode: 0644]
question/format/blackboard_six/lang/en/qformat_blackboard_six.php
question/format/blackboard_six/tests/blackboardformatpool_test.php [new file with mode: 0644]
question/format/blackboard_six/tests/blackboardsixformatqti_test.php [new file with mode: 0644]
question/format/blackboard_six/tests/fixtures/sample_blackboard_pool.dat [new file with mode: 0644]
question/format/blackboard_six/tests/fixtures/sample_blackboard_qti.dat [new file with mode: 0644]
question/format/blackboard_six/version.php
question/format/examview/format.php
question/format/examview/lang/en/qformat_examview.php
question/format/examview/tests/examviewformat_test.php [new file with mode: 0644]
question/format/examview/tests/fixtures/examview_sample.xml [new file with mode: 0644]
question/format/examview/tests/fixtures/questions.examview.xml [new file with mode: 0644]
question/format/examview/version.php
question/format/gift/format.php
question/format/learnwise/format.php
question/format/missingword/format.php
question/format/multianswer/format.php
question/format/multianswer/tests/fixtures/questions.multianswer.txt [new file with mode: 0644]
question/format/multianswer/tests/multianswerformat_test.php [new file with mode: 0644]
question/format/webct/format.php
question/format/xhtml/format.php
question/format/xml/format.php
question/preview.php
question/previewlib.php
question/tests/importexport_test.php
question/type/calculated/lang/en/qtype_calculated.php
question/type/calculated/questiontype.php
question/type/calculatedmulti/styles.css
question/type/edit_question_form.php
question/type/essay/db/upgrade.php
question/type/essay/renderer.php
question/type/match/lang/en/qtype_match.php
question/type/match/renderer.php
question/type/match/styles.css
question/type/multianswer/lang/en/qtype_multianswer.php
question/type/multianswer/questiontype.php
question/type/multianswer/renderer.php
question/type/multianswer/styles.css
question/type/multianswer/tests/helper.php
question/type/multianswer/tests/walkthrough_test.php
question/type/multichoice/lang/en/qtype_multichoice.php
question/type/multichoice/styles.css
question/type/numerical/lang/en/qtype_numerical.php
question/type/numerical/question.php
question/type/numerical/renderer.php
question/type/numerical/tests/answer_test.php
question/type/numerical/tests/question_test.php
question/type/shortanswer/lang/en/qtype_shortanswer.php
question/type/shortanswer/question.php
question/type/shortanswer/questiontype.php
question/type/shortanswer/renderer.php
report/backups/index.php
report/courseoverview/index.php
report/log/lang/en/report_log.php
report/log/locallib.php
report/participation/index.php
report/stats/lib.php
report/stats/locallib.php
report/stats/settings.php
repository/alfresco/lib.php
repository/boxnet/lib.php
repository/dropbox/db/upgrade.php [new file with mode: 0644]
repository/dropbox/lang/en/repository_dropbox.php
repository/dropbox/lib.php
repository/dropbox/locallib.php
repository/dropbox/thumbnail.php [new file with mode: 0644]
repository/dropbox/version.php
repository/equella/lib.php
repository/filepicker.js
repository/filepicker.php
repository/filesystem/lib.php
repository/flickr/lib.php
repository/flickr_public/lib.php
repository/googledocs/lib.php
repository/lib.php
repository/manage_instances.php
repository/repository_ajax.php
repository/s3/README_MOODLE.txt [new file with mode: 0644]
repository/s3/S3.php
repository/s3/lib.php
repository/webdav/lib.php
tag/coursetags_edit.php
tag/edit.php
tag/lib.php
tag/locallib.php
tag/manage.php
theme/afterburner/style/afterburner_styles.css
theme/anomaly/config.php
theme/anomaly/pix/menu/nav-arrow-left.jpg [new file with mode: 0644]
theme/anomaly/pix/menu/nav-arrow-right.jpg [new file with mode: 0644]
theme/anomaly/pix/menu/nav-arrowover-left.jpg [new file with mode: 0644]
theme/anomaly/pix/menu/nav-arrowover-right.jpg [new file with mode: 0644]
theme/anomaly/renderers.php
theme/anomaly/style/general.css
theme/anomaly/style/menu.css [new file with mode: 0644]
theme/base/style/admin.css
theme/base/style/core.css
theme/canvas/config.php
theme/formal_white/layout/frontpage.php
theme/formal_white/layout/general.php
theme/formal_white/layout/report.php
theme/formal_white/settings.php
theme/formal_white/style/formal_white.css
theme/formal_white/style/pagelayout.css
theme/fusion/style/pagelayout.css
theme/mymobile/config.php
theme/mymobile/layout/general.php
theme/mymobile/style/jmobile11_rtl.css [new file with mode: 0644]
theme/standard/style/core.css
theme/yui_combo.php
user/addnote.php
user/editadvanced_form.php
user/externallib.php
user/groupaddnote.php
user/index.php
user/lib.php
user/message.html
user/profile.php
user/selector/lib.php
user/selector/module.js
user/tests/externallib_test.php [new file with mode: 0644]
version.php
webservice/lib.php

index 004cab0..584a9b0 100644 (file)
         </FEEDBACK>
       </PHP_SETTING>
     </PHP_SETTINGS>
-</MOODLE>
+  </MOODLE>
+  <MOODLE version="2.4" requires="2.2">
+    <UNICODE level="required">
+      <FEEDBACK>
+        <ON_ERROR message="unicoderequired" />
+      </FEEDBACK>
+    </UNICODE>
+    <DATABASE level="required">
+      <VENDOR name="mysql" version="5.1.33" />
+      <VENDOR name="postgres" version="8.3" />
+      <VENDOR name="mssql" version="9.0" />
+      <VENDOR name="odbc_mssql" version="9.0" />
+      <VENDOR name="mssql_n" version="9.0" />
+      <VENDOR name="oracle" version="10.2" />
+      <VENDOR name="sqlite" version="2.0" />
+    </DATABASE>
+    <PHP version="5.3.2" level="required">
+    </PHP>
+    <PCREUNICODE level="optional">
+      <FEEDBACK>
+        <ON_CHECK message="pcreunicodewarning" />
+      </FEEDBACK>
+    </PCREUNICODE>
+    <PHP_EXTENSIONS>
+      <PHP_EXTENSION name="iconv" level="required">
+        <FEEDBACK>
+          <ON_CHECK message="iconvrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="mbstring" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="mbstringrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="curl" level="required">
+        <FEEDBACK>
+          <ON_CHECK message="curlrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="openssl" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="opensslrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="tokenizer" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="tokenizerrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="xmlrpc" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="xmlrpcrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="soap" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="soaprecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="ctype" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="ctyperequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="zip" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="ziprequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="gd" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="gdrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="simplexml" level="required">
+        <FEEDBACK>
+          <ON_CHECK message="simplexmlrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="spl" level="required">
+        <FEEDBACK>
+          <ON_CHECK message="splrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="pcre" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="dom" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="xml" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="intl" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="intlrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="json" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="hash" level="required"/>
+    </PHP_EXTENSIONS>
+    <PHP_SETTINGS>
+      <PHP_SETTING name="memory_limit" value="40M" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="settingmemorylimit" />
+        </FEEDBACK>
+      </PHP_SETTING>
+      <PHP_SETTING name="safe_mode" value="0" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="settingsafemode" />
+        </FEEDBACK>
+      </PHP_SETTING>
+      <PHP_SETTING name="file_uploads" value="1" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="settingfileuploads" />
+        </FEEDBACK>
+      </PHP_SETTING>
+    </PHP_SETTINGS>
+  </MOODLE>
 </COMPATIBILITY_MATRIX>
index 0d7faa3..39a15a8 100644 (file)
@@ -242,6 +242,7 @@ function get_table_row($filterinfo, $isfirstrow, $islastactive, $applytostrings)
 
     // Disable/off/on
     $select = new single_select(filters_action_url($filter, 'setstate'), 'newstate', $activechoices, $filterinfo->active, null, 'active' . basename($filter));
+    $select->set_label(get_string('isactive', 'filters'), array('class' => 'accesshide'));
     $row[] = $OUTPUT->render($select);
 
     // Re-order
@@ -263,6 +264,7 @@ function get_table_row($filterinfo, $isfirstrow, $islastactive, $applytostrings)
 
     // Apply to strings.
     $select = new single_select(filters_action_url($filter, 'setapplyto'), 'stringstoo', $applytochoices, $applytostrings, null, 'applyto' . basename($filter));
+    $select->set_label(get_string('applyto', 'filters'), array('class' => 'accesshide'));
     $select->disabled = $filterinfo->active == TEXTFILTER_DISABLED;
     $row[] = $OUTPUT->render($select);
 
index b9e436f..e820489 100644 (file)
@@ -203,17 +203,18 @@ echo get_string('username') . ":\n";
 if (!empty($formerror['username'])) {
     echo '<span class="error"> * </span>';
 }
-echo '<input type="text" name="username" size="20" maxlength="100" />';
+echo html_writer::label(get_string('username'), 'menuusername', false, array('class' => 'accesshide'));
+echo '<input id="menuusername" type="text" name="username" size="20" maxlength="100" />';
 
 // choose a remote host
-echo " " . get_string('remotehost', 'mnet') . ":\n";
+echo " " . html_writer::label(get_string('remotehost', 'mnet'), 'menumnet_host_id') . ":\n";
 if (!empty($formerror['mnet_host_id'])) {
     echo '<span class="error"> * </span>';
 }
 echo html_writer::select($mnethosts, 'mnet_host_id');
 
 // choose an access level
-echo " " . get_string('accesslevel', 'mnet') . ":\n";
+echo " " . html_writer::label(get_string('accesslevel', 'mnet'), 'menuaccessctrl') . ":\n";
 if (!empty($formerror['accessctrl'])) {
     echo '<span class="error"> * </span>';
 }
index 791c79f..9536942 100644 (file)
@@ -197,6 +197,7 @@ if (($action == 'edit') || ($action == 'new')) {
                 $currentaction = 'hide';
             }
             $select = new single_select(portfolio_action_url($pluginid, 'pf'), 'action', $actionchoicesforexisting, $currentaction, null, 'applyto' . $pluginid);
+            $select->set_label(get_string('action'), array('class' => 'accesshide'));
             $table->data[] = array($pluginname, $OUTPUT->render($select), $settings);
         }
         if (!in_array($plugin, $usedplugins)) {
@@ -218,6 +219,7 @@ if (($action == 'edit') || ($action == 'new')) {
                 $insaneplugins[] = $p;
             } else {
                 $select = new single_select(portfolio_action_url($p, 'pf'), 'action', $actionchoicesfornew, 'delete', null, 'applyto' . $p);
+                $select->set_label(get_string('action'), array('class' => 'accesshide'));
                 $table->data[] = array(portfolio_static_function($p, 'get_name'), $OUTPUT->render($select), '');
             }
         }
index b3494ca..04ce40e 100644 (file)
@@ -352,7 +352,7 @@ if (($action == 'edit') || ($action == 'new')) {
             }
 
             $select = new single_select(repository_action_url($typename, 'repos'), 'action', $actionchoicesforexisting, $currentaction, null, 'applyto' . basename($typename));
-
+            $select->set_label(get_string('action'), array('class' => 'accesshide'));
             // Display up/down link
             $updown = '';
             $spacer = $OUTPUT->spacer(array('height'=>15, 'width'=>15)); // should be done with CSS instead
@@ -389,6 +389,7 @@ if (($action == 'edit') || ($action == 'new')) {
             // Check that it has not already been listed
             if (!in_array($plugin, $alreadyplugins)) {
                 $select = new single_select(repository_action_url($plugin, 'repos'), 'action', $actionchoicesfornew, 'delete', null, 'applyto' . basename($plugin));
+                $select->set_label(get_string('action'), array('class' => 'accesshide'));
                 $table->data[] = array(get_string('pluginname', 'repository_'.$plugin), $OUTPUT->render($select), '', '');
             }
         }
index d57233f..93703c8 100644 (file)
@@ -1042,12 +1042,10 @@ class potential_assignees_below_course extends role_assign_user_selector_base {
         $countfields = 'SELECT COUNT(u.id)';
 
         $sql   = " FROM {user} u
-                  WHERE u.id IN ($enrolsql) $wherecondition
-                        AND u.id NOT IN (
-                           SELECT r.userid
-                             FROM {role_assignments} r
-                            WHERE r.contextid = :contextid
-                                  AND r.roleid = :roleid)";
+              LEFT JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.roleid = :roleid AND ra.contextid = :contextid)
+                  WHERE u.id IN ($enrolsql)
+                        $wherecondition
+                        AND ra.id IS NULL";
         $order = ' ORDER BY lastname ASC, firstname ASC';
 
         $params['contextid'] = $this->context->id;
index 968f025..3ac05f9 100644 (file)
@@ -166,7 +166,8 @@ function print_report_tree($contextid, $contexts, $systemcontext, $fullname) {
     $context = context::instance_by_id($contextid);
 
     // Print the context name.
-    echo $OUTPUT->heading($context->get_context_name(), 4, 'contextname');
+    echo $OUTPUT->heading(html_writer::link($context->get_url(), $context->get_context_name()),
+            4, 'contextname');
 
     // If there are any role assignments here, print them.
     foreach ($contexts[$contextid]->roleassignments as $ra) {
@@ -189,7 +190,7 @@ function print_report_tree($contextid, $contexts, $systemcontext, $fullname) {
             }
             $a = new stdClass;
             $a->fullname = $fullname;
-            $a->contextlevel = get_contextlevel_name($context->contextlevel);
+            $a->contextlevel = $context->get_level_name();
             if ($context->contextlevel == CONTEXT_SYSTEM) {
                 $strgoto = get_string('gotoassignsystemroles', 'role');
                 $strcheck = get_string('checksystempermissionsfor', 'role', $a);
index b0272b8..9995af3 100644 (file)
@@ -185,6 +185,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     $setting = new admin_setting_configcheckbox('cachejs', new lang_string('cachejs', 'admin'), new lang_string('cachejs_help', 'admin'), 1);
     $setting->set_updatedcallback('js_reset_all_caches');
     $temp->add($setting);
+    $temp->add(new admin_setting_configcheckbox('modchooserdefault', new lang_string('modchooserdefault', 'admin'), new lang_string('configmodchooserdefault', 'admin'), 1));
     $ADMIN->add('appearance', $temp);
 
     // link to tag management interface
index 92722eb..aec5102 100644 (file)
@@ -35,10 +35,11 @@ if ($hassiteconfig
     $temp->add(new admin_setting_configselect('moodlecourse/showgrades', new lang_string('showgrades'), new lang_string('coursehelpshowgrades'), 1,array(0 => new lang_string('no'), 1 => new lang_string('yes'))));
     $temp->add(new admin_setting_configselect('moodlecourse/showreports', new lang_string('showreports'), '', 0,array(0 => new lang_string('no'), 1 => new lang_string('yes'))));
 
+    $currentmaxbytes = get_config('moodlecourse', 'maxbytes');
     if (isset($CFG->maxbytes)) {
-        $choices = get_max_upload_sizes($CFG->maxbytes);
+        $choices = get_max_upload_sizes($CFG->maxbytes, 0, 0, $currentmaxbytes);
     } else {
-        $choices = get_max_upload_sizes();
+        $choices = get_max_upload_sizes(0, 0, 0, $currentmaxbytes);
     }
     $temp->add(new admin_setting_configselect('moodlecourse/maxbytes', new lang_string('maximumupload'), new lang_string('coursehelpmaximumupload'), key($choices), $choices));
 
@@ -47,6 +48,11 @@ if ($hassiteconfig
         $temp->add(new admin_setting_configselect('moodlecourse/legacyfiles', new lang_string('courselegacyfiles'), new lang_string('courselegacyfiles_help'), key($choices), $choices));
     }
 
+    $choices = array();
+    $choices[COURSE_DISPLAY_SINGLEPAGE] = new lang_string('coursedisplay_single');
+    $choices[COURSE_DISPLAY_MULTIPAGE] = new lang_string('coursedisplay_multi');
+    $temp->add(new admin_setting_configselect('moodlecourse/coursedisplay', new lang_string('coursedisplay'), new lang_string('coursedisplay_help'), COURSE_DISPLAY_SINGLEPAGE, $choices));
+
     $temp->add(new admin_setting_heading('groups', new lang_string('groups', 'group'), ''));
     $choices = array();
     $choices[NOGROUPS] = new lang_string('groupsnone', 'group');
index 3d3ccb8..9f74d51 100644 (file)
@@ -14,7 +14,8 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
 
     $temp->add(new admin_setting_heading('iplookup', new lang_string('iplookup', 'admin'), new lang_string('iplookupinfo', 'admin')));
     $temp->add(new admin_setting_configfile('geoipfile', new lang_string('geoipfile', 'admin'), new lang_string('configgeoipfile', 'admin', $CFG->dataroot.'/geoip/'), $CFG->dataroot.'/geoip/GeoLiteCity.dat'));
-    $temp->add(new admin_setting_configtext('googlemapkey', new lang_string('googlemapkey', 'admin'), new lang_string('configgooglemapkey', 'admin', $CFG->wwwroot), ''));
+    $temp->add(new admin_setting_configtext('googlemapkey', new lang_string('googlemapkey', 'admin'), new lang_string('configgooglemapkey', 'admin', $CFG->wwwroot), '', PARAM_RAW, 60));
+    $temp->add(new admin_setting_configtext('googlemapkey3', new lang_string('googlemapkey3', 'admin'), new lang_string('googlemapkey3_help', 'admin'), '', PARAM_RAW, 60));
 
     $temp->add(new admin_setting_configtext('allcountrycodes', new lang_string('allcountrycodes', 'admin'), new lang_string('configallcountrycodes', 'admin'), '', '/^(?:\w+(?:,\w+)*)?$/'));
 
index f317102..232745d 100644 (file)
@@ -150,6 +150,7 @@ if ($hassiteconfig
                     'institution' => new lang_string('institution'),
                 )));
         $temp->add(new admin_setting_configcheckbox('enablegravatar', new lang_string('enablegravatar', 'admin'), new lang_string('enablegravatar_help', 'admin'), 0));
+        $temp->add(new admin_setting_configtext('gravatardefaulturl', new lang_string('gravatardefaulturl', 'admin'), new lang_string('gravatardefaulturl_help', 'admin'), 'mm'));
     }
 
     $ADMIN->add('roles', $temp);
index e031be4..3bbe8d1 100644 (file)
@@ -44,7 +44,7 @@
     $timezones = get_list_of_timezones();
 
     echo '<center><form action="timezone.php" method="post">';
-    echo "$strusers ($strall): ";
+    echo html_writer::label($strusers . ' (' . $strall . '): ', 'menuzone');
     echo html_writer::select($timezones, "zone", $current, array('99'=>get_string("serverlocaltime")));
     echo "<input type=\"hidden\" name=\"sesskey\" value=\"".sesskey()."\" />";
     echo '<input type="submit" value="'.s($strsavechanges).'" />';
index edee839..59df8c5 100644 (file)
@@ -42,8 +42,8 @@ M.tool_assignmentupgrade = {
             }
         });
 
-        var batchform = Y.one('.tool_assignmentupgrade_batchform form');
-        batchform.on('submit', function(e) {
+        var upgradeselectedbutton = Y.one('#id_upgradeselected');
+        upgradeselectedbutton.on('click', function(e) {
             checkboxes = Y.all('td.c0 input');
             var selectedassignments = [];
             checkboxes.each(function(node) {
index 80d8829..82b5cc2 100644 (file)
@@ -287,7 +287,7 @@ $url = new moodle_url('/admin/tool/langimport/index.php', array('mode' => DELETI
 echo html_writer::start_tag('td', array('valign' => 'top'));
 echo html_writer::start_tag('form', array('id' => 'uninstallform', 'action' => $url->out(), 'method' => 'post'));
 echo html_writer::start_tag('fieldset');
-echo html_writer::label(get_string('installedlangs', 'tool_langimport'), 'uninstalllang');
+echo html_writer::label(get_string('installedlangs', 'tool_langimport'), 'menuuninstalllang');
 echo html_writer::empty_tag('br');
 echo html_writer::select($installedlangs, 'uninstalllang', '', false, array('size' => 15));
 echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
@@ -315,7 +315,7 @@ if (!empty($options)) {
     $url = new moodle_url('/admin/tool/langimport/index.php', array('mode' => INSTALLATION_OF_SELECTED_LANG));
     echo html_writer::start_tag('form', array('id' => 'installform', 'action' => $url->out(), 'method' => 'post'));
     echo html_writer::start_tag('fieldset');
-    echo html_writer::label(get_string('availablelangs','install'), 'pack');
+    echo html_writer::label(get_string('availablelangs','install'), 'menupack');
     echo html_writer::empty_tag('br');
     echo html_writer::select($options, 'pack[]', '', false, array('size' => 15, 'multiple' => 'multiple'));
     echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
index 2986d64..5afd3ba 100644 (file)
@@ -150,7 +150,7 @@ if ($diag) {
 } else if ($drop) {
     // make sure tests do not run in parallel
     phpunit_util::acquire_test_lock();
-    phpunit_util::drop_site();
+    phpunit_util::drop_site(true);
     // note: we must stop here because $CFG is messed up and we can not reinstall, sorry
     exit(0);
 
index 443f5cd..0835270 100644 (file)
@@ -96,6 +96,7 @@ echo $OUTPUT->box_start();     // The forms section at the top
 
 <form method="post" action="index.php">
   <div>
+    <label class="accesshide" for="keyword_el"><?php print_string('spamkeyword', 'tool_spamcleaner') ?></label>
     <input type="text" name="keyword" id="keyword_el" value="<?php p($keyword) ?>" />
     <input type="hidden" name="sesskey" value="<?php echo sesskey();?>" />
     <input type="submit" value="<?php echo get_string('spamsearch', 'tool_spamcleaner')?>" />
index 5a86357..df6b4a3 100644 (file)
@@ -38,6 +38,7 @@ $string['spamfromcomments'] = 'From comments:';
 $string['spamfrommessages'] = 'From messages:';
 $string['spamfromforumpost'] = 'From forum post:';
 $string['spaminvalidresult'] = 'Unknown but invalid result';
+$string['spamkeyword'] = 'Keyword';
 $string['spamoperation'] = 'Operation';
 $string['spamresult'] = 'Results of searching user profiles containing:';
 $string['spamsearch'] = 'Search for these keywords';
index ec692e2..380db45 100644 (file)
@@ -857,6 +857,8 @@ if ($formdata = $mform2->is_cancelled()) {
                         if ($duration > 0) { // sanity check
                             $timeend = $today + $duration;
                         }
+                    } else if ($manualcache[$courseid]->enrolperiod > 0) {
+                        $timeend = $today + $manualcache[$courseid]->enrolperiod;
                     }
 
                     $manual->enrol_user($manualcache[$courseid], $user->id, $rid, $today, $timeend);
index 4dca286..8332d21 100644 (file)
@@ -113,7 +113,7 @@ class new_table_from_mysql extends XMLDBAction {
             $o.= '    <input type="hidden" name ="postaction" value="edit_table" />';
             $o.= '    <input type="hidden" name ="sesskey" value="' . sesskey() . '" />';
             $o.= '    <table id="formelements" class="boxaligncenter" cellpadding="5">';
-            $o.= '      <tr><td><label for="table" accesskey="t">' . $this->str['createtable'] .' </label>' . html_writer::select($selecttables, 'table') . '<label for="after" accesskey="a">' . $this->str['aftertable'] . ' </label>' .html_writer::select($aftertables, 'after') . '</td></tr>';
+            $o.= '      <tr><td><label for="menutable" accesskey="t">' . $this->str['createtable'] .' </label>' . html_writer::select($selecttables, 'table') . '<label for="menuafter" accesskey="a">' . $this->str['aftertable'] . ' </label>' .html_writer::select($aftertables, 'after') . '</td></tr>';
             $o.= '      <tr><td colspan="2" align="center"><input type="submit" value="' .$this->str['create'] . '" /></td></tr>';
             $o.= '      <tr><td colspan="2" align="center"><a href="index.php?action=edit_xml_file&amp;dir=' . urlencode(str_replace($CFG->dirroot, '', $dirpath)) . '">[' . $this->str['back'] . ']</a></td></tr>';
             $o.= '    </table>';
index 11d779c..0ddf559 100644 (file)
@@ -114,7 +114,7 @@ class view_structure_php extends XMLDBAction {
         $o.= '    <input type="hidden" name ="dir" value="' . str_replace($CFG->dirroot, '', $dirpath) . '" />';
         $o.= '    <input type="hidden" name ="action" value="view_structure_php" />';
         $o.= '    <table id="formelements" class="boxaligncenter" cellpadding="5">';
-        $o.= '      <tr><td><label for="action" accesskey="c">' . $this->str['selectaction'] .' </label>' . html_writer::select($popcommands, 'command', $commandparam, false) . '&nbsp;<label for="table" accesskey="t">' . $this->str['selecttable'] . ' </label>' .html_writer::select($poptables, 'table', $tableparam, false) . '</td></tr>';
+        $o.= '      <tr><td><label for="menucommand" accesskey="c">' . $this->str['selectaction'] .' </label>' . html_writer::select($popcommands, 'command', $commandparam, false) . '&nbsp;<label for="menutable" accesskey="t">' . $this->str['selecttable'] . ' </label>' .html_writer::select($poptables, 'table', $tableparam, false) . '</td></tr>';
         $o.= '      <tr><td colspan="2" align="center"><input type="submit" value="' .$this->str['view'] . '" /></td></tr>';
         $o.= '    </table>';
         $o.= '</div></form>';
index 132c881..235056f 100644 (file)
@@ -163,7 +163,7 @@ class view_table_php extends XMLDBAction {
         $o.= '    <input type="hidden" name ="table" value="' . s($tableparam) . '" />';
         $o.= '    <input type="hidden" name ="action" value="view_table_php" />';
         $o.= '    <table id="formelements" class="boxaligncenter" cellpadding="5">';
-        $o.= '      <tr><td><label for="action" accesskey="c">' . $this->str['selectaction'] .' </label>' . html_writer::select($popcommands, 'command', $commandparam, false) . '&nbsp;<label for="fieldkeyindex" accesskey="f">' . $this->str['selectfieldkeyindex'] . ' </label>' .html_writer::select($popfields, 'fieldkeyindex', $origfieldkeyindexparam, false) . '</td></tr>';
+        $o.= '      <tr><td><label for="menucommand" accesskey="c">' . $this->str['selectaction'] .' </label>' . html_writer::select($popcommands, 'command', $commandparam, false) . '&nbsp;<label for="menufieldkeyindex" accesskey="f">' . $this->str['selectfieldkeyindex'] . ' </label>' .html_writer::select($popfields, 'fieldkeyindex', $origfieldkeyindexparam, false) . '</td></tr>';
         $o.= '      <tr><td colspan="2" align="center"><input type="submit" value="' .$this->str['view'] . '" /></td></tr>';
         $o.= '    </table>';
         $o.= '</div></form>';
index 4781cb9..28557dd 100644 (file)
@@ -94,9 +94,9 @@ $yesno = array( get_string('no'), get_string('yes') );
     </td>
 </tr>
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_cas_hostname_key', 'auth_cas') ?>:</td>
+    <td align="right"><label for="hostname"><?php print_string('auth_cas_hostname_key', 'auth_cas') ?>: </label></td>
     <td>
-        <input name="hostname" type="text" size="30" value="<?php echo $config->hostname ?>" />
+        <input name="hostname" id="hostname" type="text" size="30" value="<?php echo $config->hostname ?>" />
         <?php if (isset($err['hostname'])) { echo $OUTPUT->error_text($err['hostname']); } ?>
     </td>
     <td>
@@ -105,10 +105,10 @@ $yesno = array( get_string('no'), get_string('yes') );
 </tr>
 <tr valign="top" class="required">
     <td align="right">
-        <?php print_string('auth_cas_baseuri_key', 'auth_cas') ?>:
+        <label for="baseuri"><?php print_string('auth_cas_baseuri_key', 'auth_cas') ?>: </label>
     </td>
     <td>
-        <input name="baseuri" type="text" size="30" value="<?php echo $config->baseuri ?>" />
+        <input name="baseuri" id="baseuri" type="text" size="30" value="<?php echo $config->baseuri ?>" />
         <?php if (isset($err['baseuri'])) { echo $OUTPUT->error_text($err['baseuri']); } ?>
     </td>
     <td>
@@ -117,10 +117,10 @@ $yesno = array( get_string('no'), get_string('yes') );
 </tr>
 <tr valign="top" class="required">
     <td align="right">
-        <?php print_string('auth_cas_port_key', 'auth_cas') ?>:
+        <label for="port"><?php print_string('auth_cas_port_key', 'auth_cas') ?>: </label>
     </td>
     <td>
-        <input name="port" type="text" size="30" value="<?php echo $config->port ?>" />
+        <input name="port" id="port" type="text" size="30" value="<?php echo $config->port ?>" />
         <?php if (isset($err['port'])) { echo $OUTPUT->error_text($err['port']); } ?>
     </td>
     <td>
@@ -129,7 +129,7 @@ $yesno = array( get_string('no'), get_string('yes') );
 </tr>
 <tr valign="top" class="required">
     <td align="right">
-        <?php print_string('auth_cas_casversion', 'auth_cas') ?>:
+        <?php echo html_writer::label(get_string('auth_cas_casversion', 'auth_cas'), 'menucasversion'); ?>:
     </td>
     <td>
         <?php
@@ -145,7 +145,7 @@ $yesno = array( get_string('no'), get_string('yes') );
     </td>
 </tr>
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_cas_language_key', 'auth_cas') ?>:</td>
+    <td align="right"><?php echo html_writer::label(get_string('auth_cas_language_key', 'auth_cas'), 'menulanguage'); ?>:</td>
     <td>
         <?php echo html_writer::select($CASLANGUAGES, 'language', $config->language, false); ?>
     </td>
@@ -155,7 +155,7 @@ $yesno = array( get_string('no'), get_string('yes') );
 </tr>
 <tr valign="top" class="required">
     <td align="right">
-        <?php print_string('auth_cas_proxycas_key', 'auth_cas') ?>:
+        <?php echo html_writer::label(get_string('auth_cas_proxycas_key', 'auth_cas'), 'menuproxycas'); ?>:
     </td>
     <td>
         <?php echo html_writer::select($yesno, 'proxycas', $config->proxycas, false); ?>
@@ -165,7 +165,7 @@ $yesno = array( get_string('no'), get_string('yes') );
     </td>
 </tr>
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_cas_logoutcas_key', 'auth_cas') ?>:</td>
+    <td align="right"><?php echo html_writer::label(get_string('auth_cas_logoutcas_key', 'auth_cas'), 'menulogoutcas'); ?>:</td>
     <td>
         <?php echo html_writer::select($yesno, 'logoutcas', $config->logoutcas, false); ?>
     </td>
@@ -174,7 +174,7 @@ $yesno = array( get_string('no'), get_string('yes') );
     </td>
 </tr>
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_cas_multiauth_key', 'auth_cas') ?>:</td>
+    <td align="right"><?php echo html_writer::label(get_string('auth_cas_multiauth_key', 'auth_cas'), 'menumultiauth'); ?>:</td>
     <td>
         <?php echo html_writer::select($yesno, 'multiauth', $config->multiauth, false); ?>
     </td>
@@ -183,7 +183,7 @@ $yesno = array( get_string('no'), get_string('yes') );
     </td>
 </tr>
 <tr valign="top"  class="required">
-    <td align="right"><?php print_string('auth_cas_certificate_check_key', 'auth_cas') ?>:</td>
+    <td align="right"><?php echo html_writer::label(get_string('auth_cas_certificate_check_key', 'auth_cas'), 'menucertificate_check'); ?>:</td>
     <td>
         <?php echo html_writer::select($yesno, 'certificate_check', $config->certificate_check, false); ?>
     </td>
@@ -192,7 +192,7 @@ $yesno = array( get_string('no'), get_string('yes') );
     </td>
 </tr>
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_cas_certificate_path_key', 'auth_cas') ?>:</td>
+    <td align="right"><label for="certificate_path"><?php print_string('auth_cas_certificate_path_key', 'auth_cas') ?>: </label></td>
     <td>
         <input name="certificate_path" id="certificate_path" type="text" size="30" value="<?php echo $config->certificate_path ?>" />
         <?php if (isset($err['certificate_path'])) echo $OUTPUT->error_text($err['certificate_path']); ?>
@@ -219,7 +219,7 @@ $yesno = array( get_string('no'), get_string('yes') );
     </td>
 </tr>
 <tr valign="top" class="required">
-    <td align="right"><label for="menuversion"><?php print_string('auth_ldap_version_key', 'auth_ldap') ?></label></td>
+    <td align="right"><label for="menuldap_version"><?php print_string('auth_ldap_version_key', 'auth_ldap') ?></label></td>
     <td>
         <?php
              $versions = array();
index 5709513..5882bcf 100644 (file)
@@ -65,7 +65,7 @@ class auth_plugin_db extends auth_plugin_base {
                 $authdb->Close();
                 // user exists externally
                 // check username/password internally
-                if ($user = $DB->get_record('user', array('username'=>$username, 'mnethostid'=>$CFG->mnet_localhost_id))) {
+                if ($user = $DB->get_record('user', array('username'=>$username, 'mnethostid'=>$CFG->mnet_localhost_id, 'auth'=>$this->authtype))) {
                     return validate_internal_user_password($user, $password);
                 }
             } else {
@@ -191,8 +191,16 @@ class auth_plugin_db extends auth_plugin_base {
      * @return bool                  True on success
      */
     function user_update_password($user, $newpassword) {
+        global $DB;
+
         if ($this->is_internal()) {
-            return update_internal_user_password($user, $newpassword);
+            $puser = $DB->get_record('user', array('id'=>$user->id), '*', MUST_EXIST);
+            if (update_internal_user_password($puser, $newpassword)) {
+                $user->password = $puser->password;
+                return true;
+            } else {
+                return false;
+            }
         } else {
             // we should have never been called!
             return false;
@@ -346,7 +354,7 @@ class auth_plugin_db extends auth_plugin_base {
             if ($verbose) {
                 mtrace(get_string('auth_dbuserstoadd','auth_db',count($add_users)));
             }
-            $transaction = $DB->start_delegated_transaction();
+            // Do not use transactions around this foreach, we want to skip problematic users, not revert everything.
             foreach($add_users as $user) {
                 $username = $user;
                 $user = $this->get_userinfo_asobj($user);
@@ -372,9 +380,16 @@ class auth_plugin_db extends auth_plugin_base {
                 } else {
                     $user->timecreated = time();
                     $user->timemodified = $user->timecreated;
-                    $id = $DB->insert_record ('user', $user); // it is truly a new user
-                    if ($verbose) {
-                        mtrace("\t".get_string('auth_dbinsertuser', 'auth_db', array('name'=>$user->username, 'id'=>$id)));
+                    try {
+                        $id = $DB->insert_record('user', $user); // it is truly a new user
+                        if ($verbose) {
+                            mtrace("\t".get_string('auth_dbinsertuser', 'auth_db', array('name'=>$user->username, 'id'=>$id)));
+                        }
+                    } catch (moodle_exception $e) {
+                        if ($verbose) {
+                            mtrace("\t".get_string('auth_dbinsertusererror', 'auth_db', $user->username));
+                        }
+                        continue;
                     }
                     // if relevant, tag for password generation
                     if ($this->is_internal()) {
@@ -383,7 +398,6 @@ class auth_plugin_db extends auth_plugin_base {
                     }
                 }
             }
-            $transaction->allow_commit();
             unset($add_users); // free mem
         }
         return 0;
index 0051aaf..e50c09e 100644 (file)
@@ -132,7 +132,9 @@ class auth_plugin_email extends auth_plugin_base {
 
             } else if ($user->secret == $confirmsecret) {   // They have provided the secret key to get in
                 $DB->set_field("user", "confirmed", 1, array("id"=>$user->id));
-                $DB->set_field("user", "firstaccess", time(), array("id"=>$user->id));
+                if ($user->firstaccess == 0) {
+                    $DB->set_field("user", "firstaccess", time(), array("id"=>$user->id));
+                }
                 return AUTH_CONFIRM_OK;
             }
         } else {
index 91dd8c8..0d0da60 100644 (file)
@@ -27,9 +27,9 @@
 <table cellspacing="0" cellpadding="5" border="0">
 
 <tr valign="top" class="required">
-    <td align="right"><?php  print_string("auth_fchost_key", "auth_fc") ?>:</td>
+    <td align="right"><label for="host"><?php print_string("auth_fchost_key", "auth_fc") ?>:</label></td>
     <td>
-        <input name="host" type="text" size="30" value="<?php echo $config->host?>" />
+        <input name="host" id="host" type="text" size="30" value="<?php echo $config->host?>" />
     <?php  if (isset($err["host"])) echo $OUTPUT->error_text($err["host"]); ?>
     </td>
     <td>
@@ -38,9 +38,9 @@
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php  print_string("auth_fcfppport_key", "auth_fc") ?>:</td>
+    <td align="right"><label for="fppport"><?php  print_string("auth_fcfppport_key", "auth_fc") ?>: </label></td>
     <td>
-        <input name="fppport" type="text" size="30" value="<?php echo $config->fppport?>" />
+        <input name="fppport" id="fppport" type="text" size="30" value="<?php echo $config->fppport?>" />
     <?php  if (isset($err["fppport"])) echo $OUTPUT->error_text($err["host"]); ?>
     </td>
     <td>
@@ -49,9 +49,9 @@
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php  print_string("auth_fcuserid_key", "auth_fc") ?>:</td>
+    <td align="right"><label for="userid"><?php  print_string("auth_fcuserid_key", "auth_fc") ?>:</label></td>
     <td>
-        <input name="userid" type="text" size="30" maxlength="15" value="<?php echo $config->userid?>" />
+        <input name="userid" id="userid" type="text" size="30" maxlength="15" value="<?php echo $config->userid?>" />
     <?php  if (isset($err["userid"])) echo $OUTPUT->error_text($err["userid"]); ?>
     </td>
     <td>
@@ -59,9 +59,9 @@
     </td>
 </tr>
 <tr valign="top" class="required">
-    <td align="right"><?php  print_string("auth_fcpasswd_key", "auth_fc") ?>:</td>
+    <td align="right"><label for="passwd"><?php print_string("auth_fcpasswd_key", "auth_fc") ?>:</label></td>
     <td>
-        <input name="passwd" type="password" size="30" maxlength="12" value="<?php echo $config->passwd?>" />
+        <input name="passwd" id="passwd" type="password" size="30" maxlength="12" value="<?php echo $config->passwd?>" />
     <?php  if (isset($err["passwd"])) echo $OUTPUT->error_text($err["passwd"]); ?>
     </td>
     <td>
@@ -70,9 +70,9 @@
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php  print_string("auth_fccreators_key", "auth_fc") ?>:</td>
+    <td align="right"><label for="creators"><?php  print_string("auth_fccreators_key", "auth_fc") ?>: </label></td>
     <td>
-        <input name="creators" type="text" size="30" value="<?php echo $config->creators?>" />
+        <input name="creators" id="creators" type="text" size="30" value="<?php echo $config->creators?>" />
     <?php  if (isset($err["creators"])) echo $OUTPUT->error_text($err["creators"]); ?>
     </td>
     <td>
@@ -81,9 +81,9 @@
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string('auth_fcchangepasswordurl', 'auth_fc') ?>: </td>
+    <td align="right"><label for="changepasswordurl"><?php print_string('auth_fcchangepasswordurl', 'auth_fc') ?>: </label></td>
     <td>
-        <input name="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
+        <input name="changepasswordurl" id="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
         <?php
 
         if (isset($err['changepasswordurl'])) {
index d88ad3a..e36fdd0 100644 (file)
@@ -18,9 +18,9 @@ if (!isset($config->changepasswordurl)) {
 <table cellspacing="0" cellpadding="5" border="0">
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_imaphost_key', 'auth_imap') ?>: </td>
+    <td align="right"><label for="host"><?php print_string('auth_imaphost_key', 'auth_imap') ?>: </label></td>
     <td>
-        <input name="host" type="text" size="30" value="<?php echo $config->host ?>" />
+        <input name="host" id="host" type="text" size="30" value="<?php echo $config->host ?>" />
         <?php
 
         if (isset($err['host'])) {
@@ -40,7 +40,7 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_imaptype_key', 'auth_imap') ?>: </td>
+    <td align="right"><?php echo html_writer::label(get_string('auth_imaptype_key', 'auth_imap'), 'menutype'); ?>: </td>
     <td>
         <?php
 
@@ -56,9 +56,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_imapport_key', 'auth_imap') ?>: </td>
+    <td align="right"><label for="port"><?php print_string('auth_imapport_key', 'auth_imap') ?>: </label></td>
     <td>
-        <input name="port" type="text" size="6" value="<?php echo $config->port ?>" />
+        <input name="port" id="port" type="text" size="6" value="<?php echo $config->port ?>" />
         <?php
 
         if (isset($err['port'])) {
@@ -71,9 +71,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string('auth_imapchangepasswordurl_key', 'auth_imap') ?>: </td>
+    <td align="right"><label for="changepasswordurl"><?php print_string('auth_imapchangepasswordurl_key', 'auth_imap') ?>: </label></td>
     <td>
-        <input name="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
+        <input name="changepasswordurl" id="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
         <?php
 
         if (isset($err['changepasswordurl'])) {
index bc90ebc..88bb10d 100644 (file)
@@ -546,7 +546,9 @@ class auth_plugin_ldap extends auth_plugin_base {
                     return AUTH_CONFIRM_FAIL;
                 }
                 $DB->set_field('user', 'confirmed', 1, array('id'=>$user->id));
-                $DB->set_field('user', 'firstaccess', time(), array('id'=>$user->id));
+                if ($user->firstaccess == 0) {
+                    $DB->set_field('user', 'firstaccess', time(), array('id'=>$user->id));
+                }
                 return AUTH_CONFIRM_OK;
             }
         } else {
index 72519c7..8ad27ef 100644 (file)
@@ -118,7 +118,7 @@ $yesno = array(get_string('no'), get_string('yes'));
 </tr>
 <tr valign="top" class="required">
     <td align="right">
-        <label for="menuversion"><?php print_string('auth_ldap_version_key', 'auth_ldap') ?></label>
+        <label for="menuldap_version"><?php print_string('auth_ldap_version_key', 'auth_ldap') ?></label>
     </td>
     <td>
         <?php
index e3df78a..29cb59a 100644 (file)
@@ -170,7 +170,9 @@ class auth_plugin_manual extends auth_plugin_base {
                 return AUTH_CONFIRM_ALREADY;
             } else {
                 $DB->set_field("user", "confirmed", 1, array("id"=>$user->id));
-                $DB->set_field("user", "firstaccess", time(), array("id"=>$user->id));
+                if ($user->firstaccess == 0) {
+                    $DB->set_field("user", "firstaccess", time(), array("id"=>$user->id));
+                }
                 return AUTH_CONFIRM_OK;
             }
         } else  {
index 2dbba3f..c25b314 100644 (file)
@@ -22,9 +22,9 @@ if (empty($CFG->mnet_dispatcher_mode) || $CFG->mnet_dispatcher_mode !== 'strict'
 <table cellspacing="0" cellpadding="5">
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('rpc_negotiation_timeout', 'auth_mnet'); ?>: </td>
+    <td align="right"><label for="rpc_negotiation_timeout"><?php print_string('rpc_negotiation_timeout', 'auth_mnet'); ?>: </label></td>
     <td>
-        <input name="rpc_negotiation_timeout" type="text" size="5" value="<?php echo $config->rpc_negotiation_timeout ?>" />
+        <input name="rpc_negotiation_timeout" id="rpc_negotiation_timeout" type="text" size="5" value="<?php echo $config->rpc_negotiation_timeout ?>" />
         <?php
 
         if (isset($err['rpc_negotiation_timeout'])) {
@@ -45,7 +45,7 @@ if (empty($CFG->mnet_dispatcher_mode) || $CFG->mnet_dispatcher_mode !== 'strict'
 <?php /*
  See MDL-21327   for why this is commented out
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auto_add_remote_users', 'auth_mnet'); ?>: </td>
+    <td align="right"><?php echo html_writer::label(get_string('auto_add_remote_users', 'auth_mnet'), 'menuauto_add_remote_users'); ?>: </td>
     <td>
         <?php
 
index 179efdd..c9ed4c5 100644 (file)
@@ -15,9 +15,9 @@ if (!isset($config->changepasswordurl)) {
 <table cellspacing="0" cellpadding="5" border="0">
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_nntphost_key', 'auth_nntp') ?>: </td>
+    <td align="right"><label for="host"><?php print_string('auth_nntphost_key', 'auth_nntp') ?>: </label></td>
     <td>
-        <input name="host" type="text" size="30" value="<?php echo $config->host ?>" />
+        <input name="host" id="host" type="text" size="30" value="<?php echo $config->host ?>" />
         <?php
 
         if (isset($err["host"])) {
@@ -37,9 +37,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_nntpport_key', 'auth_nntp') ?>: </td>
+    <td align="right"><label for="port"><?php print_string('auth_nntpport_key', 'auth_nntp') ?>: </label></td>
     <td>
-        <input name="port" type="text" size="6" value="<?php echo $config->port ?>" />
+        <input name="port" id="port" type="text" size="6" value="<?php echo $config->port ?>" />
         <?php
 
         if (isset($err["port"])) {
@@ -52,9 +52,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string('auth_nntpchangepasswordurl_key', 'auth_nntp') ?>: </td>
+    <td align="right"><label for="changepasswordurl"><?php print_string('auth_nntpchangepasswordurl_key', 'auth_nntp') ?>: </label></td>
     <td>
-        <input name="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
+        <input name="changepasswordurl" id="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
         <?php
 
         if (isset($err['changepasswordurl'])) {
index e2d7e7a..1f21e67 100644 (file)
@@ -21,9 +21,9 @@ if (!isset($config->changepasswordurl)) {
 <table cellspacing="0" cellpadding="5" border="0">
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_pop3host_key', 'auth_pop3') ?>: </td>
+    <td align="right"><label for="host"><?php print_string('auth_pop3host_key', 'auth_pop3') ?>: </label></td>
     <td>
-        <input name="host" type="text" size="30" value="<?php echo $config->host ?>" />
+        <input name="host" id="host" type="text" size="30" value="<?php echo $config->host ?>" />
         <?php
 
         if (isset($err['host'])) {
@@ -43,7 +43,7 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_pop3type_key', 'auth_pop3') ?>: </td>
+    <td align="right"><?php echo html_writer::label(get_string('auth_pop3type_key', 'auth_pop3'), 'menutype'); ?>: </td>
     <td>
         <?php
 
@@ -59,9 +59,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_pop3port_key', 'auth_pop3') ?>: </td>
+    <td align="right"><label for="port"><?php print_string('auth_pop3port_key', 'auth_pop3') ?>: </label></td>
     <td>
-        <input name="port" type="text" size="6" value="<?php echo $config->port ?>" />
+        <input name="port" id="port" type="text" size="6" value="<?php echo $config->port ?>" />
         <?php
 
         if (isset($err['port'])) {
@@ -74,9 +74,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string('auth_pop3mailbox_key', 'auth_pop3') ?>: </td>
+    <td align="right"><label for="mailbox"><?php print_string('auth_pop3mailbox_key', 'auth_pop3') ?>: </label></td>
     <td>
-        <input name="mailbox" type="text" size="6" value="<?php echo $config->mailbox ?>" />
+        <input name="mailbox" id="mailbox" type="text" size="6" value="<?php echo $config->mailbox ?>" />
         <?php
 
         if (isset($err['mailbox'])) {
@@ -89,9 +89,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string('auth_pop3changepasswordurl_key', 'auth_pop3') ?>: </td>
+    <td align="right"><label for="changepasswordurl"><?php print_string('auth_pop3changepasswordurl_key', 'auth_pop3') ?>: </label></td>
     <td>
-        <input name="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
+        <input name="changepasswordurl" id="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
         <?php
 
         if (isset($err['changepasswordurl'])) {
index 5973c34..103bb20 100644 (file)
@@ -30,9 +30,9 @@ if (!isset($config->changepasswordurl)) {
 <table cellspacing="0" cellpadding="5" border="0">
 
 <tr valign="top">
-    <td align="right"><?php print_string('auth_radiushost_key', 'auth_radius') ?>: </td>
+    <td align="right"><label for="host"><?php print_string('auth_radiushost_key', 'auth_radius') ?>: </label></td>
     <td>
-        <input name="host" type="text" size="30" value="<?php echo $config->host ?>" />
+        <input name="host" id="host" type="text" size="30" value="<?php echo $config->host ?>" />
         <?php
 
         if (isset($err['host'])) {
@@ -45,9 +45,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string('auth_radiusnasport_key', 'auth_radius') ?>: </td>
+    <td align="right"><label for="nasport"><?php print_string('auth_radiusnasport_key', 'auth_radius') ?>: </label></td>
     <td>
-        <input name="nasport" type="text" size="6" value="<?php echo $config->nasport ?>" />
+        <input name="nasport" id="nasport" type="text" size="6" value="<?php echo $config->nasport ?>" />
         <?php
 
         if (isset($err['nasport'])) {
@@ -60,7 +60,7 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top" >
-    <td align="right"><?php print_string('auth_radiustype_key', 'auth_radius') ?>: </td>
+    <td align="right"><?php echo html_writer::label(get_string('auth_radiustype_key', 'auth_radius'), 'menuradiustype'); ?>: </td>
     <td>
 <?php
 
@@ -82,9 +82,9 @@ if (!isset($config->changepasswordurl)) {
 
 
 <tr valign="top" >
-    <td align="right"><?php print_string('auth_radiussecret_key', 'auth_radius') ?>: </td>
+    <td align="right"><label for="secret"><?php print_string('auth_radiussecret_key', 'auth_radius') ?>: </label></td>
     <td>
-        <input name="secret" type="text" size="6" value="<?php echo $config->secret ?>" />
+        <input name="secret" id="secret" type="text" size="6" value="<?php echo $config->secret ?>" />
         <?php
 
         if (isset($err['secret'])) {
@@ -97,9 +97,9 @@ if (!isset($config->changepasswordurl)) {
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string('auth_radiuschangepasswordurl_key', 'auth_radius') ?>: </td>
+    <td align="right"><label for="changepasswordurl"><?php print_string('auth_radiuschangepasswordurl_key', 'auth_radius') ?>: </label></td>
     <td>
-        <input name="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
+        <input name="changepasswordurl" id="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
         <?php
 
         if (isset($err['changepasswordurl'])) {
index 18dfdea..9a1854f 100644 (file)
 <table cellspacing="0" cellpadding="5" border="0">
 
 <tr valign="top" class="required">
-    <td align="right"><?php print_string("username") ?>:</td>
+    <td align="right"><label for="user_attribute"><?php print_string("username") ?>: </label></td>
     <td>
-        <input name="user_attribute" type="text" size="30" value="<?php echo $config->user_attribute ?>" />
+        <input id="user_attribute" name="user_attribute" type="text" size="30" value="<?php echo $config->user_attribute ?>" />
     </td>
     <td><?php print_string("auth_shib_username_description", "auth_shibboleth") ?></td>
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string("auth_shib_convert_data", "auth_shibboleth") ?>:</td>
+    <td align="right"><label for="convert_data"><?php print_string("auth_shib_convert_data", "auth_shibboleth") ?>: </label></td>
     <td>
-        <input name="convert_data" type="text" size="30" value="<?php echo $config->convert_data?>" />
+        <input name="convert_data" id="convert_data" type="text" size="30" value="<?php echo $config->convert_data?>" />
         <?php
 
         if ($config->convert_data and $config->convert_data != '' and !is_readable($config->convert_data)) {
@@ -82,9 +82,9 @@ urn:mace:organization2:providerID, Example Organization 2, /Shibboleth.sso/WAYF/
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string("auth_shib_logout_url", "auth_shibboleth") ?>:</td>
+    <td align="right"><label for="logout_handler"><?php print_string("auth_shib_logout_url", "auth_shibboleth") ?>: </label></td>
     <td>
-        <input name="logout_handler" type="text" size="30" value="<?php
+        <input name="logout_handler" id="logout_handler" type="text" size="30" value="<?php
         if ( isset($config->logout_handler) and !empty($config->logout_handler)){
             echo $config->logout_handler;
         }
@@ -94,9 +94,9 @@ urn:mace:organization2:providerID, Example Organization 2, /Shibboleth.sso/WAYF/
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string("auth_shib_logout_return_url", "auth_shibboleth") ?>:</td>
+    <td align="right"><label for="logout_return_url"><?php print_string("auth_shib_logout_return_url", "auth_shibboleth") ?>: </label></td>
     <td>
-        <input name="logout_return_url" type="text" size="30" value="<?php
+        <input name="logout_return_url" id="logout_return_url" type="text" size="30" value="<?php
         if ( isset($config->logout_return_url) and !empty($config->logout_return_url)){
             echo $config->logout_return_url;
         }
@@ -106,9 +106,9 @@ urn:mace:organization2:providerID, Example Organization 2, /Shibboleth.sso/WAYF/
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string("auth_shib_auth_method", "auth_shibboleth") ?>:</td>
+    <td align="right"><label for="login_name"><?php print_string("auth_shib_auth_method", "auth_shibboleth") ?>: </label></td>
     <td>
-        <input name="login_name" type="text" size="30" value="<?php
+        <input name="login_name" id="login_name" type="text" size="30" value="<?php
         if ( isset($config->login_name) and !empty($config->login_name)){
             echo htmlentities($config->login_name);
         } else {
@@ -120,9 +120,9 @@ urn:mace:organization2:providerID, Example Organization 2, /Shibboleth.sso/WAYF/
 </tr>
 
 <tr valign="top">
-    <td align="right"><?php print_string('auth_shib_changepasswordurl', 'auth_shibboleth') ?>: </td>
+    <td align="right"><label for="changepasswordurl"><?php print_string('auth_shib_changepasswordurl', 'auth_shibboleth') ?>: </label></td>
     <td>
-        <input name="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
+        <input name="changepasswordurl" id="changepasswordurl" type="text" value="<?php echo $config->changepasswordurl ?>" />
         <?php
 
         if (isset($err['changepasswordurl'])) {
index 423faa0..1e93cf2 100644 (file)
@@ -29,9 +29,9 @@ if ($show_instructions) {
 
         ?>
           <div class="guestsub">
-          <p><?php print_string("auth_shibboleth_select_organization", "auth_shibboleth"); ?></p>
+          <p><label for="idp"><?php print_string("auth_shibboleth_select_organization", "auth_shibboleth"); ?></label></p>
             <form action="login.php" method="post" id="guestlogin">
-            <select name="idp">
+            <select id="idp" name="idp">
                 <option value="-" ><?php print_string("auth_shibboleth_select_member", "auth_shibboleth"); ?></option>
                 <?php
                     print_idp_list();
index e0ceb33..12929de 100644 (file)
@@ -96,14 +96,19 @@ class file_nested_element extends backup_nested_element {
         if (is_null($this->backupid)) {
             $this->backupid = $processor->get_var(backup::VAR_BACKUPID);
         }
-        parent::process($processor);
+        return parent::process($processor);
     }
 
     public function fill_values($values) {
         // Fill values
         parent::fill_values($values);
         // Do our own tasks (copy file from moodle to backup)
-        backup_file_manager::copy_file_moodle2backup($this->backupid, $values);
+        try {
+            backup_file_manager::copy_file_moodle2backup($this->backupid, $values);
+        } catch (file_exception $e) {
+            $this->add_result(array('missing_files_in_pool' => true));
+            $this->add_log('missing file in pool: ' . $e->debuginfo, backup::LOG_WARNING);
+        }
     }
 }
 
index 6917b33..5838a8e 100644 (file)
@@ -293,30 +293,46 @@ abstract class restore_activity_task extends restore_task {
         // Define activity_userinfo. Dependent of:
         // - users root setting
         // - section_userinfo setting (if exists)
-        // - activity_included setting
+        // - activity_included setting.
         $settingname = $settingprefix . 'userinfo';
-        $selectvalues = array(0=>get_string('no')); // Safer options
-        $defaultvalue = false;                      // Safer default
+        $defaultvalue = false;
         if (isset($this->info->settings[$settingname]) && $this->info->settings[$settingname]) { // Only enabled when available
-            $selectvalues = array(1=>get_string('yes'), 0=>get_string('no'));
             $defaultvalue = true;
         }
+
         $activity_userinfo = new restore_activity_userinfo_setting($settingname, base_setting::IS_BOOLEAN, $defaultvalue);
-        $activity_userinfo->set_ui(new backup_setting_ui_select($activity_userinfo, get_string('includeuserinfo','backup'), $selectvalues));
+        if (!$defaultvalue) {
+            // This is a bit hacky, but if there is no user data to restore, then
+            // we replace the standard check-box with a select menu with the
+            // single choice 'No', and the select menu is clever enough that if
+            // there is only one choice, it just displays a static string.
+            //
+            // It would probably be better design to have a special UI class
+            // setting_ui_checkbox_or_no, rather than this hack, but I am not
+            // going to do that today.
+            $activity_userinfo->set_ui(new backup_setting_ui_select($activity_userinfo, '-',
+                    array(0 => get_string('no'))));
+        } else {
+            $activity_userinfo->get_ui()->set_label('-');
+        }
+
         $this->add_setting($activity_userinfo);
+
         // Look for "users" root setting
         $users = $this->plan->get_setting('users');
         $users->add_dependency($activity_userinfo);
+
         // Look for "section_userinfo" section setting (if exists)
         $settingname = 'section_' . $this->info->sectionid . '_userinfo';
         if ($this->plan->setting_exists($settingname)) {
             $section_userinfo = $this->plan->get_setting($settingname);
             $section_userinfo->add_dependency($activity_userinfo);
         }
-        // Look for "activity_included" setting
+
+        // Look for "activity_included" setting.
         $activity_included->add_dependency($activity_userinfo);
 
-        // End of common activity settings, let's add the particular ones
+        // End of common activity settings, let's add the particular ones.
         $this->define_my_settings();
     }
 
index 40b06ac..99365ba 100644 (file)
@@ -154,6 +154,22 @@ abstract class restore_qtype_plugin extends restore_plugin {
                        AND ' . $DB->sql_compare_text('answer', 255) . ' = ' . $DB->sql_compare_text('?', 255);
             $params = array($newquestionid, $data->answertext);
             $newitemid = $DB->get_field_sql($sql, $params);
+
+            // Not able to find the answer, let's try cleaning the answertext
+            // of all the question answers in DB as slower fallback. MDL-30018.
+            if (!$newitemid) {
+                $params = array('question' => $newquestionid);
+                $answers = $DB->get_records('question_answers', $params, '', 'id, answer');
+                foreach ($answers as $answer) {
+                    // Clean in the same way than {@link xml_writer::xml_safe_utf8()}.
+                    $clean = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is','', $answer->answer); // Clean CTRL chars.
+                    $clean = preg_replace("/\r\n|\r/", "\n", $clean); // Normalize line ending.
+                    if ($clean === $data->answertext) {
+                        $newitemid = $data->id;
+                    }
+                }
+            }
+
             // If we haven't found the newitemid, something has gone really wrong, question in DB
             // is missing answers, exception
             if (!$newitemid) {
index 9d48778..9112ea7 100644 (file)
@@ -169,21 +169,36 @@ class restore_section_task extends restore_task {
 
         // Define section_userinfo. Dependent of:
         // - users root setting
-        // - section_included setting
+        // - section_included setting.
         $settingname = $settingprefix . 'userinfo';
-        $selectvalues = array(0=>get_string('no')); // Safer options
-        $defaultvalue = false;                      // Safer default
+        $defaultvalue = false;
         if (isset($this->info->settings[$settingname]) && $this->info->settings[$settingname]) { // Only enabled when available
-            $selectvalues = array(1=>get_string('yes'), 0=>get_string('no'));
             $defaultvalue = true;
         }
+
         $section_userinfo = new restore_section_userinfo_setting($settingname, base_setting::IS_BOOLEAN, $defaultvalue);
-        $section_userinfo->set_ui(new backup_setting_ui_select($section_userinfo, get_string('includeuserinfo','backup'), $selectvalues));
+        if (!$defaultvalue) {
+            // This is a bit hacky, but if there is no user data to restore, then
+            // we replace the standard check-box with a select menu with the
+            // single choice 'No', and the select menu is clever enough that if
+            // there is only one choice, it just displays a static string.
+            //
+            // It would probably be better design to have a special UI class
+            // setting_ui_checkbox_or_no, rather than this hack, but I am not
+            // going to do that today.
+            $section_userinfo->set_ui(new backup_setting_ui_select($section_userinfo, get_string('includeuserinfo','backup'),
+                    array(0 => get_string('no'))));
+        } else {
+            $section_userinfo->get_ui()->set_label(get_string('includeuserinfo','backup'));
+        }
+
         $this->add_setting($section_userinfo);
-        // Look for "users" root setting
+
+        // Look for "users" root setting.
         $users = $this->plan->get_setting('users');
         $users->add_dependency($section_userinfo);
-        // Look for "section_included" section setting
+
+        // Look for "section_included" section setting.
         $section_included->add_dependency($section_userinfo);
     }
 }
index adb3cd6..dbd2c14 100644 (file)
@@ -270,7 +270,14 @@ class restore_gradebook_structure_step extends restore_structure_step {
 
         $data->contextid = get_context_instance(CONTEXT_COURSE, $this->get_courseid())->id;
 
-        $newitemid = $DB->insert_record('grade_letters', $data);
+        $gradeletter = (array)$data;
+        unset($gradeletter['id']);
+        if (!$DB->record_exists('grade_letters', $gradeletter)) {
+            $newitemid = $DB->insert_record('grade_letters', $data);
+        } else {
+            $newitemid = $data->id;
+        }
+
         $this->set_mapping('grade_letter', $oldid, $newitemid);
     }
     protected function process_grade_setting($data) {
@@ -1737,6 +1744,23 @@ class restore_calendarevents_structure_step extends restore_structure_step {
                 return;
             }
         }
+        // Handle events with empty eventtype //MDL-32827
+        if(empty($data->eventtype)) {
+            if ($data->courseid == $SITE->id) {                                // Site event
+                $data->eventtype = "site";
+            } else if ($data->courseid != 0 && $data->groupid == 0 && ($data->modulename == 'assignment' || $data->modulename == 'assign')) {
+                // Course assingment event
+                $data->eventtype = "due";
+            } else if ($data->courseid != 0 && $data->groupid == 0) {      // Course event
+                $data->eventtype = "course";
+            } else if ($data->groupid) {                                      // Group event
+                $data->eventtype = "group";
+            } else if ($data->userid) {                                       // User event
+                $data->eventtype = "user";
+            } else {
+                return;
+            }
+        }
 
         $params = array(
                 'name'           => $data->name,
@@ -2384,17 +2408,21 @@ class restore_activity_grades_structure_step extends restore_structure_step {
 
     /**
      * process activity grade_letters. Note that, while these are possible,
-     * because grade_letters are contextid based, in proctice, only course
+     * because grade_letters are contextid based, in practice, only course
      * context letters can be defined. So we keep here this method knowing
      * it won't be executed ever. gradebook restore will restore course letters.
      */
     protected function process_grade_letter($data) {
         global $DB;
 
-        $data = (object)$data;
+        $data['contextid'] = $this->task->get_contextid();
+        $gradeletter = (object)$data;
 
-        $data->contextid = $this->task->get_contextid();
-        $newitemid = $DB->insert_record('grade_letters', $data);
+        // Check if it exists before adding it
+        unset($data['id']);
+        if (!$DB->record_exists('grade_letters', $data)) {
+            $newitemid = $DB->insert_record('grade_letters', $gradeletter);
+        }
         // no need to save any grade_letter mapping
     }
 }
diff --git a/backup/upgrade.txt b/backup/upgrade.txt
new file mode 100644 (file)
index 0000000..cb02095
--- /dev/null
@@ -0,0 +1,17 @@
+This files describes API changes in /backup/*,
+information provided here is intended especially for developers.
+
+=== 2.4 ===
+
+* Since 2.3.1+ the backup file name schema has changed. The ID of the course will always be part of
+    the filename regardless of the setting 'backup_shortname'. See MDL-33812.
+
+=== 2.3 ===
+
+* Since 2.3.1+ the backup file name schema has changed. The ID of the course will always be part of
+    the filename regardless of the setting 'backup_shortname'. See MDL-33812.
+
+=== 2.2 ===
+
+* Since 2.2.4+ the backup file name schema has changed. The ID of the course will always be part of
+    the filename regardless of the setting 'backup_shortname'. See MDL-33812.
\ No newline at end of file
index 2ce9434..0752f0d 100644 (file)
@@ -112,7 +112,7 @@ abstract class backup_plan_dbops extends backup_dbops {
 
         // Get all sections belonging to requested course
         $sectionsarr = array();
-        $sections = $DB->get_records('course_sections', array('course' => $courseid));
+        $sections = $DB->get_records('course_sections', array('course' => $courseid), 'section');
         foreach ($sections as $section) {
             $sectionsarr[] = $section->id;
         }
@@ -197,19 +197,19 @@ abstract class backup_plan_dbops extends backup_dbops {
     * @param int $courseid/$sectionid/$cmid
     * @param bool $users Should be true is users were included in the backup
     * @param bool $anonymised Should be true is user information was anonymized.
-    * @param bool $useidasname true to use id, false to use strings (default)
+    * @param bool $useidonly only use the ID in the file name
     * @return string The filename to use
     */
-    public static function get_default_backup_filename($format, $type, $id, $users, $anonymised, $useidasname = false) {
+    public static function get_default_backup_filename($format, $type, $id, $users, $anonymised, $useidonly = false) {
         global $DB;
 
         // Calculate backup word
         $backupword = str_replace(' ', '_', textlib::strtolower(get_string('backupfilename')));
         $backupword = trim(clean_filename($backupword), '_');
 
+        // Not $useidonly, lets fetch the name
         $shortname = '';
-        // Not $useidasname, lets calculate it, else $id will be used
-        if (!$useidasname) {
+        if (!$useidonly) {
             // Calculate proper name element (based on type)
             switch ($type) {
                 case backup::TYPE_1COURSE:
@@ -231,7 +231,11 @@ abstract class backup_plan_dbops extends backup_dbops {
             $shortname = textlib::strtolower(trim(clean_filename($shortname), '_'));
         }
 
-        $name = empty($shortname) ? $id : $shortname;
+        // The name will always contain the ID, but we append the course short name if requested.
+        $name = $id;
+        if (!$useidonly && $shortname != '') {
+            $name .= '-' . $shortname;
+        }
 
         // Calculate date
         $backupdateformat = str_replace(' ', '_', get_string('backupnameformat', 'langconfig'));
index 2e73e8f..fb7beb3 100644 (file)
@@ -819,10 +819,13 @@ abstract class restore_dbops {
      * @param int|null $olditemid
      * @param int|null $forcenewcontextid explicit value for the new contextid (skip mapping)
      * @param bool $skipparentitemidctxmatch
+     * @return array of result object
      */
     public static function send_files_to_pool($basepath, $restoreid, $component, $filearea, $oldcontextid, $dfltuserid, $itemname = null, $olditemid = null, $forcenewcontextid = null, $skipparentitemidctxmatch = false) {
         global $DB;
 
+        $results = array();
+
         if ($forcenewcontextid) {
             // Some components can have "forced" new contexts (example: questions can end belonging to non-standard context mappings,
             // with questions originally at system/coursecat context in source being restored to course context in target). So we need
@@ -902,8 +905,14 @@ abstract class restore_dbops {
                 // this is a regular file, it must be present in the backup pool
                 $backuppath = $basepath . backup_file_manager::get_backup_content_file_location($file->contenthash);
 
+                // The file is not found in the backup.
                 if (!file_exists($backuppath)) {
-                    throw new restore_dbops_exception('file_not_found_in_pool', $file);
+                    $result = new stdClass();
+                    $result->code = 'file_missing_in_backup';
+                    $result->message = sprintf('missing file %s%s in backup', $file->filepath, $file->filename);
+                    $result->level = backup::LOG_WARNING;
+                    $results[] = $result;
+                    continue;
                 }
 
                 // create the file in the filepool if it does not exist yet
@@ -960,6 +969,7 @@ abstract class restore_dbops {
             }
         }
         $rs->close();
+        return $results;
     }
 
     /**
index 00db13d..f7c6bc1 100644 (file)
@@ -46,6 +46,8 @@ abstract class backup_cron_automated_helper {
     const BACKUP_STATUS_UNFINISHED = 2;
     /** Course automated backup was skipped */
     const BACKUP_STATUS_SKIPPED = 3;
+    /** Course automated backup had warnings */
+    const BACKUP_STATUS_WARNING = 4;
 
     /** Run if required by the schedule set in config. Default. **/
     const RUN_ON_SCHEDULE = 0;
@@ -110,7 +112,7 @@ abstract class backup_cron_automated_helper {
             $nextstarttime = backup_cron_automated_helper::calculate_next_automated_backup($admin->timezone, $now);
             $showtime = "undefined";
             if ($nextstarttime > 0) {
-                $showtime = userdate($nextstarttime,"",$admin->timezone);
+                $showtime = date('r', $nextstarttime);
             }
 
             $rs = $DB->get_recordset('course');
@@ -124,7 +126,14 @@ abstract class backup_cron_automated_helper {
                 }
 
                 // Skip courses that do not yet need backup
-                $skipped = !(($backupcourse->nextstarttime >= 0 && $backupcourse->nextstarttime < $now) || $rundirective == self::RUN_IMMEDIATELY);
+                $skipped = !(($backupcourse->nextstarttime > 0 && $backupcourse->nextstarttime < $now) || $rundirective == self::RUN_IMMEDIATELY);
+                if ($skipped && $backupcourse->nextstarttime != $nextstarttime) {
+                    $backupcourse->nextstarttime = $nextstarttime;
+                    $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_SKIPPED;
+                    $DB->update_record('backup_courses', $backupcourse);
+                    mtrace('Backup of \'' . $course->fullname . '\' is scheduled on ' . $showtime);
+                }
+
                 // Skip backup of unavailable courses that have remained unmodified in a month
                 if (!$skipped && empty($course->visible) && ($now - $course->timemodified) > 31*24*60*60) {  //Hidden + settings were unmodified last month
                     //Check log if there were any modifications to the course content
@@ -132,16 +141,17 @@ abstract class backup_cron_automated_helper {
                     $params = array('courseid' => $course->id, 'time' => $now-31*24*60*60, 'action' => '%view%');
                     $logexists = $DB->record_exists_select('log', $sqlwhere, $params);
                     if (!$logexists) {
-                        $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_SKIPPED;
+                        $backupcourse->laststatus = self::BACKUP_STATUS_SKIPPED;
                         $backupcourse->nextstarttime = $nextstarttime;
                         $DB->update_record('backup_courses', $backupcourse);
                         mtrace('Skipping unchanged course '.$course->fullname);
                         $skipped = true;
                     }
                 }
+
                 //Now we backup every non-skipped course
                 if (!$skipped) {
-                    mtrace('Backing up '.$course->fullname'...');
+                    mtrace('Backing up '.$course->fullname.'...');
 
                     //We have to send a email because we have included at least one backup
                     $emailpending = true;
@@ -152,7 +162,7 @@ abstract class backup_cron_automated_helper {
                         $starttime = time();
 
                         $backupcourse->laststarttime = time();
-                        $backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_UNFINISHED;
+                        $backupcourse->laststatus = self::BACKUP_STATUS_UNFINISHED;
                         $DB->update_record('backup_courses', $backupcourse);
 
                         $backupcourse->laststatus = backup_cron_automated_helper::launch_automated_backup($course, $backupcourse->laststarttime, $admin->id);
@@ -161,7 +171,7 @@ abstract class backup_cron_automated_helper {
 
                         $DB->update_record('backup_courses', $backupcourse);
 
-                        if ($backupcourse->laststatus) {
+                        if ($backupcourse->laststatus === self::BACKUP_STATUS_OK) {
                             // Clean up any excess course backups now that we have
                             // taken a successful backup.
                             $removedcount = backup_cron_automated_helper::remove_excess_backups($course);
@@ -180,17 +190,18 @@ abstract class backup_cron_automated_helper {
             $message = "";
 
             $count = backup_cron_automated_helper::get_backup_status_array();
-            $haserrors = ($count[backup_cron_automated_helper::BACKUP_STATUS_ERROR] != 0 || $count[backup_cron_automated_helper::BACKUP_STATUS_UNFINISHED] != 0);
+            $haserrors = ($count[self::BACKUP_STATUS_ERROR] != 0 || $count[self::BACKUP_STATUS_UNFINISHED] != 0);
 
             //Build the message text
             //Summary
             $message .= get_string('summary')."\n";
             $message .= "==================================================\n";
             $message .= "  ".get_string('courses').": ".array_sum($count)."\n";
-            $message .= "  ".get_string('ok').": ".$count[backup_cron_automated_helper::BACKUP_STATUS_OK]."\n";
-            $message .= "  ".get_string('skipped').": ".$count[backup_cron_automated_helper::BACKUP_STATUS_SKIPPED]."\n";
-            $message .= "  ".get_string('error').": ".$count[backup_cron_automated_helper::BACKUP_STATUS_ERROR]."\n";
-            $message .= "  ".get_string('unfinished').": ".$count[backup_cron_automated_helper::BACKUP_STATUS_UNFINISHED]."\n\n";
+            $message .= "  ".get_string('ok').": ".$count[self::BACKUP_STATUS_OK]."\n";
+            $message .= "  ".get_string('skipped').": ".$count[self::BACKUP_STATUS_SKIPPED]."\n";
+            $message .= "  ".get_string('error').": ".$count[self::BACKUP_STATUS_ERROR]."\n";
+            $message .= "  ".get_string('unfinished').": ".$count[self::BACKUP_STATUS_UNFINISHED]."\n";
+            $message .= "  ".get_string('warning').": ".$count[self::BACKUP_STATUS_WARNING]."\n\n";
 
             //Reference
             if ($haserrors) {
@@ -253,9 +264,10 @@ abstract class backup_cron_automated_helper {
             self::BACKUP_STATUS_OK => 0,
             self::BACKUP_STATUS_UNFINISHED => 0,
             self::BACKUP_STATUS_SKIPPED => 0,
+            self::BACKUP_STATUS_WARNING => 0
         );
 
-        $statuses = $DB->get_records_sql('SELECT DISTINCT bc.laststatus, COUNT(bc.courseid) statuscount FROM {backup_courses} bc GROUP BY bc.laststatus');
+        $statuses = $DB->get_records_sql('SELECT DISTINCT bc.laststatus, COUNT(bc.courseid) AS statuscount FROM {backup_courses} bc GROUP BY bc.laststatus');
 
         foreach ($statuses as $status) {
             if (empty($status->statuscount)) {
@@ -270,38 +282,47 @@ abstract class backup_cron_automated_helper {
     /**
      * Works out the next time the automated backup should be run.
      *
-     * @param mixed $timezone
-     * @param int $now
-     * @return int
+     * @param mixed $timezone user timezone
+     * @param int $now timestamp, should not be in the past, most likely time()
+     * @return int timestamp of the next execution at server time
      */
     public static function calculate_next_automated_backup($timezone, $now) {
 
-        $result = -1;
+        $result = 0;
         $config = get_config('backup');
-        $midnight = usergetmidnight($now, $timezone);
+        $autohour = $config->backup_auto_hour;
+        $automin = $config->backup_auto_minute;
+
+        // Gets the user time relatively to the server time.
         $date = usergetdate($now, $timezone);
+        $usertime = mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']);
+        $diff = $now - $usertime;
 
-        // Get number of days (from today) to execute backups
+        // Get number of days (from user's today) to execute backups.
         $automateddays = substr($config->backup_auto_weekdays, $date['wday']) . $config->backup_auto_weekdays;
-        $daysfromtoday = strpos($automateddays, "1", 1);
+        $daysfromnow = strpos($automateddays, "1");
 
-        // If we can't find the next day, we set it to tomorrow
-        if (empty($daysfromtoday)) {
-            $daysfromtoday = 1;
+        // Error, there are no days to schedule the backup for.
+        if ($daysfromnow === false) {
+            return 0;
         }
 
-        // If some day has been found
-        if ($daysfromtoday !== false) {
-            // Calculate distance
-            $dist = ($daysfromtoday * 86400) +                // Days distance
-                    ($config->backup_auto_hour * 3600) +      // Hours distance
-                    ($config->backup_auto_minute * 60);       // Minutes distance
-            $result = $midnight + $dist;
+        // Checks if the date would happen in the future (of the user).
+        $userresult = mktime($autohour, $automin, 0, $date['mon'], $date['mday'] + $daysfromnow, $date['year']);
+        if ($userresult <= $usertime) {
+            // If not, we skip the first scheduled day, that should fix it.
+            $daysfromnow = strpos($automateddays, "1", 1);
+            $userresult = mktime($autohour, $automin, 0, $date['mon'], $date['mday'] + $daysfromnow, $date['year']);
         }
 
-        // If that time is past, call the function recursively to obtain the next valid day
-        if ($result > 0 && $result < time()) {
-            $result = self::calculate_next_automated_backup($timezone, $result);
+        // Now we generate the time relative to the server.
+        $result = $userresult + $diff;
+
+        // If that time is past, call the function recursively to obtain the next valid day.
+        if ($result <= $now) {
+            // Checking time() in here works, but makes PHPUnit Tests extremely hard to predict.
+            // $now should never be earlier than time() anyway...
+            $result = self::calculate_next_automated_backup($timezone, $now + DAYSECS);
         }
 
         return $result;
@@ -317,7 +338,7 @@ abstract class backup_cron_automated_helper {
      */
     public static function launch_automated_backup($course, $starttime, $userid) {
 
-        $outcome = true;
+        $outcome = self::BACKUP_STATUS_OK;
         $config = get_config('backup');
         $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_AUTOMATED, $userid);
 
@@ -352,6 +373,7 @@ abstract class backup_cron_automated_helper {
 
             $bc->execute_plan();
             $results = $bc->get_results();
+            $outcome = self::outcome_from_results($results);
             $file = $results['backup_destination']; // may be empty if file already moved to target location
             $dir = $config->backup_auto_destination;
             $storage = (int)$config->backup_auto_storage;
@@ -360,8 +382,10 @@ abstract class backup_cron_automated_helper {
             }
             if ($file && !empty($dir) && $storage !== 0) {
                 $filename = backup_plan_dbops::get_default_backup_filename($format, $type, $course->id, $users, $anonymised, !$config->backup_shortname);
-                $outcome = $file->copy_content_to($dir.'/'.$filename);
-                if ($outcome && $storage === 1) {
+                if (!$file->copy_content_to($dir.'/'.$filename)) {
+                    $outcome = self::BACKUP_STATUS_ERROR;
+                }
+                if ($outcome != self::BACKUP_STATUS_ERROR && $storage === 1) {
                     $file->delete();
                 }
             }
@@ -370,7 +394,7 @@ abstract class backup_cron_automated_helper {
             $bc->log('backup_auto_failed_on_course', backup::LOG_ERROR, $course->shortname); // Log error header.
             $bc->log('Exception: ' . $e->errorcode, backup::LOG_ERROR, $e->a, 1); // Log original exception problem.
             $bc->log('Debug: ' . $e->debuginfo, backup::LOG_DEBUG, null, 1); // Log original debug information.
-            $outcome = false;
+            $outcome = self::BACKUP_STATUS_ERROR;
         }
 
         $bc->destroy();
@@ -379,6 +403,30 @@ abstract class backup_cron_automated_helper {
         return $outcome;
     }
 
+    /**
+     * Returns the backup outcome by analysing its results.
+     *
+     * @param array $results returned by a backup
+     * @return int {@link self::BACKUP_STATUS_OK} and other constants
+     */
+    public static function outcome_from_results($results) {
+        $outcome = self::BACKUP_STATUS_OK;
+        foreach ($results as $code => $value) {
+            // Each possible error and warning code has to be specified in this switch
+            // which basically analyses the results to return the correct backup status.
+            switch ($code) {
+                case 'missing_files_in_pool':
+                    $outcome = self::BACKUP_STATUS_WARNING;
+                    break;
+            }
+            // If we found the highest error level, we exit the loop.
+            if ($outcome == self::BACKUP_STATUS_ERROR) {
+                break;
+            }
+        }
+        return $outcome;
+    }
+
     /**
      * Removes deleted courses fromn the backup_courses table so that we don't
      * waste time backing them up.
@@ -411,7 +459,12 @@ abstract class backup_cron_automated_helper {
 
         $config = get_config('backup');
         $active = (int)$config->backup_auto_active;
-        if ($active === self::AUTO_BACKUP_DISABLED || ($rundirective == self::RUN_ON_SCHEDULE && $active === self::AUTO_BACKUP_MANUAL)) {
+        $weekdays = (string)$config->backup_auto_weekdays;
+
+        // In case of automated backup also check that it is scheduled for at least one weekday.
+        if ($active === self::AUTO_BACKUP_DISABLED ||
+                ($rundirective == self::RUN_ON_SCHEDULE && $active === self::AUTO_BACKUP_MANUAL) ||
+                ($rundirective == self::RUN_ON_SCHEDULE && strpos($weekdays, '1') === false)) {
             return self::STATE_DISABLED;
         } else if (!empty($config->backup_auto_running)) {
             // Detect if the backup_auto_running semaphore is a valid one
diff --git a/backup/util/helper/tests/cronhelper_test.php b/backup/util/helper/tests/cronhelper_test.php
new file mode 100644 (file)
index 0000000..7afd1be
--- /dev/null
@@ -0,0 +1,442 @@
+<?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 backups cron helper.
+ *
+ * @package   core_backup
+ * @category  phpunit
+ * @copyright 2012 Frédéric Massart <fred@moodle.com>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/backup/util/helper/backup_cron_helper.class.php');
+
+/**
+ * Unit tests for backup cron helper
+ */
+class backup_cron_helper_testcase extends advanced_testcase {
+
+    /**
+     * Test {@link backup_cron_automated_helper::calculate_next_automated_backup}.
+     */
+    public function test_next_automated_backup() {
+        $this->resetAfterTest();
+        set_config('backup_auto_active', '1', 'backup');
+
+        // Notes
+        // - backup_auto_weekdays starts on Sunday
+        // - Tests cannot be done in the past
+        // - Only the DST on the server side is handled.
+
+        // Every Tue and Fri at 11pm.
+        set_config('backup_auto_weekdays', '0010010', 'backup');
+        set_config('backup_auto_hour', '23', 'backup');
+        set_config('backup_auto_minute', '0', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Monday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Tuesday 18:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Wednesday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('5-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Thursday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('5-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Friday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('5-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Saturday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-23:00', date('w-H:i', $next));
+
+        $now = strtotime('next Sunday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-23:00', date('w-H:i', $next));
+
+        // Every Sun and Sat at 12pm.
+        set_config('backup_auto_weekdays', '1000001', 'backup');
+        set_config('backup_auto_hour', '0', 'backup');
+        set_config('backup_auto_minute', '0', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Monday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Tuesday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Wednesday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Thursday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Friday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Saturday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Sunday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        // Every Sun at 4am.
+        set_config('backup_auto_weekdays', '1000000', 'backup');
+        set_config('backup_auto_hour', '4', 'backup');
+        set_config('backup_auto_minute', '0', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Monday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Tuesday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Wednesday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Thursday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Friday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Saturday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        $now = strtotime('next Sunday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-04:00', date('w-H:i', $next));
+
+        // Every day but Wed at 8:30pm.
+        set_config('backup_auto_weekdays', '1110111', 'backup');
+        set_config('backup_auto_hour', '20', 'backup');
+        set_config('backup_auto_minute', '30', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Monday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('1-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Tuesday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Wednesday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('4-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Thursday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('4-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Friday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('5-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Saturday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-20:30', date('w-H:i', $next));
+
+        $now = strtotime('next Sunday 17:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-20:30', date('w-H:i', $next));
+
+        // Sun, Tue, Thu, Sat at 12pm.
+        set_config('backup_auto_weekdays', '1010101', 'backup');
+        set_config('backup_auto_hour', '0', 'backup');
+        set_config('backup_auto_minute', '0', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Monday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Tuesday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('4-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Wednesday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('4-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Thursday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Friday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('6-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Saturday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0-00:00', date('w-H:i', $next));
+
+        $now = strtotime('next Sunday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('2-00:00', date('w-H:i', $next));
+
+        // None.
+        set_config('backup_auto_weekdays', '0000000', 'backup');
+        set_config('backup_auto_hour', '15', 'backup');
+        set_config('backup_auto_minute', '30', 'backup');
+        $timezone = 99;
+
+        $now = strtotime('next Sunday 13:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals('0', $next);
+
+        // Playing with timezones.
+        set_config('backup_auto_weekdays', '1111111', 'backup');
+        set_config('backup_auto_hour', '20', 'backup');
+        set_config('backup_auto_minute', '00', 'backup');
+
+        $timezone = 99;
+        date_default_timezone_set('Australia/Perth');
+        $now = strtotime('18:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+        $timezone = 99;
+        date_default_timezone_set('Europe/Brussels');
+        $now = strtotime('18:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+        $timezone = 99;
+        date_default_timezone_set('America/New_York');
+        $now = strtotime('18:00:00');
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+        // Viva Australia! (UTC+8).
+        date_default_timezone_set('Australia/Perth');
+        $now = strtotime('18:00:00');
+
+        $timezone = -10.0; // 12am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-14:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        $timezone = -5.0; // 5am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-09:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        $timezone = 0.0;  // 10am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-04:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        $timezone = 3.0; // 1pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-01:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        $timezone = 8.0; // 6pm for the user (same than the server).
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-20:00'), date('w-H:i', $next));
+
+        $timezone = 9.0; // 7pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-19:00'), date('w-H:i', $next));
+
+        $timezone = 13.0; // 12am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $this->assertEquals(date('w-15:00', strtotime('tomorrow')), date('w-H:i', $next));
+
+        // Let's have a Belgian beer! (UTC+1 / UTC+2 DST).
+        date_default_timezone_set('Europe/Brussels');
+        $now = strtotime('18:00:00');
+        $dst = date('I');
+
+        $timezone = -10.0; // 7am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-07:00', strtotime('tomorrow')) : date('w-08:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = -5.0; // 12pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-02:00', strtotime('tomorrow')) : date('w-03:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 0.0;  // 5pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-21:00') : date('w-22:00');
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 3.0; // 8pm for the user (note the expected time is today while in DST).
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-18:00', strtotime('tomorrow')) : date('w-19:00');
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 8.0; // 1am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-13:00', strtotime('tomorrow')) : date('w-14:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 9.0; // 2am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-12:00', strtotime('tomorrow')) : date('w-13:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 13.0; // 6am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-08:00', strtotime('tomorrow')) : date('w-09:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        // The big apple! (UTC-5 / UTC-4 DST).
+        date_default_timezone_set('America/New_York');
+        $now = strtotime('18:00:00');
+        $dst = date('I');
+
+        $timezone = -10.0; // 1pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-01:00', strtotime('tomorrow')) : date('w-02:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = -5.0; // 6pm for the user (server time).
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-20:00') : date('w-21:00');
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 0.0;  // 11pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-15:00', strtotime('tomorrow')) : date('w-16:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 3.0; // 2am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-12:00', strtotime('tomorrow')) : date('w-13:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 8.0; // 7am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-07:00', strtotime('tomorrow')) : date('w-08:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 9.0; // 8am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-06:00', strtotime('tomorrow')) : date('w-07:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 13.0; // 6am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? date('w-02:00', strtotime('tomorrow')) : date('w-03:00', strtotime('tomorrow'));
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        // Some more timezone tests
+        set_config('backup_auto_weekdays', '0100001', 'backup');
+        set_config('backup_auto_hour', '20', 'backup');
+        set_config('backup_auto_minute', '00', 'backup');
+
+        date_default_timezone_set('Europe/Brussels');
+        $now = strtotime('next Monday 18:00:00');
+        $dst = date('I');
+
+        $timezone = -12.0;  // 1pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '2-09:00' : '2-10:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = -4.0;  // 1pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '2-01:00' : '2-02:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 0.0;  // 5pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '1-21:00' : '1-22:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 2.0;  // 7pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '1-19:00' : '1-20:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 4.0;  // 9pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '6-17:00' : '6-18:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 12.0;  // 6am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '6-09:00' : '6-10:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        // Some more timezone tests
+        set_config('backup_auto_weekdays', '0100001', 'backup');
+        set_config('backup_auto_hour', '02', 'backup');
+        set_config('backup_auto_minute', '00', 'backup');
+
+        date_default_timezone_set('America/New_York');
+        $now = strtotime('next Monday 04:00:00');
+        $dst = date('I');
+
+        $timezone = -12.0;  // 8pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '1-09:00' : '1-10:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = -4.0;  // 4am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '6-01:00' : '6-02:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 0.0;  // 8am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '5-21:00' : '5-22:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 2.0;  // 10am for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '5-19:00' : '5-20:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 4.0;  // 12pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '5-17:00' : '5-18:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+        $timezone = 12.0;  // 8pm for the user.
+        $next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
+        $expected = !$dst ? '5-09:00' : '5-10:00';
+        $this->assertEquals($expected, date('w-H:i', $next));
+
+    }
+}
index f62fee9..964dd3f 100644 (file)
@@ -94,11 +94,22 @@ abstract class backup_structure_step extends backup_step {
         // Process structure definition
         $structure->process($pr);
 
+        // Get the results from the nested elements
+        $results = $structure->get_results();
+
+        // Get the log messages to append to the log
+        $logs = $structure->get_logs();
+        foreach ($logs as $log) {
+            $this->log($log->message, $log->level, $log->a, $log->depth, $log->display);
+        }
+
         // Close everything
         $xw->stop();
 
         // Destroy the structure. It helps PHP 5.2 memory a lot!
         $structure->destroy();
+
+        return $results;
     }
 
     /**
index 4b0ff58..b6c0ead 100644 (file)
@@ -218,8 +218,14 @@ abstract class restore_structure_step extends restore_step {
      */
     public function add_related_files($component, $filearea, $mappingitemname, $filesctxid = null, $olditemid = null) {
         $filesctxid = is_null($filesctxid) ? $this->task->get_old_contextid() : $filesctxid;
-        restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), $component,
-                                          $filearea, $filesctxid, $this->task->get_userid(), $mappingitemname, $olditemid);
+        $results = restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), $component,
+                $filearea, $filesctxid, $this->task->get_userid(), $mappingitemname, $olditemid);
+        $resultstoadd = array();
+        foreach ($results as $result) {
+            $this->log($result->message, $result->level);
+            $resultstoadd[$result->code] = true;
+        }
+        $this->task->add_result($resultstoadd);
     }
 
     /**
index 9a47901..8557ec8 100644 (file)
@@ -37,6 +37,8 @@ class backup_nested_element extends base_nested_element implements processable {
     protected $aliases;   // Define DB->final element aliases
     protected $fileannotations;   // array of file areas to be searched by file annotations
     protected $counter;   // Number of instances of this element that have been processed
+    protected $results;  // Logs the results we encounter during the process.
+    protected $logs;     // Some log messages that could be retrieved later.
 
     /**
      * Constructor - instantiates one backup_nested_element, specifying its basic info.
@@ -55,8 +57,16 @@ class backup_nested_element extends base_nested_element implements processable {
         $this->aliases   = array();
         $this->fileannotations = array();
         $this->counter   = 0;
+        $this->results  = array();
+        $this->logs     = array();
     }
 
+    /**
+     * Process the nested element
+     *
+     * @param object $processor the processor
+     * @return void
+     */
     public function process($processor) {
         if (!$processor instanceof base_processor) { // No correct processor, throw exception
             throw new base_element_struct_exception('incorrect_processor');
@@ -113,6 +123,69 @@ class backup_nested_element extends base_nested_element implements processable {
         $iterator->close();
     }
 
+    /**
+     * Saves a log message to an array
+     *
+     * @see backup_helper::log()
+     * @param string $message to add to the logs
+     * @param int $level level of importance {@link backup::LOG_DEBUG} and other constants
+     * @param mixed $a to be included in $message
+     * @param int $depth of the message
+     * @param display $bool supporting translation via get_string() if true
+     * @return void
+     */
+    protected function add_log($message, $level, $a = null, $depth = null, $display = false) {
+        // Adding the result to the oldest parent.
+        if ($this->get_parent()) {
+            $parent = $this->get_grandparent();
+            $parent->add_log($message, $level, $a, $depth, $display);
+        } else {
+            $log = new stdClass();
+            $log->message = $message;
+            $log->level = $level;
+            $log->a = $a;
+            $log->depth = $depth;
+            $log->display = $display;
+            $this->logs[] = $log;
+        }
+    }
+
+    /**
+     * Saves the results to an array
+     *
+     * @param array $result associative array
+     * @return void
+     */
+    protected function add_result($result) {
+        if (is_array($result)) {
+            // Adding the result to the oldest parent.
+            if ($this->get_parent()) {
+                $parent = $this->get_grandparent();
+                $parent->add_result($result);
+            } else {
+                $this->results = array_merge($this->results, $result);
+            }
+        }
+    }
+
+    /**
+     * Returns the logs
+     *
+     * @return array of log objects
+     */
+    public function get_logs() {
+        return $this->logs;
+    }
+
+    /**
+     * Returns the results
+     *
+     * @return associative array of results
+     */
+    public function get_results() {
+        return $this->results;
+    }
+
     public function set_source_array($arr) {
         // TODO: Only elements having final elements can set source
         $this->var_array = $arr;
index 7995561..0b90e15 100644 (file)
@@ -487,6 +487,9 @@ class backup_ui_stage_complete extends backup_ui_stage_final {
         if (!empty($this->results['include_file_references_to_external_content'])) {
             $output .= $renderer->notification(get_string('filereferencesincluded', 'backup'), 'notifyproblem');
         }
+        if (!empty($this->results['missing_files_in_pool'])) {
+            $output .= $renderer->notification(get_string('missingfilesinpool', 'backup'), 'notifyproblem');
+        }
         $output .= $renderer->notification(get_string('executionsuccess', 'backup'), 'notifysuccess');
         $output .= $renderer->continue_button($restorerul);
         $output .= $renderer->box_end();
index e0ffc0f..ce95e7a 100644 (file)
@@ -96,7 +96,6 @@ abstract class base_moodleform extends moodleform {
      * @global moodle_page $PAGE
      */
     function definition_after_data() {
-        global $PAGE;
         $buttonarray=array();
         $buttonarray[] = $this->_form->createElement('submit', 'submitbutton', get_string($this->uistage->get_ui()->get_name().'stage'.$this->uistage->get_stage().'action', 'backup'), array('class'=>'proceedbutton'));
         if (!$this->uistage->is_first_stage()) {
@@ -106,13 +105,9 @@ abstract class base_moodleform extends moodleform {
         $this->_form->addGroup($buttonarray, 'buttonar', '', array(' '), false);
         $this->_form->closeHeaderBefore('buttonar');
 
-        $config = new stdClass;
-        $config->title = get_string('confirmcancel', 'backup');
-        $config->question = get_string('confirmcancelquestion', 'backup');
-        $config->yesLabel = get_string('confirmcancelyes', 'backup');
-        $config->noLabel = get_string('confirmcancelno', 'backup');
-        $PAGE->requires->yui_module('moodle-backup-confirmcancel', 'M.core_backup.watch_cancel_buttons', array($config));
+        $this->_definition_finalized = true;
     }
+
     /**
      * Closes any open divs
      */
@@ -318,7 +313,20 @@ abstract class base_moodleform extends moodleform {
      * Displays the form
      */
     public function display() {
+        global $PAGE;
+
         $this->require_definition_after_data();
+
+        $config = new stdClass;
+        $config->title = get_string('confirmcancel', 'backup');
+        $config->question = get_string('confirmcancelquestion', 'backup');
+        $config->yesLabel = get_string('confirmcancelyes', 'backup');
+        $config->noLabel = get_string('confirmcancelno', 'backup');
+        $PAGE->requires->yui_module('moodle-backup-confirmcancel', 'M.core_backup.watch_cancel_buttons', array($config));
+
+        $PAGE->requires->yui_module('moodle-backup-backupselectall', 'M.core_backup.select_all_init',
+                array(array('select' => get_string('select'), 'all' => get_string('all'), 'none' => get_string('none'))));
+
         parent::display();
     }
 
@@ -327,7 +335,6 @@ abstract class base_moodleform extends moodleform {
      */
     public function require_definition_after_data() {
         if (!$this->_definition_finalized) {
-            $this->_definition_finalized = true;
             $this->definition_after_data();
         }
     }
index 7e92069..34bff92 100644 (file)
@@ -772,6 +772,9 @@ class restore_ui_stage_complete extends restore_ui_stage_process {
             $html .= $renderer->box_end();
         }
         $html .= $renderer->box_start();
+        if (array_key_exists('file_missing_in_backup', $this->results)) {
+            $html .= $renderer->notification(get_string('restorefileweremissing', 'backup'), 'notifyproblem');
+        }
         $html .= $renderer->notification(get_string('restoreexecutionsuccess', 'backup'), 'notifysuccess');
         $html .= $renderer->continue_button(new moodle_url('/course/view.php', array(
             'id' => $this->get_ui()->get_controller()->get_courseid())), 'get');
diff --git a/backup/util/ui/yui/backupselectall/backupselectall.js b/backup/util/ui/yui/backupselectall/backupselectall.js
new file mode 100644 (file)
index 0000000..9f05b7f
--- /dev/null
@@ -0,0 +1,80 @@
+YUI.add('moodle-backup-backupselectall', function(Y) {
+
+// Namespace for the backup
+M.core_backup = M.core_backup || {};
+
+/**
+ * Adds select all/none links to the top of the backup/restore/import schema page.
+ */
+M.core_backup.select_all_init = function(str) {
+    var formid = null;
+
+    var helper = function(e, check, type) {
+        e.preventDefault();
+
+        var len = type.length;
+        Y.all('input[type="checkbox"]').each(function(checkbox) {
+            var name = checkbox.get('name');
+            if (name.substring(name.length - len) == type) {
+                checkbox.set('checked', check);
+            }
+        });
+
+        // At this point, we really need to persuade the form we are part of to
+        // update all of its disabledIf rules. However, as far as I can see,
+        // given the way that lib/form/form.js is written, that is impossible.
+        if (formid && M.form) {
+            M.form.updateFormState(formid);
+        }
+    };
+
+    var html_generator = function(classname, idtype) {
+        return '<div class="' + classname + '">' +
+                    '<div class="fitem fitem_fcheckbox">' +
+                        '<div class="fitemtitle">' + str.select + '</div>' +
+                        '<div class="felement">' +
+                            '<a id="backup-all-' + idtype + '" href="#">' + str.all + '</a> / ' +
+                            '<a id="backup-none-' + idtype + '" href="#">' + str.none + '</a>' +
+                        '</div>' +
+                    '</div>' +
+                '</div>';
+    };
+
+    var firstsection = Y.one('fieldset#coursesettings .fcontainer.clearfix .grouped_settings.section_level');
+    if (!firstsection) {
+        // This is not a relevant page.
+        return;
+    }
+    if (!firstsection.one('.felement.fcheckbox')) {
+        // No checkboxes.
+        return;
+    }
+
+    formid = firstsection.ancestor('form').getAttribute('id');
+
+    var withuserdata = false;
+    Y.all('input[type="checkbox"]').each(function(checkbox) {
+        var name = checkbox.get('name');
+        if (name.substring(name.length - 9) == '_userdata') {
+            withuserdata = '_userdata';
+        } else if (name.substring(name.length - 9) == '_userinfo') {
+            withuserdata = '_userinfo';
+        }
+    });
+
+    var html = html_generator('include_setting section_level', 'included');
+    if (withuserdata) {
+        html += html_generator('normal_setting', 'userdata');
+    }
+    var links = Y.Node.create('<div class="grouped_settings section_level">' + html + '</div>');
+    firstsection.insert(links, 'before');
+
+    Y.one('#backup-all-included').on('click',  function(e) { helper(e, true,  '_included'); });
+    Y.one('#backup-none-included').on('click', function(e) { helper(e, false, '_included'); });
+    if (withuserdata) {
+        Y.one('#backup-all-userdata').on('click',  function(e) { helper(e, true,  withuserdata); });
+        Y.one('#backup-none-userdata').on('click', function(e) { helper(e, false, withuserdata); });
+    }
+}
+
+}, '@VERSION@', {'requires':['base','node','event', 'node-event-simulate']});
index c3071c4..35e3f2e 100644 (file)
@@ -71,7 +71,7 @@ class block_community extends block_list {
         $icon = html_writer::empty_tag('img', array('src' => $OUTPUT->pix_url('i/group'),
                     'class' => 'icon', 'alt' => get_string('addcourse', 'block_community')));
         $addcourseurl = new moodle_url('/blocks/community/communitycourse.php',
-                        array('add' => true, 'courseid' => $coursecontext->instanceid));
+                        array('add' => true, 'courseid' => $this->page->course->id));
         $searchlink = html_writer::tag('a', $icon . '&nbsp;' . get_string('addcourse', 'block_community'),
                         array('href' => $addcourseurl->out(false)));
         $this->content->items[] = $searchlink;
@@ -91,7 +91,7 @@ class block_community extends block_list {
                                     'alt' => get_string('removecommunitycourse', 'block_community')));
                 $deleteurl = new moodle_url('/blocks/community/communitycourse.php',
                                 array('remove' => true,
-                                    'courseid' => $coursecontext->instanceid,
+                                    'courseid' => $this->page->course->id,
                                     'communityid' => $course->id, 'sesskey' => sesskey()));
                 $deleteatag = html_writer::tag('a', $deleteicon, array('href' => $deleteurl));
 
index 155a823..7355b80 100644 (file)
@@ -23,8 +23,7 @@ YUI.add('moodle-block_community-comments', function(Y) {
                     bodyContent:Y.one('#commentoverlay-'+commentid).get('innerHTML'),
                     visible: false, //by default it is not displayed
                     lightbox : false,
-                    zIndex:100,
-                    height: '350px'
+                    zIndex:100
                 });
 
                 this.overlays[commentid].get('contentBox').one('.commenttitle').remove();
@@ -86,4 +85,4 @@ YUI.add('moodle-block_community-comments', function(Y) {
 
 }, '@VERSION@', {
     requires:['base','overlay', 'moodle-enrol-notification']
-});
\ No newline at end of file
+});
index 0daec7c..5caf743 100644 (file)
  *
  * @package    block
  * @subpackage completion
- * @copyright  2009 Catalyst IT Ltd
+ * @copyright  2009-2012 Catalyst IT Ltd
  * @author     Aaron Barnes <aaronb@catalyst.net.nz>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
 defined('MOODLE_INTERNAL') || die();
 
-
-require_once($CFG->libdir.'/completionlib.php');
+require_once("{$CFG->libdir}/completionlib.php");
 
 /**
  * Course completion status
@@ -36,25 +35,29 @@ require_once($CFG->libdir.'/completionlib.php');
 class block_completionstatus extends block_base {
 
     public function init() {
-        $this->title   = get_string('pluginname', 'block_completionstatus');
+        $this->title = get_string('pluginname', 'block_completionstatus');
     }
 
     public function get_content() {
-        global $USER, $CFG, $DB, $COURSE;
+        global $USER;
 
         // If content is cached
         if ($this->content !== NULL) {
             return $this->content;
         }
 
+        $course  = $this->page->course;
+
         // Create empty content
-        $this->content = new stdClass;
+        $this->content = new stdClass();
+
+        $context = get_context_instance(CONTEXT_COURSE, $course->id);
 
         // Can edit settings?
-        $can_edit = has_capability('moodle/course:update', get_context_instance(CONTEXT_COURSE, $this->page->course->id));
+        $can_edit = has_capability('moodle/course:update', $context);
 
         // Get course completion data
-        $info = new completion_info($this->page->course);
+        $info = new completion_info($course);
 
         // Don't display if completion isn't enabled!
         if (!completion_info::is_enabled_for_site()) {
@@ -82,147 +85,145 @@ class block_completionstatus extends block_base {
         }
 
         // Check this user is enroled
-        if (!$info->is_tracked_user($USER->id)) {
-            // If not enrolled, but are can view the report:
-            if (has_capability('report/completion:view', get_context_instance(CONTEXT_COURSE, $COURSE->id))) {
-                $this->content->text = '<a href="'.$CFG->wwwroot.'/report/completion/index.php?course='.$COURSE->id.
-                                       '">'.get_string('viewcoursereport', 'completion').'</a>';
-                return $this->content;
-            }
+        if ($info->is_tracked_user($USER->id)) {
 
-            // Otherwise, show error
-            $this->content->text = get_string('notenroled', 'completion');
-            return $this->content;
-        }
+            // Generate markup for criteria statuses
+            $shtml = '';
 
-        // Generate markup for criteria statuses
-        $shtml = '';
+            // For aggregating activity completion
+            $activities = array();
+            $activities_complete = 0;
 
-        // For aggregating activity completion
-        $activities = array();
-        $activities_complete = 0;
+            // For aggregating course prerequisites
+            $prerequisites = array();
+            $prerequisites_complete = 0;
 
-        // For aggregating course prerequisites
-        $prerequisites = array();
-        $prerequisites_complete = 0;
+            // Flag to set if current completion data is inconsistent with
+            // what is stored in the database
+            $pending_update = false;
 
-        // Flag to set if current completion data is inconsistent with
-        // what is stored in the database
-        $pending_update = false;
+            // Loop through course criteria
+            foreach ($completions as $completion) {
 
-        // Loop through course criteria
-        foreach ($completions as $completion) {
+                $criteria = $completion->get_criteria();
+                $complete = $completion->is_complete();
 
-            $criteria = $completion->get_criteria();
-            $complete = $completion->is_complete();
+                if (!$pending_update && $criteria->is_pending($completion)) {
+                    $pending_update = true;
+                }
 
-            if (!$pending_update && $criteria->is_pending($completion)) {
-                $pending_update = true;
-            }
+                // Activities are a special case, so cache them and leave them till last
+                if ($criteria->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
+                    $activities[$criteria->moduleinstance] = $complete;
 
-            // Activities are a special case, so cache them and leave them till last
-            if ($criteria->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
-                $activities[$criteria->moduleinstance] = $complete;
+                    if ($complete) {
+                        $activities_complete++;
+                    }
 
-                if ($complete) {
-                    $activities_complete++;
+                    continue;
                 }
 
-                continue;
-            }
+                // Prerequisites are also a special case, so cache them and leave them till last
+                if ($criteria->criteriatype == COMPLETION_CRITERIA_TYPE_COURSE) {
+                    $prerequisites[$criteria->courseinstance] = $complete;
 
-            // Prerequisites are also a special case, so cache them and leave them till last
-            if ($criteria->criteriatype == COMPLETION_CRITERIA_TYPE_COURSE) {
-                $prerequisites[$criteria->courseinstance] = $complete;
+                    if ($complete) {
+                        $prerequisites_complete++;
+                    }
 
-                if ($complete) {
-                    $prerequisites_complete++;
+                    continue;
                 }
 
-                continue;
+                $shtml .= '<tr><td>';
+                $shtml .= $criteria->get_title();
+                $shtml .= '</td><td style="text-align: right">';
+                $shtml .= $completion->get_status();
+                $shtml .= '</td></tr>';
             }
 
-            $shtml .= '<tr><td>';
-            $shtml .= $criteria->get_title();
-            $shtml .= '</td><td style="text-align: right">';
-            $shtml .= $completion->get_status();
-            $shtml .= '</td></tr>';
-        }
+            // Aggregate activities
+            if (!empty($activities)) {
+
+                $shtml .= '<tr><td>';
+                $shtml .= get_string('activitiescompleted', 'completion');
+                $shtml .= '</td><td style="text-align: right">';
+                $a = new stdClass();
+                $a->first = $activities_complete;
+                $a->second = count($activities);
+                $shtml .= get_string('firstofsecond', 'block_completionstatus', $a);
+                $shtml .= '</td></tr>';
+            }
 
-        // Aggregate activities
-        if (!empty($activities)) {
-
-            $shtml .= '<tr><td>';
-            $shtml .= get_string('activitiescompleted', 'completion');
-            $shtml .= '</td><td style="text-align: right">';
-            $a = new stdClass();
-            $a->first = $activities_complete;
-            $a->second = count($activities);
-            $shtml .= get_string('firstofsecond', 'block_completionstatus', $a);
-            $shtml .= '</td></tr>';
-        }
+            // Aggregate prerequisites
+            if (!empty($prerequisites)) {
 
-        // Aggregate prerequisites
-        if (!empty($prerequisites)) {
+                $phtml  = '<tr><td>';
+                $phtml .= get_string('prerequisitescompleted', 'completion');
+                $phtml .= '</td><td style="text-align: right">';
+                $a = new stdClass();
+                $a->first = $prerequisites_complete;
+                $a->second = count($prerequisites);
+                $phtml .= get_string('firstofsecond', 'block_completionstatus', $a);
+                $phtml .= '</td></tr>';
 
-            $phtml  = '<tr><td>';
-            $phtml .= get_string('prerequisitescompleted', 'completion');
-            $phtml .= '</td><td style="text-align: right">';
-            $a = new stdClass();
-            $a->first = $prerequisites_complete;
-            $a->second = count($prerequisites);
-            $phtml .= get_string('firstofsecond', 'block_completionstatus', $a);
-            $phtml .= '</td></tr>';
+                $shtml = $phtml . $shtml;
+            }
 
-            $shtml = $phtml . $shtml;
-        }
+            // Display completion status
+            $this->content->text  = '<table width="100%" style="font-size: 90%;"><tbody>';
+            $this->content->text .= '<tr><td colspan="2"><b>'.get_string('status').':</b> ';
+
+            // Is course complete?
+            $coursecomplete = $info->is_course_complete($USER->id);
+
+            // Load course completion
+            $params = array(
+                'userid' => $USER->id,
+                'course' => $course->id
+            );
+            $ccompletion = new completion_completion($params);
+
+            // Has this user completed any criteria?
+            $criteriacomplete = $info->count_course_user_data($USER->id);
+
+            if ($pending_update) {
+                $this->content->text .= '<i>'.get_string('pending', 'completion').'</i>';
+            } else if ($coursecomplete) {
+                $this->content->text .= get_string('complete');
+            } else if (!$criteriacomplete && !$ccompletion->timestarted) {
+                $this->content->text .= '<i>'.get_string('notyetstarted', 'completion').'</i>';
+            } else {
+                $this->content->text .= '<i>'.get_string('inprogress','completion').'</i>';
+            }
 
-        // Display completion status
-        $this->content->text  = '<table width="100%" style="font-size: 90%;"><tbody>';
-        $this->content->text .= '<tr><td colspan="2"><b>'.get_string('status').':</b> ';
-
-        // Is course complete?
-        $coursecomplete = $info->is_course_complete($USER->id);
-
-        // Load course completion
-        $params = array(
-            'userid' => $USER->id,
-            'course' => $COURSE->id
-        );
-        $ccompletion = new completion_completion($params);
-
-        // Has this user completed any criteria?
-        $criteriacomplete = $info->count_course_user_data($USER->id);
-
-        if ($pending_update) {
-            $this->content->text .= '<i>'.get_string('pending', 'completion').'</i>';
-        } else if ($coursecomplete) {
-            $this->content->text .= get_string('complete');
-        } else if (!$criteriacomplete && !$ccompletion->timestarted) {
-            $this->content->text .= '<i>'.get_string('notyetstarted', 'completion').'</i>';
-        } else {
-            $this->content->text .= '<i>'.get_string('inprogress','completion').'</i>';
-        }
+            $this->content->text .= '</td></tr>';
+            $this->content->text .= '<tr><td colspan="2">';
 
-        $this->content->text .= '</td></tr>';
-        $this->content->text .= '<tr><td colspan="2">';
+            // Get overall aggregation method
+            $overall = $info->get_aggregation_method();
 
-        // Get overall aggregation method
-        $overall = $info->get_aggregation_method();
+            if ($overall == COMPLETION_AGGREGATION_ALL) {
+                $this->content->text .= get_string('criteriarequiredall', 'completion');
+            } else {
+                $this->content->text .= get_string('criteriarequiredany', 'completion');
+            }
+
+            $this->content->text .= ':</td></tr>';
+            $this->content->text .= '<tr><td><b>'.get_string('requiredcriteria', 'completion').'</b></td><td style="text-align: right"><b>'.get_string('status').'</b></td></tr>';
+            $this->content->text .= $shtml.'</tbody></table>';
 
-        if ($overall == COMPLETION_AGGREGATION_ALL) {
-            $this->content->text .= get_string('criteriarequiredall', 'completion');
+            // Display link to detailed view
+            $details = new moodle_url('/blocks/completionstatus/details.php', array('course' => $course->id));
+            $this->content->footer = '<br><a href="'.$details->out().'">'.get_string('moredetails', 'completion').'</a>';
         } else {
-            $this->content->text .= get_string('criteriarequiredany', 'completion');
+            // If user is not enrolled, show error
+            $this->content->text = get_string('notenroled', 'completion');
         }
 
-        $this->content->text .= ':</td></tr>';
-        $this->content->text .= '<tr><td><b>'.get_string('requiredcriteria', 'completion').'</b></td><td style="text-align: right"><b>'.get_string('status').'</b></td></tr>';
-        $this->content->text .= $shtml.'</tbody></table>';
-
-        // Display link to detailed view
-        $this->content->footer = '<br><a href="'.$CFG->wwwroot.'/blocks/completionstatus/details.php?course='.$COURSE->id.'">'.get_string('moredetails', 'completion').'</a>';
-
+        if (has_capability('report/completion:view', $context)) {
+            $report = new moodle_url('/report/completion/index.php', array('course' => $course->id));
+            $this->content->footer .= '<br /><a href="'.$report->out().'">'.get_string('viewcoursereport', 'completion').'</a>';
+        }
         return $this->content;
     }
 }
index a1ac771..84406e3 100644 (file)
  *
  * @package    block
  * @subpackage completion
- * @copyright  2009 Catalyst IT Ltd
+ * @copyright  2009-2012 Catalyst IT Ltd
  * @author     Aaron Barnes <aaronb@catalyst.net.nz>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-require_once('../../config.php');
-require_once($CFG->libdir.'/completionlib.php');
-
-
-// TODO:  Make this page Moodle 2.0 compliant
+require_once(dirname(__FILE__).'/../../config.php');
+require_once("{$CFG->libdir}/completionlib.php");
 
 
 ///
 /// Load data
 ///
 $id = required_param('course', PARAM_INT);
-// User id
 $userid = optional_param('user', 0, PARAM_INT);
 
 // Load course
-$course = $DB->get_record('course', array('id' => $id));
+$course = $DB->get_record('course', array('id' => $id), '*', MUST_EXIST);
 
 // Load user
 if ($userid) {
@@ -76,21 +72,13 @@ if (!$can_view) {
 // Load completion data
 $info = new completion_info($course);
 
-$returnurl = "{$CFG->wwwroot}/course/view.php?id={$id}";
+$returnurl = new moodle_url('/course/view.php', array('id' => $id));
 
 // Don't display if completion isn't enabled!
 if (!$info->is_enabled()) {
     print_error('completionnotenabled', 'completion', $returnurl);
 }
 
-// Load criteria to display
-$completions = $info->get_completions($user->id);
-
-// Check if this course has any criteria
-if (empty($completions)) {
-    print_error('nocriteriaset', 'completion', $returnurl);
-}
-
 // Check this user is enroled
 if (!$info->is_tracked_user($user->id)) {
     if ($USER->id == $user->id) {
@@ -104,6 +92,7 @@ if (!$info->is_tracked_user($user->id)) {
 ///
 /// Display page
 ///
+$PAGE->set_context(context_course::instance($course->id));
 
 // Print header
 $page = get_string('completionprogressdetails', 'block_completionstatus');
@@ -111,7 +100,7 @@ $title = format_string($course->fullname) . ': ' . $page;
 
 $PAGE->navbar->add($page);
 $PAGE->set_pagelayout('standard');
-$PAGE->set_url('/blocks/completionstatus/details.php', array('course' => $course->id));
+$PAGE->set_url('/blocks/completionstatus/details.php', array('course' => $course->id, 'user' => $user->id));
 $PAGE->set_title(get_string('course') . ': ' . $course->fullname);
 $PAGE->set_heading($title);
 echo $OUTPUT->header();
@@ -135,122 +124,148 @@ $coursecomplete = $info->is_course_complete($user->id);
 // Has this user completed any criteria?
 $criteriacomplete = $info->count_course_user_data($user->id);
 
+// Load course completion
+$params = array(
+    'userid' => $user->id,
+    'course' => $course->id,
+);
+$ccompletion = new completion_completion($params);
+
 if ($coursecomplete) {
     echo get_string('complete');
-} else if (!$criteriacomplete) {
+} else if (!$criteriacomplete && !$ccompletion->timestarted) {
     echo '<i>'.get_string('notyetstarted', 'completion').'</i>';
 } else {
     echo '<i>'.get_string('inprogress','completion').'</i>';
 }
 
 echo '</td></tr>';
-echo '<tr><td colspan="2"><b>'.get_string('required').':</b> ';
 
-// Get overall aggregation method
-$overall = $info->get_aggregation_method();
+// Load criteria to display
+$completions = $info->get_completions($user->id);
 
-if ($overall == COMPLETION_AGGREGATION_ALL) {
-    echo get_string('criteriarequiredall', 'completion');
+// Check if this course has any criteria
+if (empty($completions)) {
+    echo '<tr><td colspan="2"><br />';
+    echo $OUTPUT->box(get_string('err_nocriteria', 'completion'), 'noticebox');
+    echo '</td></tr></tbody></table>';
 } else {
-    echo get_string('criteriarequiredany', 'completion');
-}
+    echo '<tr><td colspan="2"><b>'.get_string('required').':</b> ';
 
-echo '</td></tr></tbody></table>';
-
-// Generate markup for criteria statuses
-echo '<table class="generalbox boxaligncenter" cellpadding="3"><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>';
-echo '<th class="c2 header" scope="col">'.get_string('requirement', 'block_completionstatus').'</th>';
-echo '<th class="c3 header" scope="col">'.get_string('status').'</th>';
-echo '<th class="c4 header" scope="col">'.get_string('complete').'</th>';
-echo '<th class="c5 header" scope="col">'.get_string('completiondate', 'report_completion').'</th>';
-echo '</tr>';
-
-// Save row data
-$rows = array();
-
-global $COMPLETION_CRITERIA_TYPES;
-
-// Loop through course criteria
-foreach ($completions as $completion) {
-    $criteria = $completion->get_criteria();
-    $complete = $completion->is_complete();
-
-    $row = array();
-    $row['type'] = $criteria->criteriatype;
-    $row['title'] = $criteria->get_title();
-    $row['status'] = $completion->get_status();
-    $row['timecompleted'] = $completion->timecompleted;
-    $row['details'] = $criteria->get_details($completion);
-    $rows[] = $row;
-}
+    // Get overall aggregation method
+    $overall = $info->get_aggregation_method();
 
-// Print table
-$last_type = '';
-$agg_type = false;
+    if ($overall == COMPLETION_AGGREGATION_ALL) {
+        echo get_string('criteriarequiredall', 'completion');
+    } else {
+        echo get_string('criteriarequiredany', 'completion');
+    }
+
+    echo '</td></tr></tbody></table>';
+
+    // Generate markup for criteria statuses
+    echo '<table class="generalbox 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>';
+    echo '<th class="c2 header" scope="col">'.get_string('requirement', 'block_completionstatus').'</th>';
+    echo '<th class="c3 header" scope="col">'.get_string('status').'</th>';
+    echo '<th class="c4 header" scope="col">'.get_string('complete').'</th>';
+    echo '<th class="c5 header" scope="col">'.get_string('completiondate', 'report_completion').'</th>';
+    echo '</tr>';
 
-foreach ($rows as $row) {
+    // Save row data
+    $rows = array();
+
+    // Loop through course criteria
+    foreach ($completions as $completion) {
+        $criteria = $completion->get_criteria();
+
+        $row = array();
+        $row['type'] = $criteria->criteriatype;
+        $row['title'] = $criteria->get_title();
+        $row['status'] = $completion->get_status();
+        $row['complete'] = $completion->is_complete();
+        $row['timecompleted'] = $completion->timecompleted;
+        $row['details'] = $criteria->get_details($completion);
+        $rows[] = $row;
+    }
 
-    // Criteria group
-    echo '<td class="c0">';
-    if ($last_type !== $row['details']['type']) {
-        $last_type = $row['details']['type'];
-        echo $last_type;
+    // Print table
+    $last_type = '';
+    $agg_type = false;
+    $oddeven = 0;
 
-        // Reset agg type
-        $agg_type = true;
-    } else {
-        // Display aggregation type
-        if ($agg_type) {
-            $agg = $info->get_aggregation_method($row['type']);
+    foreach ($rows as $row) {
 
-            echo '(<i>';
+        echo '<tr class="r' . $oddeven . '">';
 
-            if ($agg == COMPLETION_AGGREGATION_ALL) {
-                echo strtolower(get_string('all', 'completion'));
-            } else {
-                echo strtolower(get_string('any', 'completion'));
-            }
+        // Criteria group
+        echo '<td class="cell c0">';
+        if ($last_type !== $row['details']['type']) {
+            $last_type = $row['details']['type'];
+            echo $last_type;
+
+            // Reset agg type
+            $agg_type = true;
+        } else {
+            // Display aggregation type
+            if ($agg_type) {
+                $agg = $info->get_aggregation_method($row['type']);
 
-            echo '</i> '.strtolower(get_string('required')).')';
-            $agg_type = false;
+                echo '(<i>';
+
+                if ($agg == COMPLETION_AGGREGATION_ALL) {
+                    echo strtolower(get_string('aggregateall', 'completion'));
+                } else {
+                    echo strtolower(get_string('aggregateany', 'completion'));
+                }
+
+                echo '</i> '.strtolower(get_string('required')).')';
+                $agg_type = false;
+            }
         }
+        echo '</td>';
+
+        // Criteria title
+        echo '<td class="cell c1">';
+        echo $row['details']['criteria'];
+        echo '</td>';
+
+        // Requirement
+        echo '<td class="cell c2">';
+        echo $row['details']['requirement'];
+        echo '</td>';
+
+        // Status
+        echo '<td class="cell c3">';
+        echo $row['details']['status'];
+        echo '</td>';
+
+        // Is complete
+        echo '<td class="cell c4">';
+        echo $row['complete'] ? get_string('yes') : get_string('no');
+        echo '</td>';
+
+        // Completion data
+        echo '<td class="cell c5">';
+        if ($row['timecompleted']) {
+            echo userdate($row['timecompleted'], get_string('strftimedate', 'langconfig'));
+        } else {
+            echo '-';
+        }
+        echo '</td>';
+        echo '</tr>';
+        // for row striping
+        $oddeven = $oddeven ? 0 : 1;
     }
-    echo '</td>';
-
-    // Criteria title
-    echo '<td class="c1">';
-    echo $row['details']['criteria'];
-    echo '</td>';
-
-    // Requirement
-    echo '<td class="c2">';
-    echo $row['details']['requirement'];
-    echo '</td>';
-
-    // Status
-    echo '<td class="c3">';
-    echo $row['details']['status'];
-    echo '</td>';
-
-    // Is complete
-    echo '<td class="c4">';
-    echo ($row['status'] === get_string('yes')) ? get_string('yes') : get_string('no');
-    echo '</td>';
-
-    // Completion data
-    echo '<td class="c5">';
-    if ($row['timecompleted']) {
-        echo userdate($row['timecompleted'], '%e %B %G');
-    } else {
-        echo '-';
-    }
-    echo '</td>';
-    echo '</tr>';
+
+    echo '</tbody></table>';
 }
 
-echo '</tbody></table>';
+echo '<div class="buttons">';
+$courseurl = new moodle_url("/course/view.php", array('id' => $course->id));
+echo $OUTPUT->single_button($courseurl, get_string('returntocourse', 'block_completionstatus'), 'get');
+echo '</div>';
 
 echo $OUTPUT->footer();
index fcc965a..6658c17 100644 (file)
@@ -5,3 +5,4 @@ $string['criteriagroup'] = 'Criteria group';
 $string['firstofsecond'] = '{$a->first} of {$a->second}';
 $string['pluginname'] = 'Course completion status';
 $string['requirement'] = 'Requirement';
+$string['returntocourse'] = 'Return to course';
index df79e3b..72b60cb 100644 (file)
@@ -64,7 +64,7 @@ class block_course_overview extends block_base {
             $courses_limit = $courses_limit + 1;
         }
 
-        $courses = enrol_get_my_courses('id, shortname, modinfo', 'visible DESC,sortorder ASC', $courses_limit);
+        $courses = enrol_get_my_courses('id, shortname, modinfo, sectioncache', 'visible DESC,sortorder ASC', $courses_limit);
         $site = get_site();
         $course = $site; //just in case we need the old global $course hack
 
index 5560a32..4eff68c 100644 (file)
@@ -164,7 +164,7 @@ M.core_dock.init = function(Y) {
     var dock = Y.one('#dock');
     if (!dock) {
         // Start the construction of the dock
-        dock = Y.Node.create('<div id="dock" class="'+css.dock+' '+css.dock+'_'+this.cfg.position+'_'+this.cfg.orientation+'"></div>')
+        dock = Y.Node.create('<div id="dock" role="menubar" class="'+css.dock+' '+css.dock+'_'+this.cfg.position+'_'+this.cfg.orientation+'"></div>')
                     .append(Y.Node.create('<div class="'+css.buttonscontainer+'"></div>')
                         .append(Y.Node.create('<div class="'+css.dockeditemcontainer+'"></div>')));
         this.nodes.body.append(dock);
@@ -863,6 +863,12 @@ M.core_dock.genericblock.prototype = {
             return;
         }
 
+        // Disable the skip anchor when docking
+        var skipanchor = node.previous();
+        if (skipanchor.hasClass('skip-block')) {
+            skipanchor.hide();
+        }
+
         var blockclass = (function(classes){
             var r = /(^|\s)(block_[a-zA-Z0-9_]+)(\s|$)/;
             var m = r.exec(classes);
@@ -937,6 +943,12 @@ M.core_dock.genericblock.prototype = {
     return_to_block : function(dockitem) {
         var placeholder = this.Y.one('#content_placeholder_'+this.id);
 
+        // Enable the skip anchor when going back to block mode
+        var skipanchor = placeholder.previous();
+        if (skipanchor.hasClass('skip-block')) {
+            skipanchor.show();
+        }
+
         if (this.cachedcontentnode.one('.header')) {
             this.cachedcontentnode.one('.header').insert(dockitem.contents, 'after');
         } else {
@@ -1024,7 +1036,7 @@ M.core_dock.item.prototype = {
         var Y = this.Y;
         var css = M.core_dock.css;
 
-        this.nodes.docktitle = Y.Node.create('<div id="dock_item_'+this.id+'_title" class="'+css.dockedtitle+'"></div>');
+        this.nodes.docktitle = Y.Node.create('<div id="dock_item_'+this.id+'_title" role="menu" aria-haspopup="true" class="'+css.dockedtitle+'"></div>');
         this.nodes.docktitle.append(this.title);
         this.nodes.dockitem = Y.Node.create('<div id="dock_item_'+this.id+'" class="'+css.dockeditem+'" tabindex="0"></div>');
         this.nodes.dockitem.on('dock:actionkey', this.toggle, this);
@@ -1053,6 +1065,8 @@ M.core_dock.item.prototype = {
         this.active = true;
         // Add active item class first up
         this.nodes.docktitle.addClass(css.activeitem);
+        // Set aria-exapanded property to true.
+        this.nodes.docktitle.set('aria-expanded', "true");
         this.fire('dockeditem:showcomplete');
         M.core_dock.resize();
         return true;
@@ -1069,6 +1083,8 @@ M.core_dock.item.prototype = {
         this.nodes.docktitle.removeClass(css.activeitem);
         // Hide the panel
         M.core_dock.getPanel().hide();
+        // Set aria-exapanded property to false
+        this.nodes.docktitle.set('aria-expanded', "false");
         this.fire('dockeditem:hidecomplete');
     },
     /**
index 4c3d28c..92e2831 100644 (file)
@@ -121,18 +121,20 @@ class block_navigation_renderer extends plugin_renderer_base {
 
             // this applies to the li item which contains all child lists too
             $liclasses = array($item->get_css_type(), 'depth_'.$depth);
+            $liexpandable = array();
             if ($item->has_children() && (!$item->forceopen || $item->collapse)) {
                 $liclasses[] = 'collapsed';
             }
             if ($isbranch) {
                 $liclasses[] = 'contains_branch';
+                $liexpandable = array('aria-expanded' => in_array('collapsed', $liclasses) ? "false" : "true");
             } else if ($hasicon) {
                 $liclasses[] = 'item_with_icon';
             }
             if ($item->isactive === true) {
                 $liclasses[] = 'current_branch';
             }
-            $liattr = array('class'=>join(' ',$liclasses));
+            $liattr = array('class' => join(' ',$liclasses)) + $liexpandable;
             // class attribute on the div item which only contains the item content
             $divclasses = array('tree_item');
             if ($isbranch) {
index 180977d..2189d51 100644 (file)
@@ -162,16 +162,20 @@ TREE.prototype = {
                 switch (e.action) {
                     case 'expand' :
                         target.removeClass('collapsed');
+                        target.set('aria-expanded', true);
                         break;
                     case 'collapse' :
                         target.addClass('collapsed');
+                        target.set('aria-expanded', false);
                         break;
                     default :
                         target.toggleClass('collapsed');
+                        target.set('aria-expanded', !target.hasClass('collapsed'));
                 }
                 e.halt();
             } else {
                 target.toggleClass('collapsed');
+                target.set('aria-expanded', !target.hasClass('collapsed'));
             }
         }
 
@@ -180,6 +184,7 @@ TREE.prototype = {
             target.siblings('li').each(function(){
                 if (this.get('id') !== target.get('id') && !this.hasClass('collapsed')) {
                     this.addClass('collapsed');
+                    this.set('aria-expanded', false);
                 }
             });
         }
@@ -287,6 +292,7 @@ BRANCH.prototype = {
         }
         if (isbranch) {
             branchli.addClass('collapsed').addClass('contains_branch');
+            branchli.set('aria-expanded', false);
             branchp.addClass('branch');
         }
 
index 6fcd152..24e9ca0 100644 (file)
@@ -106,7 +106,7 @@ class block_news_items extends block_base {
                     $tooltiptext = get_string('rsssubscriberssposts','forum');
                 }
                 if (!isloggedin()) {
-                    $userid = 0;
+                    $userid = $CFG->siteguest;
                 } else {
                     $userid = $USER->id;
                 }
index 086983d..38f8856 100644 (file)
 
         $r = html_writer::start_tag('li');
             $r.= html_writer::start_tag('div',array('class'=>'link'));
-                $r.= html_writer::link(clean_param($link,PARAM_URL), s($title), array('onclick'=>'this.target="_blank"'));
+                $r.= html_writer::link($link, s($title), array('onclick'=>'this.target="_blank"'));
             $r.= html_writer::end_tag('div');
 
             if($this->config->display_description && !empty($description)){
index efc2fbc..a2765da 100644 (file)
@@ -66,7 +66,7 @@ for($i = 1; $i < 3; $i++){
 ?>
     <tr valign="top">
         <td align="right">
-            <?php print_string('numsections'.$i, 'block_section_links'); ?>:
+            <label for="menunumsections<?php echo $i; ?>"><?php print_string('numsections'.$i, 'block_section_links'); ?>:</label>
         </td>
         <td>
             <?php choose_from_menu($numberofsections, 'numsections'.$i, $selected[$i][0]); ?>
@@ -77,7 +77,7 @@ for($i = 1; $i < 3; $i++){
     </tr>
     <tr valign="top">
         <td align="right">
-            <?php print_string('incby'.$i, 'block_section_links'); ?>:
+            <label for="menuincby<?php echo $i;?>"><?php print_string('incby'.$i, 'block_section_links'); ?>:</label>
         </td>
         <td>
             <?php choose_from_menu($increments, 'incby'.$i, $selected[$i][1]); ?>
index 41cea87..a19d41e 100644 (file)
@@ -40,18 +40,20 @@ class block_settings_renderer extends plugin_renderer_base {
 
             // this applies to the li item which contains all child lists too
             $liclasses = array($item->get_css_type());
+            $liexpandable = array();
             if (!$item->forceopen || (!$item->forceopen && $item->collapse) || ($item->children->count()==0  && $item->nodetype==navigation_node::NODETYPE_BRANCH)) {
                 $liclasses[] = 'collapsed';
             }
             if ($isbranch) {
                 $liclasses[] = 'contains_branch';
+                $liexpandable = array('aria-expanded' => in_array('collapsed', $liclasses) ? "false" : "true");
             } else if ($hasicon) {
                 $liclasses[] = 'item_with_icon';
             }
             if ($item->isactive === true) {
                 $liclasses[] = 'current_branch';
             }
-            $liattr = array('class'=>join(' ',$liclasses));
+            $liattr = array('class' => join(' ',$liclasses)) + $liexpandable;
             // class attribute on the div item which only contains the item content
             $divclasses = array('tree_item');
             if ($isbranch) {
index b7a35fd..6183a9b 100644 (file)
@@ -40,6 +40,7 @@ class block_tags extends block_base {
         global $CFG, $COURSE, $SITE, $USER, $SCRIPT, $OUTPUT;
 
         if (empty($CFG->usetags)) {
+            $this->content = new stdClass();
             $this->content->text = '';
             if ($this->page->user_is_editing()) {
                 $this->content->text = get_string('disabledtags', 'block_tags');
@@ -225,7 +226,6 @@ class block_tags extends block_base {
             if ($officialtags) { $this->content->text .= $officialtagscontent; }
             if ($coursetags) { $this->content->text .= $coursetagscontent; }
             if ($commtags) { $this->content->text .= $commtagscontent; }
-
             // add the input form section (allowing a user to tag the current course) and navigation, or loggin message
             if ($loggedin) {
                 // only show the input form on course pages for those allowed (or not barred)
@@ -250,7 +250,8 @@ class block_tags extends block_base {
                             <div class="coursetag_form_wrapper">
                             <div class="coursetag_form_positioner">
                                 <div class="coursetag_form_input1">
-                                    <input type="text" name="coursetag_sug_keyword" class="coursetag_form_input1a" disabled="disabled" />
+                                    <label class="accesshide" for="coursetag_sug_keyword">$tagthisunit</label>
+                                    <input type="text" name="coursetag_sug_keyword" id="coursetag_sug_keyword" class="coursetag_form_input1a" disabled="disabled" />
                                 </div>
                                 <div class="coursetag_form_input2">
                                     <input type="text" name="coursetag_new_tag" id="coursetag_new_tag" class="coursetag_form_input2a"
index 0643b91..265cd5a 100644 (file)
@@ -82,6 +82,7 @@ $string['pluginname'] = 'Tags';
 $string['select'] = 'Select...';
 $string['showcoursetags'] = 'Show course tags';
 $string['showcoursetagsdef'] = 'Display the course tagging features in the tags block, allowing students to tag courses.';
+$string['suggestedtagthisunit'] = 'Suggested tag to this course:';
 $string['tags'] = 'tags';
 $string['tagthisunit'] = 'Tag this course:';
 $string['tagunits'] = 'to tag your favourite courses';
index 292d55c..1def593 100644 (file)
@@ -71,24 +71,28 @@ class blog_edit_form extends moodleform {
         $allmodnames = array();
 
         if (!empty($CFG->useblogassociations)) {
-            if ((!empty($entry->courseassoc) || (!empty($courseid) && empty($modid))) && has_capability('moodle/blog:associatecourse', $sitecontext)) {
+            if ((!empty($entry->courseassoc) || (!empty($courseid) && empty($modid)))) {
                 if (!empty($courseid)) {
                     $course = $DB->get_record('course', array('id' => $courseid));
-                    $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));
-                    $context = get_context_instance(CONTEXT_COURSE, $courseid);
+                    $context = context_course::instance($courseid);
                     $a = new stdClass();
                     $a->coursename = format_string($course->fullname, true, array('context' => $context));
                     $contextid = $context->id;
                 } else {
+                    $context = context::instance_by_id($entry->courseassoc);
                     $sql = 'SELECT fullname FROM {course} cr LEFT JOIN {context} ct ON ct.instanceid = cr.id WHERE ct.id = ?';
                     $a = new stdClass();
                     $a->coursename = $DB->get_field_sql($sql, array($entry->courseassoc));
                     $contextid = $entry->courseassoc;
                 }
 
-                $mform->addElement('advcheckbox', 'courseassoc', get_string('associatewithcourse', 'blog', $a), null, null, array(0, $contextid));
-                $mform->setDefault('courseassoc', $contextid);
-            } else if ((!empty($entry->modassoc) || !empty($modid)) && has_capability('moodle/blog:associatemodule', $sitecontext)) {
+                if (has_capability('moodle/blog:associatecourse', $context)) {
+                    $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));\r
+                    $mform->addElement('advcheckbox', 'courseassoc', get_string('associatewithcourse', 'blog', $a), null, null, array(0, $contextid));\r
+                    $mform->setDefault('courseassoc', $contextid);
+                }
+
+            } else if ((!empty($entry->modassoc) || !empty($modid))) {
                 if (!empty($modid)) {
                     $mod = get_coursemodule_from_id(false, $modid);
                     $a = new stdClass();
@@ -101,11 +105,14 @@ class blog_edit_form extends moodleform {
                     $a = new stdClass();
                     $a->modtype = $DB->get_field('modules', 'name', array('id' => $cm->module));
                     $a->modname = $DB->get_field($a->modtype, 'name', array('id' => $cm->instance));
+                    $modid = $context->instanceid;
                 }
 
-                $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));
-                $mform->addElement('advcheckbox', 'modassoc', get_string('associatewithmodule', 'blog', $a), null, null, array(0, $context->id));
-                $mform->setDefault('modassoc', $context->id);
+                if (has_capability('moodle/blog:associatemodule', $context)) {
+                    $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));
+                    $mform->addElement('advcheckbox', 'modassoc', get_string('associatewithmodule', 'blog', $a), null, null, array(0, $context->id));
+                    $mform->setDefault('modassoc', $context->id);
+                }
             }
         }
 
@@ -131,13 +138,13 @@ class blog_edit_form extends moodleform {
         global $CFG, $DB, $USER;
 
         $errors = array();
-        $sitecontext = get_context_instance(CONTEXT_SYSTEM);
 
         // validate course association
-        if (!empty($data['courseassoc']) && has_capability('moodle/blog:associatecourse', $sitecontext)) {
+        if (!empty($data['courseassoc'])) {
             $coursecontext = context::instance_by_id($data['courseassoc'], IGNORE_MISSING);
 
-            if ($coursecontext and $coursecontext->contextlevel == CONTEXT_COURSE)  {
+        &nbs