Merge branch 'MDL-49840-master' of git://github.com/andrewnicols/moodle
authorDavid Monllao <davidm@moodle.com>
Fri, 1 May 2015 03:05:59 +0000 (11:05 +0800)
committerDavid Monllao <davidm@moodle.com>
Fri, 1 May 2015 03:05:59 +0000 (11:05 +0800)
662 files changed:
admin/cli/install.php
admin/cli/mysql_compressed_rows.php
admin/environment.xml
admin/index.php
admin/registration/confirmregistration.php
admin/registration/renderer.php
admin/renderer.php
admin/roles/assign.php
admin/roles/check.php
admin/roles/permissions.php
admin/settings/appearance.php
admin/settings/grades.php
admin/settings/location.php
admin/tests/behat/display_short_names.feature
admin/tests/behat/filter_users.feature
admin/tests/behat/set_admin_settings_value.feature
admin/tests/behat/upload_users.feature
admin/tool/availabilityconditions/tests/behat/manage_conditions.feature
admin/tool/behat/cli/init.php
admin/tool/behat/cli/run.php
admin/tool/behat/cli/util.php
admin/tool/behat/cli/util_single_run.php
admin/tool/behat/tests/behat/basic_actions.feature
admin/tool/behat/tests/behat/data_generators.feature
admin/tool/behat/tests/behat/edit_permissions.feature
admin/tool/behat/tests/behat/get_and_set_fields.feature
admin/tool/behat/tests/behat/manipulate_forms.feature
admin/tool/behat/tests/behat/nasty_strings.feature
admin/tool/behat/tests/behat/test_environment.feature
admin/tool/filetypes/tests/behat/add_filetypes.feature
admin/tool/monitor/classes/output/managesubs/renderer.php
admin/tool/monitor/classes/output/managesubs/rules.php
admin/tool/monitor/index.php
admin/tool/monitor/lang/en/tool_monitor.php
admin/tool/monitor/lib.php
admin/tool/monitor/tests/behat/rule.feature
admin/tool/monitor/tests/behat/subscription.feature
admin/tool/templatelibrary/amd/build/display.min.js [new file with mode: 0644]
admin/tool/templatelibrary/amd/build/search.min.js [new file with mode: 0644]
admin/tool/templatelibrary/amd/src/display.js [new file with mode: 0644]
admin/tool/templatelibrary/amd/src/search.js [new file with mode: 0644]
admin/tool/templatelibrary/classes/api.php [new file with mode: 0644]
admin/tool/templatelibrary/classes/external.php [new file with mode: 0644]
admin/tool/templatelibrary/classes/output/list_templates_page.php [new file with mode: 0644]
admin/tool/templatelibrary/classes/output/renderer.php [new file with mode: 0644]
admin/tool/templatelibrary/db/services.php [new file with mode: 0644]
admin/tool/templatelibrary/index.php [new file with mode: 0644]
admin/tool/templatelibrary/lang/en/tool_templatelibrary.php [new file with mode: 0644]
admin/tool/templatelibrary/settings.php [new file with mode: 0644]
admin/tool/templatelibrary/styles.css [new file with mode: 0644]
admin/tool/templatelibrary/templates/display_template.mustache [new file with mode: 0644]
admin/tool/templatelibrary/templates/list_templates_page.mustache [new file with mode: 0644]
admin/tool/templatelibrary/templates/search_results.mustache [new file with mode: 0644]
admin/tool/templatelibrary/tests/externallib_test.php [new file with mode: 0644]
admin/tool/templatelibrary/version.php [new file with mode: 0644]
admin/tool/uploadcourse/tests/behat/create.feature
admin/tool/uploadcourse/tests/behat/update.feature
admin/tool/uploaduser/locallib.php
auth/cas/db/upgrade.php
auth/cas/version.php
auth/email/lang/en/auth_email.php
auth/ldap/db/upgrade.php
auth/ldap/tests/plugin_test.php
auth/ldap/version.php
auth/tests/behat/login.feature
availability/condition/completion/tests/behat/availability_completion.feature
availability/condition/date/tests/behat/availability_date.feature
availability/condition/grade/tests/behat/availability_grade.feature
availability/condition/grade/yui/build/moodle-availability_grade-form/moodle-availability_grade-form-debug.js
availability/condition/grade/yui/build/moodle-availability_grade-form/moodle-availability_grade-form-min.js
availability/condition/grade/yui/build/moodle-availability_grade-form/moodle-availability_grade-form.js
availability/condition/grade/yui/src/form/js/form.js
availability/condition/group/tests/behat/availability_group.feature
availability/condition/grouping/tests/behat/availability_grouping.feature
availability/condition/profile/tests/behat/availability_profile.feature
availability/tests/behat/display_availability.feature
availability/tests/behat/edit_availability.feature
backup/converter/moodle1/tests/fixtures/moodle.xml
backup/moodle2/restore_stepslib.php
backup/moodle2/tests/moodle2_course_format_test.php [new file with mode: 0644]
backup/util/helper/backup_cron_helper.class.php
backup/util/helper/backup_general_helper.class.php
backup/util/ui/tests/behat/backup_courses.feature
backup/util/ui/tests/behat/behat_backup.php
backup/util/ui/tests/behat/duplicate_activities.feature
backup/util/ui/tests/behat/import_course.feature
backup/util/ui/tests/behat/import_groups.feature
backup/util/ui/tests/behat/restore_moodle2_courses.feature
badges/lib.php [new file with mode: 0644]
badges/mybackpack.php
badges/mybadges.php
badges/preferences.php
badges/renderer.php
badges/tests/behat/add_badge.feature
badges/tests/behat/award_badge.feature
badges/view.php
blocks/activity_modules/tests/behat/block_activity_modules.feature
blocks/activity_results/lang/en/block_activity_results.php
blocks/activity_results/tests/behat/addblockinactivity.feature
blocks/activity_results/tests/behat/addunconfiguredblock.feature
blocks/activity_results/tests/behat/addunsupportedactivity.feature
blocks/activity_results/tests/behat/highscoreswithoutgroups.feature
blocks/activity_results/tests/behat/highscoreswithseperategroups.feature
blocks/activity_results/tests/behat/highscoreswithvisiblegroups.feature
blocks/activity_results/tests/behat/lowscoreswithoutgroups.feature
blocks/activity_results/tests/behat/lowscoreswithseperategroups.feature
blocks/activity_results/tests/behat/lowscoreswithvisiblegroups.feature
blocks/admin_bookmarks/lang/en/block_admin_bookmarks.php
blocks/badges/lang/en/block_badges.php
blocks/calendar_month/lang/en/block_calendar_month.php
blocks/calendar_upcoming/lang/en/block_calendar_upcoming.php
blocks/comments/lang/en/block_comments.php
blocks/comments/tests/behat/add_comment.feature
blocks/comments/tests/behat/delete_comment.feature
blocks/community/lang/en/block_community.php
blocks/course_list/lang/en/block_course_list.php
blocks/course_overview/lang/en/block_course_overview.php
blocks/course_summary/tests/behat/block_course_summary_course.feature
blocks/course_summary/tests/behat/block_course_summary_frontpage.feature
blocks/glossary_random/lang/en/block_glossary_random.php
blocks/glossary_random/tests/behat/glossary_random.feature
blocks/glossary_random/tests/behat/glossary_random_frontpage.feature
blocks/html/lang/en/block_html.php
blocks/html/tests/behat/configuring_html_block.feature
blocks/html/tests/behat/course_block.feature
blocks/html/tests/behat/multiple_instances.feature
blocks/login/tests/behat/login_block.feature
blocks/mentees/lang/en/block_mentees.php
blocks/messages/lang/en/block_messages.php
blocks/mnet_hosts/lang/en/block_mnet_hosts.php
blocks/moodleblock.class.php
blocks/myprofile/lang/en/block_myprofile.php
blocks/navigation/lang/en/block_navigation.php
blocks/navigation/tests/behat/expand_courses_node.feature
blocks/navigation/tests/behat/expand_my_courses_setting.feature
blocks/navigation/tests/behat/view_my_courses.feature
blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-debug.js
blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-min.js
blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation.js
blocks/navigation/yui/src/navigation/js/navigation.js
blocks/news_items/lang/en/block_news_items.php
blocks/news_items/tests/behat/display_news.feature
blocks/online_users/lang/en/block_online_users.php
blocks/participants/tests/behat/block_participants_course.feature
blocks/participants/tests/behat/block_participants_frontpage.feature
blocks/private_files/lang/en/block_private_files.php
blocks/quiz_results/lang/en/block_quiz_results.php
blocks/recent_activity/tests/behat/structural_changes.feature
blocks/rss_client/lang/en/block_rss_client.php
blocks/settings/lang/en/block_settings.php
blocks/settings/renderer.php
blocks/tags/lang/en/block_tags.php
blocks/tests/behat/add_blocks.feature
blocks/tests/behat/configure_block_throughout_site.feature
blocks/tests/behat/hide_blocks.feature
blocks/tests/behat/manage_blocks.feature
blocks/tests/behat/restrict_available_blocks.feature
blocks/tests/behat/return_block_original_state.feature
blocks/upgrade.txt
blog/edit.php
blog/external_blog_edit.php
blog/external_blogs.php
blog/index.php
blog/lib.php
blog/preferences.php
blog/tests/behat/comment.feature
blog/tests/bloglib_test.php
cache/stores/memcache/lang/en/cachestore_memcache.php
cache/stores/memcached/lang/en/cachestore_memcached.php
calendar/tests/behat/calendar.feature
calendar/tests/behat/minicalendar.feature
calendar/tests/externallib_test.php
cohort/tests/behat/access_visible_cohorts.feature
cohort/tests/behat/add_cohort.feature
cohort/tests/behat/behat_cohort.php
cohort/tests/behat/upload_cohort_users.feature
cohort/tests/behat/upload_cohorts.feature
cohort/tests/behat/view_cohorts.feature
cohort/tests/externallib_test.php
completion/tests/behat/enable_manual_complete_mark.feature
completion/tests/behat/restrict_activity_by_date.feature
completion/tests/behat/restrict_activity_by_grade.feature
completion/tests/behat/restrict_section_availability.feature
completion/tests/behat/teacher_manual_completion.feature
course/category.ajax.php
course/format/lib.php
course/format/social/tests/behat/social_adjust_discussion_count.feature
course/format/topics/tests/behat/edit_delete_sections.feature
course/format/weeks/tests/behat/edit_delete_sections.feature
course/index.php
course/modlib.php
course/renderer.php
course/tests/behat/activities_edit_completion.feature
course/tests/behat/activities_edit_with_block_dock.feature
course/tests/behat/activities_group_icons.feature
course/tests/behat/activities_indentation.feature
course/tests/behat/activities_visibility_icons.feature
course/tests/behat/add_activities.feature
course/tests/behat/course_controls.feature
course/tests/behat/course_creation.feature
course/tests/behat/edit_settings.feature
course/tests/behat/force_group_mode.feature
course/tests/behat/frontpage_display_modes.feature
course/tests/behat/max_number_sections.feature
course/tests/behat/move_activities.feature
course/tests/behat/move_sections.feature
course/tests/behat/navigate_course_list.feature [new file with mode: 0644]
course/tests/behat/paged_course_navigation.feature
course/tests/behat/rename_roles.feature
course/tests/behat/restrict_available_activities.feature
course/tests/behat/section_highlighting.feature
course/tests/behat/section_visibility.feature
course/tests/behat/view_subfolders_inline.feature [new file with mode: 0644]
course/tests/externallib_test.php
course/user.php
course/view.php
course/yui/build/moodle-course-categoryexpander/moodle-course-categoryexpander-debug.js
course/yui/build/moodle-course-categoryexpander/moodle-course-categoryexpander-min.js
course/yui/build/moodle-course-categoryexpander/moodle-course-categoryexpander.js
course/yui/src/categoryexpander/js/categoryexpander.js
enrol/cohort/lang/en/enrol_cohort.php
enrol/cohort/lib.php
enrol/cohort/locallib.php
enrol/cohort/tests/cohortlib_test.php
enrol/guest/tests/behat/guest_access.feature
enrol/imsenterprise/tests/imsenterprise_test.php
enrol/index.php
enrol/manual/yui/quickenrolment/quickenrolment.js
enrol/meta/addinstance.php
enrol/meta/addinstance_form.php
enrol/meta/lang/en/enrol_meta.php
enrol/meta/lib.php
enrol/meta/locallib.php
enrol/meta/tests/behat/enrol_meta.feature [new file with mode: 0644]
enrol/meta/tests/plugin_test.php
enrol/self/lib.php
enrol/self/tests/behat/self_enrolment.feature
enrol/self/tests/externallib_test.php
enrol/tests/behat/add_to_group.feature
enrol/tests/externallib_test.php
enrol/upgrade.txt
enrol/users.php
files/tests/behat/course_files.feature
files/tests/externallib_test.php
files/upgrade.txt [new file with mode: 0644]
grade/edit/tree/lib.php
grade/export/txt/tests/behat/export.feature
grade/export/xml/tests/behat/export.feature
grade/grading/form/rubric/tests/behat/edit_rubric.feature
grade/grading/form/rubric/tests/behat/publish_rubric_templates.feature
grade/grading/form/rubric/tests/behat/reuse_own_rubrics.feature
grade/import/csv/tests/load_data_test.php
grade/lib.php
grade/report/grader/module.js
grade/report/history/tests/behat/basic_functionality.feature
grade/report/lib.php
grade/report/mygrades.php [new file with mode: 0644]
grade/report/overview/index.php
grade/report/overview/lib.php
grade/report/singleview/classes/local/screen/grade.php
grade/report/singleview/classes/local/screen/user.php
grade/report/singleview/classes/local/ui/override.php
grade/report/singleview/index.php
grade/report/singleview/styles.css
grade/report/singleview/tests/behat/bulk_insert_grades.feature [new file with mode: 0644]
grade/report/singleview/tests/behat/singleview.feature
grade/report/user/index.php
grade/report/user/lib.php
grade/report/user/tests/externallib_test.php
grade/tests/behat/grade_UI_settings.feature
grade/tests/behat/grade_aggregation.feature
grade/tests/behat/grade_calculated_weights.feature
grade/tests/behat/grade_contribution_with_extra_credit.feature
grade/tests/behat/grade_mingrade.feature
grade/tests/behat/grade_natural_normalisation.feature
grade/tests/behat/grade_override_letter.feature
grade/tests/behat/grade_point_maximum.feature
grade/tests/behat/grade_scales.feature
grade/tests/behat/grade_scales_aggregation.feature
grade/tests/behat/grade_single_item_scales.feature
grade/tests/behat/grade_to_pass.feature
grade/tests/behat/grade_view.feature
group/index.php
group/lib.php
group/tests/behat/auto_creation.feature
group/tests/behat/behat_groups.php
group/tests/behat/create_groups.feature
group/tests/behat/delete_groups.feature
group/tests/behat/groups_import.feature
group/tests/behat/id_uniqueness.feature
group/tests/behat/update_groups.feature
index.php
install/lang/ja/error.php
install/lang/mn/moodle.php
install/lang/oc_lnc/admin.php
install/lang/zh_tw/error.php
install/lang/zh_tw/install.php
lang/en/admin.php
lang/en/badges.php
lang/en/blog.php
lang/en/deprecated.txt
lang/en/error.php
lang/en/grades.php
lang/en/mnet.php
lang/en/moodle.php
lang/en/my.php
lang/en/notes.php
lang/en/pagetype.php
lang/en/repository.php
lang/en/role.php
lang/en/webservice.php
lib/accesslib.php
lib/adminlib.php
lib/ajax/getnavbranch.php
lib/badgeslib.php
lib/behat/classes/behat_command.php
lib/behat/classes/behat_config_manager.php
lib/behat/classes/util.php
lib/classes/date.php
lib/classes/output/mustache_filesystem_loader.php
lib/classes/plugin_manager.php
lib/classes/update/checker.php
lib/coursecatlib.php
lib/db/upgrade.php
lib/ddl/mysql_sql_generator.php
lib/deprecatedlib.php
lib/dml/moodle_database.php
lib/dml/tests/dml_test.php
lib/editor/atto/plugins/accessibilitychecker/tests/behat/accessibilitychecker.feature
lib/editor/atto/plugins/accessibilityhelper/tests/behat/accessibilityhelper.feature
lib/editor/atto/plugins/align/tests/behat/align.feature
lib/editor/atto/plugins/bold/tests/behat/bold.feature
lib/editor/atto/plugins/charmap/tests/behat/charmap.feature
lib/editor/atto/plugins/clear/tests/behat/clear.feature
lib/editor/atto/plugins/collapse/tests/behat/collapse.feature
lib/editor/atto/plugins/equation/tests/behat/equation.feature
lib/editor/atto/plugins/html/tests/behat/html.feature
lib/editor/atto/plugins/image/tests/behat/image.feature
lib/editor/atto/plugins/indent/tests/behat/indent.feature
lib/editor/atto/plugins/italic/tests/behat/italic.feature
lib/editor/atto/plugins/link/tests/behat/link.feature
lib/editor/atto/plugins/media/tests/behat/media.feature
lib/editor/atto/plugins/orderedlist/tests/behat/orderedlist.feature
lib/editor/atto/plugins/strike/tests/behat/strike.feature
lib/editor/atto/plugins/subscript/tests/behat/subscript.feature
lib/editor/atto/plugins/superscript/tests/behat/superscript.feature
lib/editor/atto/plugins/table/tests/behat/table.feature
lib/editor/atto/plugins/title/tests/behat/title.feature
lib/editor/atto/plugins/underline/tests/behat/underline.feature
lib/editor/atto/plugins/unorderedlist/tests/behat/unorderedlist.feature
lib/editor/atto/styles.css
lib/editor/tinymce/lang/en/editor_tinymce.php
lib/editor/tinymce/tests/behat/edit_available_icons.feature
lib/form/submitlink.php
lib/form/yui/checkboxcontroller/checkboxcontroller.js
lib/gdlib.php
lib/installlib.php
lib/ldaplib.php
lib/moodlelib.php
lib/myprofilelib.php [new file with mode: 0644]
lib/navigationlib.php
lib/outputcomponents.php
lib/outputrenderers.php
lib/pagelib.php
lib/templates/notification_message.mustache [moved from lib/templates/output/notification_message.mustache with 85% similarity]
lib/templates/notification_problem.mustache [moved from lib/templates/output/notification_problem.mustache with 85% similarity]
lib/templates/notification_redirect.mustache [moved from lib/templates/output/notification_redirect.mustache with 85% similarity]
lib/templates/notification_success.mustache [moved from lib/templates/output/notification_success.mustache with 85% similarity]
lib/templates/pix_icon.mustache
lib/tests/accesslib_test.php
lib/tests/behat/behat_general.php
lib/tests/behat/behat_navigation.php
lib/tests/datalib_test.php
lib/tests/fixtures/google_gmail.ics
lib/tests/fixtures/upload_users.csv
lib/tests/ldaplib_test.php
lib/tests/message_test.php
lib/tests/moodlelib_test.php
lib/tests/user_menu_test.php
lib/tests/user_test.php
lib/upgrade.txt
lib/upgradelib.php
lib/yui/build/moodle-core-blocks/moodle-core-blocks-debug.js
lib/yui/build/moodle-core-blocks/moodle-core-blocks.js
lib/yui/src/blocks/js/blocks.js
lib/yui/src/blocks/js/manager.js
login/change_password.php
message/edit.php
message/index.php
message/lib.php
message/output/airnotifier/tests/externallib_test.php
message/output/email/lang/en/message_email.php
message/output/email/message_output_email.php
message/renderer.php
message/tests/behat/behat_message.php
message/tests/behat/block_users.feature
message/tests/behat/display_history.feature
message/tests/behat/manage_contacts.feature
message/tests/behat/message_participants.feature
message/tests/behat/recent_conversations.feature [new file with mode: 0644]
message/tests/behat/search_history.feature
message/tests/behat/send_message.feature
mod/assign/externallib.php
mod/assign/feedback/editpdf/tests/behat/annotate_pdf.feature
mod/assign/gradingtable.php
mod/assign/locallib.php
mod/assign/tests/behat/allow_another_attempt.feature
mod/assign/tests/behat/comment_inline.feature
mod/assign/tests/behat/display_grade.feature
mod/assign/tests/behat/edit_previous_feedback.feature
mod/assign/tests/behat/file_submission.feature
mod/assign/tests/behat/filter_by_marker.feature
mod/assign/tests/behat/grading_status.feature
mod/assign/tests/behat/grant_extension.feature
mod/assign/tests/behat/group_submission.feature
mod/assign/tests/behat/online_submissions.feature
mod/assign/tests/behat/outcome_grading.feature
mod/assign/tests/behat/prevent_submission_changes.feature
mod/assign/tests/behat/quickgrading.feature
mod/assign/tests/behat/steps_blind_marking.feature [new file with mode: 0644]
mod/assign/tests/behat/submission_comments.feature
mod/assign/tests/behat/submit_without_group.feature
mod/assign/tests/externallib_test.php
mod/assign/upgrade.txt
mod/book/tests/behat/create_chapters.feature
mod/book/tests/behat/log_entries.feature
mod/book/tests/behat/show_hide_chapters.feature
mod/choice/tests/behat/add_choice.feature
mod/choice/tests/behat/allow_preview.feature
mod/choice/tests/behat/block_editing.feature
mod/choice/tests/behat/change_response.feature
mod/choice/tests/behat/include_inactive.feature
mod/choice/tests/behat/limit_responses.feature
mod/choice/tests/behat/multiple_options.feature
mod/choice/tests/behat/my_home.feature
mod/choice/tests/behat/publish_results.feature
mod/choice/tests/behat/publish_results_anonymously.feature
mod/choice/view.php
mod/data/classes/external.php
mod/data/lib.php
mod/data/tests/behat/add_entries.feature
mod/data/tests/behat/required_entries.feature
mod/data/tests/behat/view_entries.feature
mod/data/tests/externallib_test.php
mod/data/tests/fixtures/test_data_content.csv
mod/feedback/styles.css
mod/forum/classes/event/user_report_viewed.php
mod/forum/db/services.php
mod/forum/externallib.php
mod/forum/lang/en/forum.php
mod/forum/lib.php
mod/forum/post.php
mod/forum/tests/behat/add_forum.feature
mod/forum/tests/behat/completion_condition_number_discussions.feature
mod/forum/tests/behat/discussion_display.feature
mod/forum/tests/behat/discussion_navigation.feature
mod/forum/tests/behat/discussion_subscriptions.feature
mod/forum/tests/behat/edit_post_student.feature
mod/forum/tests/behat/edit_post_teacher.feature
mod/forum/tests/behat/forum_subscriptions.feature
mod/forum/tests/behat/forum_subscriptions_default.feature
mod/forum/tests/behat/my_forum_posts.feature
mod/forum/tests/behat/post_to_multiple_groups.feature
mod/forum/tests/behat/separate_group_discussions.feature
mod/forum/tests/behat/separate_group_single_group_discussions.feature
mod/forum/tests/behat/single_forum_discussion.feature
mod/forum/tests/behat/track_read_posts.feature
mod/forum/tests/events_test.php
mod/forum/tests/externallib_test.php
mod/forum/upgrade.txt
mod/forum/user.php
mod/glossary/tests/behat/categories.feature
mod/glossary/tests/behat/entries_always_editable.feature
mod/glossary/tests/behat/entries_require_approval.feature
mod/glossary/tests/behat/prevent_duplicate_entries.feature
mod/glossary/tests/behat/print_friendly_version.feature
mod/glossary/tests/behat/search_entries.feature
mod/lesson/editpage.php
mod/lesson/format.php
mod/lesson/locallib.php
mod/lesson/pagetypes/matching.php
mod/lesson/pagetypes/multichoice.php
mod/lesson/pagetypes/numerical.php
mod/lesson/pagetypes/shortanswer.php
mod/lesson/pagetypes/truefalse.php
mod/lesson/tests/behat/completion_condition_end_reached.feature
mod/lesson/tests/behat/completion_condition_time_spent.feature
mod/lesson/tests/behat/date_availability.feature
mod/lesson/tests/behat/import_fillintheblank_question.feature
mod/lesson/tests/behat/import_images.feature
mod/lesson/tests/behat/lesson_course_reset.feature
mod/lesson/tests/behat/lesson_edit_cluster.feature
mod/lesson/tests/behat/lesson_edit_pages.feature
mod/lesson/tests/behat/lesson_essay_question.feature
mod/lesson/tests/behat/lesson_group_override.feature
mod/lesson/tests/behat/lesson_informations_at_end.feature
mod/lesson/tests/behat/lesson_navigation.feature
mod/lesson/tests/behat/lesson_number_of_student_attempts.feature
mod/lesson/tests/behat/lesson_practice.feature
mod/lesson/tests/behat/lesson_progress_bar.feature
mod/lesson/tests/behat/lesson_review.feature
mod/lesson/tests/behat/lesson_student_dashboard.feature [moved from mod/lesson/tests/behat/lesson_student_my_home.feature with 94% similarity]
mod/lesson/tests/behat/lesson_student_resume.feature
mod/lesson/tests/behat/lesson_user_override.feature
mod/lesson/tests/behat/lesson_with_clusters.feature
mod/lesson/tests/behat/lesson_with_subcluster.feature
mod/lesson/tests/behat/link_to_gradebook.feature
mod/lesson/tests/behat/password_protection.feature
mod/lesson/tests/behat/questions_images.feature
mod/lesson/tests/behat/teacher_grade_essays.feature
mod/lesson/tests/behat/time_limit.feature
mod/quiz/attemptlib.php
mod/quiz/backup/moodle2/restore_quiz_stepslib.php
mod/quiz/classes/output/edit_renderer.php
mod/quiz/classes/structure.php
mod/quiz/edit.php
mod/quiz/module.js
mod/quiz/styles.css
mod/quiz/tests/behat/add_quiz.feature
mod/quiz/tests/behat/attempt_basic.feature
mod/quiz/tests/behat/attempt_redo_questions.feature
mod/quiz/tests/behat/attempt_require_previous.feature
mod/quiz/tests/behat/backup.feature
mod/quiz/tests/behat/completion_condition_attempts_used.feature
mod/quiz/tests/behat/completion_condition_passing_grade.feature
mod/quiz/tests/behat/editing_add.feature
mod/quiz/tests/behat/editing_move_by_click.feature
mod/quiz/tests/behat/editing_remove_question.feature
mod/quiz/tests/behat/editing_repaginate.feature
mod/quiz/tests/behat/editing_require_previous.feature
mod/quiz/tests/behat/editing_section_headings.feature
mod/quiz/tests/behat/editing_set_marks_no_attempts.feature
mod/quiz/tests/behat/editing_set_marks_with_attempts.feature
mod/quiz/tests/behat/quiz_reset.feature
mod/quiz/yui/build/moodle-mod_quiz-util-page/moodle-mod_quiz-util-page-debug.js
mod/quiz/yui/build/moodle-mod_quiz-util-page/moodle-mod_quiz-util-page-min.js
mod/quiz/yui/build/moodle-mod_quiz-util-page/moodle-mod_quiz-util-page.js
mod/quiz/yui/src/util/js/page.js
mod/scorm/lang/en/scorm.php
mod/scorm/tests/behat/add_scorm.feature
mod/survey/tests/behat/survey_types.feature
mod/wiki/tests/behat/collaborative_individual.feature
mod/wiki/tests/behat/edit_tags.feature
mod/wiki/tests/behat/page_history.feature
mod/wiki/tests/behat/preview_page.feature
mod/wiki/tests/behat/wiki_comments.feature
mod/wiki/tests/behat/wiki_formats.feature
mod/wiki/tests/behat/wiki_search.feature
mod/workshop/tests/behat/workshop_assessment.feature
my/index.php
my/lib.php
my/tests/behat/add_blocks.feature
my/tests/behat/reset_page.feature
my/tests/behat/restrict_available_blocks.feature
notes/index.php
notes/lib.php
notes/tests/externallib_test.php
pix/t/preferences.png [new file with mode: 0644]
pix/t/preferences.svg [new file with mode: 0644]
question/format/xml/format.php
question/tests/behat/copy_questions.feature
question/tests/behat/delete_questions.feature
question/tests/behat/edit_questions.feature
question/tests/behat/preview_question.feature
question/tests/behat/question_categories.feature
question/tests/behat/sort_questions.feature
question/type/match/renderer.php
question/type/match/styles.css
question/type/multichoice/question.php
question/type/questionbase.php
question/type/tests/question_definition_test.php [new file with mode: 0644]
question/type/tests/question_first_matching_answer_grading_strategy_test.php [moved from question/type/tests/questionbase_test.php with 67% similarity]
question/type/tests/question_hint_test.php [new file with mode: 0644]
rating/classes/external.php
rating/tests/externallib_test.php
report/log/lib.php
report/log/tests/behat/filter_log.feature
report/log/tests/behat/user_log.feature
report/log/user.php
report/loglive/tests/behat/loglive_report.feature
report/outline/lib.php
report/outline/tests/behat/outline.feature
report/outline/tests/behat/user.feature
report/outline/user.php
report/participation/tests/behat/filter_participation.feature
report/security/lang/en/report_security.php
report/stats/lib.php
report/stats/user.php
report/usersessions/lib.php
report/usersessions/tests/behat/usersessions_report.feature
report/usersessions/user.php
repository/manage_instances.php
repository/recent/tests/behat/add_recent.feature
repository/tests/behat/cancel_add_file.feature
repository/tests/behat/create_folders.feature
repository/tests/behat/create_shortcut.feature
repository/tests/behat/delete_files.feature
repository/tests/behat/overwrite_file.feature
repository/tests/behat/zip_and_unzip.feature
repository/upload/tests/behat/upload_file.feature
tag/index.php
tag/search.php
theme/base/style/grade.css
theme/base/style/message.css
theme/base/style/user.css
theme/base/templates/core/notification_message.mustache [moved from theme/base/templates/core/output/notification_message.mustache with 100% similarity]
theme/base/templates/core/notification_problem.mustache [moved from theme/base/templates/core/output/notification_problem.mustache with 100% similarity]
theme/base/templates/core/notification_redirect.mustache [moved from theme/base/templates/core/output/notification_redirect.mustache with 100% similarity]
theme/base/templates/core/notification_success.mustache [moved from theme/base/templates/core/output/notification_success.mustache with 100% similarity]
theme/bootstrapbase/layout/columns1.php
theme/bootstrapbase/layout/columns2.php
theme/bootstrapbase/layout/columns3.php
theme/bootstrapbase/layout/popup.php
theme/bootstrapbase/less/moodle/core.less
theme/bootstrapbase/less/moodle/grade.less
theme/bootstrapbase/less/moodle/message.less
theme/bootstrapbase/less/moodle/user.less
theme/bootstrapbase/renderers/core_renderer.php
theme/bootstrapbase/style/moodle.css
theme/clean/layout/columns1.php
theme/clean/layout/columns2.php
theme/clean/layout/columns3.php
user/classes/output/myprofile/category.php [new file with mode: 0644]
user/classes/output/myprofile/manager.php [new file with mode: 0644]
user/classes/output/myprofile/node.php [new file with mode: 0644]
user/classes/output/myprofile/renderer.php [new file with mode: 0644]
user/classes/output/myprofile/tree.php [new file with mode: 0644]
user/edit.php
user/edit_form.php
user/editadvanced.php
user/editadvanced_form.php
user/editlib.php
user/editor.php [new file with mode: 0644]
user/editor_form.php [new file with mode: 0644]
user/files.php
user/forum.php [new file with mode: 0644]
user/forum_form.php [new file with mode: 0644]
user/index.php
user/language.php [new file with mode: 0644]
user/language_form.php [new file with mode: 0644]
user/lib.php
user/portfolio.php
user/portfoliologs.php
user/preferences.php [new file with mode: 0644]
user/profile.php
user/tests/behat/add_blocks.feature
user/tests/behat/delete_users.feature
user/tests/behat/edituserpassword.feature
user/tests/behat/filter_idnumber.feature
user/tests/behat/reset_page.feature
user/tests/behat/set_default_homepage.feature [new file with mode: 0644]
user/tests/behat/table_sorting.feature
user/tests/behat/user_grade_navigation.feature [new file with mode: 0644]
user/tests/behat/view_full_profile.feature
user/tests/externallib_test.php
user/tests/fixtures/myprofile_fixtures.php [new file with mode: 0644]
user/tests/myprofile_test.php [new file with mode: 0644]
user/tests/userlib_test.php
user/view.php
version.php
webservice/upgrade.txt
webservice/upload.php

index 6b8e88f..acd6060 100644 (file)
@@ -69,6 +69,7 @@ Options:
 --prefix=STRING       Table prefix for above database tables. Default is mdl_
 --fullname=STRING     The fullname of the site
 --shortname=STRING    The shortname of the site
+--summary=STRING      The summary to be displayed on the front page
 --adminuser=USERNAME  Username for the moodle admin account. Default is admin
 --adminpass=PASSWORD  Password for the moodle admin account,
                       required in non-interactive mode.
@@ -252,6 +253,7 @@ list($options, $unrecognized) = cli_get_params(
         'prefix'            => 'mdl_',
         'fullname'          => '',
         'shortname'         => '',
+        'summary'           => '',
         'adminuser'         => 'admin',
         'adminpass'         => '',
         'adminemail'        => '',
index 95af47d..df69376 100644 (file)
@@ -90,7 +90,7 @@ if (!empty($options['info'])) {
     $problem = false;
     foreach ($DB->get_tables(false) as $table) {
         $columns = $DB->get_columns($table, false);
-        $size = $generator->guess_antolope_row_size($columns);
+        $size = $generator->guess_antelope_row_size($columns);
         $format = $DB->get_row_format($table);
         if ($size <= $generator::ANTELOPE_MAX_ROW_SIZE) {
             continue;
@@ -120,7 +120,7 @@ if (!empty($options['info'])) {
     $fixtables = array();
     foreach ($DB->get_tables(false) as $table) {
         $columns = $DB->get_columns($table, false);
-        $size = $generator->guess_antolope_row_size($columns);
+        $size = $generator->guess_antelope_row_size($columns);
         $format = $DB->get_row_format($table);
         if ($size <= $generator::ANTELOPE_MAX_ROW_SIZE) {
             continue;
@@ -169,7 +169,7 @@ if (!empty($options['info'])) {
 
     foreach ($DB->get_tables(false) as $table) {
         $columns = $DB->get_columns($table, false);
-        $size = $generator->guess_antolope_row_size($columns);
+        $size = $generator->guess_antelope_row_size($columns);
         $format = $DB->get_row_format($table);
         if ($size <= $generator::ANTELOPE_MAX_ROW_SIZE) {
             continue;
index ede697b..e596403 100644 (file)
           <ON_CHECK message="slashargumentswarning" />
         </FEEDBACK>
       </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="unsupporteddbtablerowformat" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
     </CUSTOM_CHECKS>
   </MOODLE>
 </COMPATIBILITY_MATRIX>
index b263903..bad3ed9 100644 (file)
@@ -556,31 +556,36 @@ $cronoverdue = ($lastcron < time() - 3600 * 24);
 $dbproblems = $DB->diagnose();
 $maintenancemode = !empty($CFG->maintenance_enabled);
 
-// Available updates for Moodle core
+// Available updates for Moodle core.
 $updateschecker = \core\update\checker::instance();
 $availableupdates = array();
-$availableupdates['core'] = $updateschecker->get_update_info('core',
-    array('minmaturity' => $CFG->updateminmaturity, 'notifybuilds' => $CFG->updatenotifybuilds));
-
-// Available updates for contributed plugins
-$pluginman = core_plugin_manager::instance();
-foreach ($pluginman->get_plugins() as $plugintype => $plugintypeinstances) {
-    foreach ($plugintypeinstances as $pluginname => $plugininfo) {
-        if (!empty($plugininfo->availableupdates)) {
-            foreach ($plugininfo->availableupdates as $pluginavailableupdate) {
-                if ($pluginavailableupdate->version > $plugininfo->versiondisk) {
-                    if (!isset($availableupdates[$plugintype.'_'.$pluginname])) {
-                        $availableupdates[$plugintype.'_'.$pluginname] = array();
+$availableupdatesfetch = null;
+
+if (empty($CFG->disableupdatenotifications)) {
+    // Only compute the update information when it is going to be displayed to the user.
+    $availableupdates['core'] = $updateschecker->get_update_info('core',
+        array('minmaturity' => $CFG->updateminmaturity, 'notifybuilds' => $CFG->updatenotifybuilds));
+
+    // Available updates for contributed plugins
+    $pluginman = core_plugin_manager::instance();
+    foreach ($pluginman->get_plugins() as $plugintype => $plugintypeinstances) {
+        foreach ($plugintypeinstances as $pluginname => $plugininfo) {
+            if (!empty($plugininfo->availableupdates)) {
+                foreach ($plugininfo->availableupdates as $pluginavailableupdate) {
+                    if ($pluginavailableupdate->version > $plugininfo->versiondisk) {
+                        if (!isset($availableupdates[$plugintype.'_'.$pluginname])) {
+                            $availableupdates[$plugintype.'_'.$pluginname] = array();
+                        }
+                        $availableupdates[$plugintype.'_'.$pluginname][] = $pluginavailableupdate;
                     }
-                    $availableupdates[$plugintype.'_'.$pluginname][] = $pluginavailableupdate;
                 }
             }
         }
     }
-}
 
-// The timestamp of the most recent check for available updates
-$availableupdatesfetch = $updateschecker->get_last_timefetched();
+    // The timestamp of the most recent check for available updates
+    $availableupdatesfetch = $updateschecker->get_last_timefetched();
+}
 
 $buggyiconvnomb = (!function_exists('mb_convert_encoding') and @iconv('UTF-8', 'UTF-8//IGNORE', '100'.chr(130).'€') !== '100€');
 //check if the site is registered on Moodle.org
index d1a4e8b..77b2fb2 100644 (file)
@@ -58,7 +58,6 @@ if (!empty($registeredhub) and $registeredhub->token == $token) {
 
     echo $OUTPUT->header();
     echo $OUTPUT->heading(get_string('registrationconfirmed', 'hub'), 3, 'main');
-    $hublink = html_writer::tag('a', $hubname, array('href' => $url));
 
     $registeredhub->token = $newtoken;
     $registeredhub->confirmed = 1;
@@ -66,9 +65,7 @@ if (!empty($registeredhub) and $registeredhub->token == $token) {
     $registrationmanager->update_registeredhub($registeredhub);
 
     // Display notification message.
-    $notificationmessage = $OUTPUT->notification(
-            get_string('registrationconfirmedon', 'hub', $hublink), 'notifysuccess');
-    echo $notificationmessage;
+    echo $OUTPUT->notification(get_string('registrationconfirmedon', 'hub'), 'notifysuccess');
 
     //display continue button
     $registrationpage = new moodle_url('/admin/registration/index.php');
index f3aba40..09d2735 100644 (file)
 class core_register_renderer extends plugin_renderer_base {
 
     /**
-     * Display Moodle.org registration message about benefit to register on Moodle.org
+     * Display message about the benefits of registering on Moodle.org
      *
      * @return string
      */
     public function moodleorg_registration_message() {
-
         $moodleorgstatslink = html_writer::link('http://moodle.net/stats',
                                                get_string('statsmoodleorg', 'admin'),
                                                array('target' => '_blank'));
 
-        $hublink = html_writer::link('https://moodle.net/mod/page/view.php?id=1',
-                                      get_string('moodleorghubname', 'admin'),
-                                      array('target' => '_blank'));
-
-        $moodleorgregmsg = get_string('registermoodleorg', 'admin', $hublink);
+        $moodleorgregmsg = get_string('registermoodleorg', 'admin');
         $items = array(get_string('registermoodleorgli1', 'admin'),
                        get_string('registermoodleorgli2', 'admin', $moodleorgstatslink));
         $moodleorgregmsg .= html_writer::alist($items);
index 26afb90..5d75e70 100644 (file)
@@ -721,6 +721,8 @@ class core_admin_renderer extends plugin_renderer_base {
                 foreach ($updates['core'] as $update) {
                     $updateinfo .= $this->moodle_available_update_info($update);
                 }
+                $updateinfo .= html_writer::tag('p', get_string('updateavailablerecommendation', 'core_admin'),
+                    array('class' => 'updateavailablerecommendation'));
             }
             unset($updates['core']);
             // If something has left in the $updates array now, it is updates for plugins.
index 78b496a..3d723b8 100644 (file)
@@ -135,6 +135,11 @@ if ($roleid) {
     }
 }
 
+if (!empty($user) && ($user->id != $USER->id)) {
+    $PAGE->navigation->extend_for_user($user);
+    $PAGE->navbar->includesettingsbase = true;
+}
+
 $PAGE->set_pagelayout('admin');
 $PAGE->set_title($title);
 
index 938fc90..79c697b 100644 (file)
@@ -52,6 +52,7 @@ if (!has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride',
 $PAGE->set_url($url);
 
 if ($context->contextlevel == CONTEXT_USER and $USER->id != $context->instanceid) {
+    $PAGE->navbar->includesettingsbase = true;
     $PAGE->navigation->extend_for_user($user);
     $PAGE->set_context(context_course::instance($course->id));
 } else {
index 3670a86..841732d 100644 (file)
@@ -59,8 +59,9 @@ require_capability('moodle/role:review', $context);
 $PAGE->set_url($url);
 
 if ($context->contextlevel == CONTEXT_USER and $USER->id != $context->instanceid) {
+    $PAGE->navbar->includesettingsbase = true;
     $PAGE->navigation->extend_for_user($user);
-    $PAGE->set_context(context_course::instance($course->id));
+    $PAGE->set_context(context_user::instance($user->id));
 } else {
     $PAGE->set_context($context);
 }
index 70c564f..ab8911a 100644 (file)
@@ -27,9 +27,9 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) { // sp
         'customusermenuitems',
         new lang_string('customusermenuitems', 'admin'),
         new lang_string('configcustomusermenuitems', 'admin'),
-        'messages,message|/message/index.php|message
-myfiles,moodle|/user/files.php|download
-mybadges,badges|/badges/mybadges.php|award',
+        'mygrades,grades|/grade/report/mygrades.php|grades
+messages,message|/message/index.php|message
+mypreferences,moodle|/user/preferences.php|preferences',
         PARAM_TEXT,
         '50',
         '10'
@@ -140,7 +140,8 @@ mybadges,badges|/badges/mybadges.php|award',
         HOMEPAGE_MY => new lang_string('mymoodle', 'admin'),
         HOMEPAGE_USER => new lang_string('userpreference', 'admin')
     );
-    $temp->add(new admin_setting_configselect('defaulthomepage', new lang_string('defaulthomepage', 'admin'), new lang_string('configdefaulthomepage', 'admin'), HOMEPAGE_SITE, $choices));
+    $temp->add(new admin_setting_configselect('defaulthomepage', new lang_string('defaulthomepage', 'admin'),
+            new lang_string('configdefaulthomepage', 'admin'), HOMEPAGE_MY, $choices));
     $temp->add(new admin_setting_configcheckbox('allowguestmymoodle', new lang_string('allowguestmymoodle', 'admin'), new lang_string('configallowguestmymoodle', 'admin'), 1));
     $temp->add(new admin_setting_configcheckbox('navshowfullcoursenames', new lang_string('navshowfullcoursenames', 'admin'), new lang_string('navshowfullcoursenames_help', 'admin'), 0));
     $temp->add(new admin_setting_configcheckbox('navshowcategories', new lang_string('navshowcategories', 'admin'), new lang_string('confignavshowcategories', 'admin'), 1));
index 15a429e..ff70900 100644 (file)
@@ -75,6 +75,11 @@ if (has_capability('moodle/grade:manage', $systemcontext)
         $temp->add(new admin_setting_special_gradepointmax());
 
         $temp->add(new admin_setting_special_gradepointdefault());
+
+        $temp->add(new admin_setting_my_grades_report());
+
+        $temp->add(new admin_setting_configtext('gradereport_mygradeurl', new lang_string('externalurl', 'grades'),
+                new lang_string('externalurl_desc', 'grades'), ''));
     }
     $ADMIN->add('grades', $temp);
 
index 3666409..1868f33 100644 (file)
@@ -4,26 +4,8 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
 
     // "locations" settingpage
     $temp = new admin_settingpage('locationsettings', new lang_string('locationsettings', 'admin'));
-
-    $current = isset($CFG->timezone) ? $CFG->timezone : null;
-    $options = core_date::get_list_of_timezones($current, false);
-    $default = core_date::get_default_php_timezone();
-    if ($current == 99) {
-        // Do not show 99 unless it is current value, we want to get rid of it over time.
-        $options['99'] = new lang_string('timezonephpdefault', 'core_admin', $default);
-    }
-    if ($default === 'UTC') {
-        // Nobody really wants UTC, so instead default selection to the country that is confused by the UTC the most.
-        $default = 'Europe/London';
-    }
-    $temp->add(new admin_setting_configselect('timezone', new lang_string('timezone', 'admin'),
-        new lang_string('configtimezone', 'admin'), $default, $options));
-
-    $options = core_date::get_list_of_timezones(isset($CFG->forcetimezone) ? $CFG->forcetimezone : null, true);
-    $options[99] = new lang_string('timezonenotforced', 'admin');
-    $temp->add(new admin_setting_configselect('forcetimezone', new lang_string('forcetimezone', 'admin'),
-        new lang_string('helpforcetimezone', 'admin'), 99, $options));
-
+    $temp->add(new admin_setting_servertimezone());
+    $temp->add(new admin_setting_forcetimezone());
     $temp->add(new admin_settings_country_select('country', new lang_string('country', 'admin'), new lang_string('configcountry', 'admin'), 0));
     $temp->add(new admin_setting_configtext('defaultcity', new lang_string('defaultcity', 'admin'), new lang_string('defaultcity_help', 'admin'), ''));
 
index 9bf7585..864b733 100644 (file)
@@ -9,6 +9,7 @@ Feature: Display extended course names
       | fullname | shortname | category |
       | Course fullname | C_shortname | 0 |
     And I log in as "admin"
+    And I am on site homepage
 
   Scenario: Courses list without extended course names (default value)
     Then I should see "Course fullname"
@@ -19,5 +20,5 @@ Feature: Display extended course names
     And I click on "Courses" "link" in the "//div[@id='settingsnav']/descendant::li[contains(concat(' ', normalize-space(@class), ' '), ' type_setting ')][contains(., 'Appearance')]" "xpath_element"
     And I set the field "Display extended course names" to "1"
     When I press "Save changes"
-    And I am on homepage
+    And I am on site homepage
     Then I should see "C_shortname Course fullname"
index 253ec7c..8feb542 100644 (file)
@@ -7,10 +7,10 @@ Feature: An administrator can filter user accounts by role, cohort and other pro
   Background:
     Given the following "users" exist:
       | username | firstname | lastname | email | auth | confirmed |
-      | user1 | User | One | one@asd.com | manual | 0 |
-      | user2 | User | Two | two@asd.com | ldap | 1 |
-      | user3 | User | Three | three@asd.com | manual | 1 |
-      | user4 | User | Four | four@asd.com | ldap | 0 |
+      | user1 | User | One | one@example.com | manual | 0 |
+      | user2 | User | Two | two@example.com | ldap | 1 |
+      | user3 | User | Three | three@example.com | manual | 1 |
+      | user4 | User | Four | four@example.com | ldap | 0 |
     And the following "cohorts" exist:
       | name | idnumber |
       | Cohort 1 | CH1 |
@@ -23,8 +23,8 @@ Feature: An administrator can filter user accounts by role, cohort and other pro
       | user2 | C1 | student |
       | user3 | C1 | student |
     And I log in as "admin"
-    And I add "User Two (two@asd.com)" user to "CH1" cohort members
-    And I add "User Three (three@asd.com)" user to "CH1" cohort members
+    And I add "User Two (two@example.com)" user to "CH1" cohort members
+    And I add "User Three (three@example.com)" user to "CH1" cohort members
     And I follow "Browse list of users"
 
   @javascript
index 66ab175..ffe69cb 100644 (file)
@@ -9,17 +9,18 @@ Feature: Set admin settings value
       | fullname | shortname | category |
       | Course fullname | C_shortname | 0 |
     And I log in as "admin"
+    And I am on site homepage
     And I should see "Course fullname"
     And I should not see "C_shortname Course fullname"
 
   Scenario: set admin value with full name
     Given the following config values are set as admin:
       | courselistshortnames | 1 |
-    And I am on homepage
+    And I am on site homepage
     Then I should see "C_shortname Course fullname"
 
   Scenario: set admin value with short name
     Given the following config values are set as admin:
       | courselistshortnames | 1 |
-    And I am on homepage
-    Then I should see "C_shortname Course fullname"
\ No newline at end of file
+    And I am on site homepage
+    Then I should see "C_shortname Course fullname"
index 7194144..0c4b1da 100644 (file)
@@ -21,7 +21,7 @@ Feature: Upload users
     And I should see "Tom"
     And I should see "Jones"
     And I should see "verysecret"
-    And I should see "jonest@someplace.edu"
+    And I should see "jonest@example.com"
     And I should see "Reznor"
     And I should see "course1"
     And I should see "math102"
@@ -32,8 +32,8 @@ Feature: Upload users
     And I follow "Browse list of users"
     And I should see "Tom Jones"
     And I should see "Trent Reznor"
-    And I should see "reznor@someplace.edu"
-    And I am on homepage
+    And I should see "reznor@example.com"
+    And I am on site homepage
     And I follow "Maths"
     And I expand "Users" node
     And I follow "Groups"
index e968c20..9234fee 100644 (file)
@@ -31,7 +31,7 @@ Feature: Manage availability conditions
     And the following config values are set as admin:
       | enableavailability | 1 |
     And I log in as "admin"
-    And I am on homepage
+    And I am on site homepage
     When I navigate to "Manage restrictions" node in "Site administration > Plugins > Availability restrictions"
 
     # Check the icon is there (it should be a Hide icon, meaning is currently visible).
@@ -47,7 +47,7 @@ Feature: Manage availability conditions
 
     # OK, toggling works. Set the grade one to Hide and we'll go see if it actually worked.
     And I click on "input[title=Hide]" "css_element" in the "Restriction by grade" "table_row"
-    And I am on homepage
+    And I am on site homepage
     And I follow "Course 1"
     And I turn editing mode on
     And I add a "Page" to section "1"
index c24eaea..4517a7e 100644 (file)
@@ -59,6 +59,9 @@ list($options, $unrecognized) = cli_get_params(
 $help = "
 Behat utilities to initialise behat tests
 
+Usage:
+  php init.php [--parallel=value [--maxruns=value] [--fromrun=value --torun=value]] [--help]
+
 Options:
 -j, --parallel Number of parallel behat run to initialise
 -m, --maxruns  Max parallel processes to be executed at one time.
@@ -82,7 +85,7 @@ if (!empty($options['help'])) {
 $utilfile = 'util_single_run.php';
 $paralleloption = "";
 // If parallel run then use utilparallel.
-if ($options['parallel']) {
+if ($options['parallel'] && $options['parallel'] > 1) {
     $utilfile = 'util.php';
     $paralleloption = "";
     foreach ($options as $option => $value) {
index 4240747..06630ea 100644 (file)
@@ -50,24 +50,29 @@ list($options, $unrecognised) = cli_get_params(
         'help'     => false,
         'tags'     => '',
         'profile'  => '',
+        'feature'  => '',
         'fromrun'  => 1,
         'torun'    => 0,
+        'single-run' => false,
     ),
     array(
         'h' => 'help',
         't' => 'tags',
         'p' => 'profile',
+        's' => 'single-run',
     )
 );
 
 // Checking run.php CLI script usage.
 $help = "
 Behat utilities to run behat tests in parallel
+
+Usage:
+  php run.php [--BEHAT_OPTION=\"value\"] [--feature=\"value\"] [--replace] [--fromrun=value --torun=value] [--help]
+
 Options:
--t, --tags         Tags to execute.
--p, --profile      Profile to execute.
---stop-on-failure  Stop on failure in any parallel run.
---verbose          Verbose output
+--BEHAT_OPTION     Any combination of behat option specified in http://behat.readthedocs.org/en/v2.5/guides/6.cli.html
+--feature          Only execute specified feature file (Absolute path of feature file).
 --replace          Replace args string with run process number, useful for output.
 --fromrun          Execute run starting from (Used for parallel runs on different vms)
 --torun            Execute run till (Used for parallel runs on different vms)
@@ -75,7 +80,7 @@ Options:
 -h, --help         Print out this help
 
 Example from Moodle root directory:
-\$ php admin/tool/behat/cli/run.php --parallel=2
+\$ php admin/tool/behat/cli/run.php --tags=\"@javascript\"
 
 More info in http://docs.moodle.org/dev/Acceptance_testing#Running_tests
 ";
@@ -101,25 +106,6 @@ if (extension_loaded('pcntl')) {
     }
 }
 
-// If empty parallelrun then just check with user if it's a run single behat test.
-if (empty($parallelrun)) {
-    if (cli_input("This is not a parallel site, do you want to run single behat run? (Y/N)", 'n', array('y', 'n')) == 'y') {
-        $runtestscommand = behat_command::get_behat_command();
-        $runtestscommand .= ' --config ' . behat_config_manager::get_behat_cli_config_filepath();
-        exec("php $runtestscommand", $output, $code);
-        echo implode(PHP_EOL, $output) . PHP_EOL;
-        exit($code);
-    } else {
-        exit(1);
-    }
-}
-
-// Create site symlink if necessary.
-if (!behat_config_manager::create_parallel_site_links($options['fromrun'], $options['torun'])) {
-    echo "Check permissions. If on windows, make sure you are running this command as admin" . PHP_EOL;
-    exit(1);
-}
-
 $time = microtime(true);
 array_walk($unrecognised, function (&$v) {
     if ($x = preg_filter("#^(-+\w+)=(.+)#", "\$1='\$2'", $v)) {
@@ -151,6 +137,30 @@ if ($options['tags']) {
     $extraopts[] = '--tags="' . $tags . '"';
 }
 
+// Feature should be added to last, for behat command.
+if ($options['feature']) {
+    $extraopts[] = $options['feature'];
+    // Only run 1 process as process.
+    // Feature file is picked from absolute path provided, so no need to check for behat.yml.
+    $options['torun'] = $options['fromrun'];
+}
+
+// Set of options to pass to behat.
+$extraopts = implode(' ', $extraopts);
+
+// If empty parallelrun then just check with user if it's a run single behat test.
+if (empty($parallelrun)) {
+    $cwd = getcwd();
+    chdir(__DIR__);
+    $runtestscommand = behat_command::get_behat_command(false, false, true);
+    $runtestscommand .= ' --config ' . behat_config_manager::get_behat_cli_config_filepath();
+    $runtestscommand .= ' ' . $extraopts;
+    echo "Running single behat site:" . PHP_EOL;
+    passthru("php $runtestscommand", $code);
+    chdir($cwd);
+    exit($code);
+}
+
 // Update config file if tags defined.
 if ($tags) {
     // Hack to set proper dataroot and wwwroot.
@@ -158,12 +168,17 @@ if ($tags) {
     $behatwwwroot  = $CFG->behat_wwwroot;
     for ($i = 1; $i <= $parallelrun; $i++) {
         $CFG->behatrunprocess = $i;
-        $CFG->behat_dataroot = $behatdataroot . $i;
-        if (!empty($CFG->behat_parallel_run['behat_wwwroot'][$i - 1]['behat_wwwroot'])) {
-            $CFG->behat_wwwroot = $CFG->behat_parallel_run['behat_wwwroot'][$i - 1]['behat_wwwroot'];
+
+        if (!empty($CFG->behat_parallel_run[$i - 1]['behat_wwwroot'])) {
+            $CFG->behat_wwwroot = $CFG->behat_parallel_run[$i - 1]['behat_wwwroot'];
         } else {
             $CFG->behat_wwwroot = $behatwwwroot . "/" . BEHAT_PARALLEL_SITE_NAME . $i;
         }
+        if (!empty($CFG->behat_parallel_run[$i - 1]['behat_dataroot'])) {
+            $CFG->behat_dataroot = $CFG->behat_parallel_run[$i - 1]['behat_dataroot'];
+        } else {
+            $CFG->behat_dataroot = $behatdataroot . $i;
+        }
         behat_config_manager::update_config_file('', true, $tags);
     }
     $CFG->behat_dataroot = $behatdataroot;
@@ -172,7 +187,6 @@ if ($tags) {
 }
 
 $cmds = array();
-$extraopts = implode(' ', $extraopts);
 echo "Running " . ($options['torun'] - $options['fromrun'] + 1) . " parallel behat sites:" . PHP_EOL;
 
 for ($i = $options['fromrun']; $i <= $options['torun']; $i++) {
@@ -181,7 +195,7 @@ for ($i = $options['fromrun']; $i <= $options['torun']; $i++) {
     // Options parameters to be added to each run.
     $myopts = !empty($options['replace']) ? str_replace($options['replace'], $i, $extraopts) : $extraopts;
 
-    $behatcommand = behat_command::get_behat_command();
+    $behatcommand = behat_command::get_behat_command(false, false, true);
     $behatconfigpath = behat_config_manager::get_behat_cli_config_filepath($i);
 
     // Command to execute behat run.
@@ -194,8 +208,14 @@ if (empty($cmds)) {
     exit(1);
 }
 
+// Create site symlink if necessary.
+if (!behat_config_manager::create_parallel_site_links($options['fromrun'], $options['torun'])) {
+    echo "Check permissions. If on windows, make sure you are running this command as admin" . PHP_EOL;
+    exit(1);
+}
+
 // Execute all commands.
-$processes = cli_execute_parallel($cmds);
+$processes = cli_execute_parallel($cmds, __DIR__);
 $stoponfail = empty($options['stop-on-failure']) ? false : true;
 
 // Print header.
@@ -213,21 +233,31 @@ foreach ($exitcodes as $exitcode) {
     $status = (bool)$status || (bool)$exitcode;
 }
 
+// Run finished. Show exit code and output from individual process.
+$verbose = empty($options['verbose']) ? false : true;
+$verbose = $verbose || $status;
+
 // Show exit code from each process, if any process failed.
-if ($status) {
-    echo "Exit codes: " . implode(" ", $exitcodes) . PHP_EOL;
-    echo "To re-run failed processes, you can use following commands:" . PHP_EOL;
-    foreach ($cmds as $name => $cmd) {
-        if (!empty($exitcodes[$name])) {
-            echo "[" . $name . "] " . $cmd . PHP_EOL;
+if ($verbose) {
+    // Echo exit codes.
+    echo "Exit codes for each behat run: " . PHP_EOL;
+    ksort($exitcodes);
+    foreach ($exitcodes as $run => $exitcode) {
+        echo $run . ": " . $exitcode . PHP_EOL;
+    }
+
+    // Show failed re-run commands.
+    if ($status) {
+        echo "To re-run failed processes, you can use following commands:" . PHP_EOL;
+        foreach ($cmds as $name => $cmd) {
+            if (!empty($exitcodes[$name])) {
+                echo "[" . $name . "] " . $cmd . PHP_EOL;
+            }
         }
     }
     echo PHP_EOL;
 }
 
-// Run finished. Show exit code and output from individual process.
-$verbose = empty($options['verbose']) ? false : true;
-$verbose = $verbose || $status;
 print_each_process_info($processes, $verbose);
 
 // Remove site symlink if necessary.
index 1bdb72d..23a47fd 100644 (file)
@@ -68,15 +68,18 @@ list($options, $unrecognized) = cli_get_params(
 $help = "
 Behat utilities to manage the test environment
 
+Usage:
+  php util.php [--install|--drop|--enable|--disable|--diag|--updatesteps|--help] [--parallel=value [--maxruns=value]]
+
 Options:
 --install      Installs the test environment for acceptance tests
 --drop         Drops the database tables and the dataroot contents
 --enable       Enables test environment and updates tests list
 --disable      Disables test environment
 --diag         Get behat test environment status code
+--updatesteps  Update feature step file.
 -j, --parallel Number of parallel behat run operation
 -m, --maxruns  Max parallel processes to be executed at one time.
---updatesteps  Update feature step file.
 
 -h, --help     Print out this help
 
@@ -205,8 +208,12 @@ if ($options['install']) {
 } else if ($options['disable']) {
     echo "Acceptance tests environment disabled for " . $options['parallel'] . " parallel sites" . PHP_EOL;
 
+} else if ($options['diag']) {
+    // Valid option, so nothing to do.
 } else {
     echo $help;
+    chdir($cwd);
+    exit(1);
 }
 
 chdir($cwd);
index fa90359..b089539 100644 (file)
@@ -61,6 +61,9 @@ if ($options['install'] or $options['drop']) {
 $help = "
 Behat utilities to manage the test environment
 
+Usage:
+  php util_single_run.php [--install|--drop|--enable|--disable|--diag|--updatesteps|--help]
+
 Options:
 --install     Installs the test environment for acceptance tests
 --drop        Drops the database tables and the dataroot contents
index 6460eb2..86bfdaa 100644 (file)
@@ -7,7 +7,7 @@ Feature: Page contents assertions
   @javascript
   Scenario: Basic contents assertions
     Given I log in as "admin"
-    And I am on homepage
+    And I am on site homepage
     And I expand "Users" node
     And I follow "Groups"
     And I press "Create group"
@@ -22,8 +22,8 @@ Feature: Page contents assertions
     Then I should see "I'm the description"
     And "Grouping" "select" in the "region-main" "region" should be visible
     And "Group" "select" should be visible
-    And "Messaging" "link" in the "Administration" "block" should not be visible
-    And "Change password" "link" should not be visible
+    And "Activity report" "link" in the "Administration" "block" should not be visible
+    And "Event monitoring rules" "link" should not be visible
     And I should see "Filter groups by"
     And I should not see "Filter groupssss by"
     And I should see "Group members" in the "#region-main table th.c1" "css_element"
@@ -38,6 +38,7 @@ Feature: Page contents assertions
       | fullname | shortname | category |
       | Course 1 | C1 | 0 |
     And I log in as "admin"
+    And I am on site homepage
     And I follow "Course 1"
     When I dock "Administration" block
     Then I should not see "Question bank" in the ".block-region" "css_element"
index 7b05caf..905e23b 100644 (file)
@@ -27,6 +27,7 @@ Feature: Set up contextual data for tests
       | Course 2 | COURSE2 | CAT3 |
       | Course 3 | COURSE3 | 0 |
     When I log in as "admin"
+    And I am on site homepage
     Then I should see "Course 1"
     And I should see "Course 2"
     And I should see "Course 3"
@@ -56,6 +57,7 @@ Feature: Set up contextual data for tests
       | Grouping 1 | C1 | GG1 |
       | Grouping 2 | C1 | GG2 |
     When I log in as "admin"
+    And I am on site homepage
     And I follow "Course 1"
     And I expand "Users" node
     And I follow "Groups"
@@ -69,8 +71,8 @@ Feature: Set up contextual data for tests
   Scenario: Role overrides
     Given the following "users" exist:
       | username | firstname | lastname | email |
-      | teacher1 | Teacher | 1 | teacher1@asd.com |
-      | student1 | Student | 1 | student1@asd.com |
+      | teacher1 | Teacher | 1 | teacher1@example.com |
+      | student1 | Student | 1 | student1@example.com |
     And the following "categories" exist:
       | name | category | idnumber |
       | Cat 1 | 0 | CAT1 |
@@ -86,6 +88,7 @@ Feature: Set up contextual data for tests
       | mod/forum:editanypost | Allow | student | Course | C1 |
       | mod/forum:replynews | Prevent | editingteacher | Course | C1 |
     When I log in as "admin"
+    And I am on site homepage
     And I follow "Course 1"
     And I expand "Users" node
     And I follow "Permissions"
@@ -99,7 +102,7 @@ Feature: Set up contextual data for tests
   Scenario: Add course enrolments
     Given the following "users" exist:
       | username | firstname | lastname | email |
-      | student1 | Student | 1 | student1@asd.com |
+      | student1 | Student | 1 | student1@example.com |
     And the following "courses" exist:
       | fullname | shortname | format |
       | Course 1 | C1 | topics |
@@ -117,11 +120,11 @@ Feature: Set up contextual data for tests
       | Custom student         | custom2   |                  |                |
     And the following "users" exist:
       | username | firstname | lastname | email |
-      | user1 | User | 1 | user1@moodlemoodle.com |
-      | user2 | User | 2 | user2@moodlemoodle.com |
-      | user3 | User | 3 | user3@moodlemoodle.com |
-      | user4 | User | 4 | user4@moodlemoodle.com |
-      | user5 | User | 5 | user5@moodlemoodle.com |
+      | user1 | User | 1 | user1@example.com |
+      | user2 | User | 2 | user2@example.com |
+      | user3 | User | 3 | user3@example.com |
+      | user4 | User | 4 | user4@example.com |
+      | user5 | User | 5 | user5@example.com |
     And the following "categories" exist:
       | name | category | idnumber |
       | Cat 1 | 0 | CAT1 |
@@ -138,22 +141,27 @@ Feature: Set up contextual data for tests
       | user3 | editingteacher | Course       | C1        |
       | user5 | custom2        | System       |           |
     When I log in as "user1"
+    And I am on site homepage
     Then I should see "Front page settings"
     And I log out
     And I log in as "user2"
+    And I am on site homepage
     And I follow "Course 1"
     And I should see "Turn editing on"
     And I log out
     And I log in as "user3"
+    And I am on site homepage
     And I follow "Course 1"
     And I should see "Turn editing on"
     And I log out
     And I log in as "user4"
+    And I am on site homepage
     And I follow "Course 1"
     And I should see "Turn editing on"
     And I log out
     And I log in as "user5"
     And I should see "You are logged in as"
+    And I am on site homepage
     And I follow "Course 1"
     And I should see "You can not enrol yourself in this course."
 
@@ -192,6 +200,7 @@ Feature: Set up contextual data for tests
       | activity   | name                            | intro                         | course | idnumber    | grade |
       | assign     | Test assignment name with scale | Test assignment description   | C1     | assign1     | Test Scale 1 |
     When I log in as "admin"
+    And I am on site homepage
     And I follow "Course 1"
     Then I should see "Test assignment name"
     # Assignment 2.2 module type is disabled by default
@@ -229,8 +238,8 @@ Feature: Set up contextual data for tests
   Scenario: Add relations between users and groups
     Given the following "users" exist:
       | username | firstname | lastname | email |
-      | student1 | Student | 1 | student1@asd.com |
-      | student2 | Student | 2 | student2@asd.com |
+      | student1 | Student | 1 | student1@example.com |
+      | student2 | Student | 2 | student2@example.com |
     And the following "courses" exist:
       | fullname | shortname |
       | Course 1 | C1 |
@@ -253,6 +262,7 @@ Feature: Set up contextual data for tests
       | grouping | group |
       | GG1 | G1 |
     When I log in as "admin"
+    And I am on site homepage
     And I follow "Course 1"
     And I expand "Users" node
     And I follow "Groups"
@@ -269,8 +279,8 @@ Feature: Set up contextual data for tests
       | Cat 1 | 0        | CAT1     |
     And the following "users" exist:
       | username | firstname | lastname | email |
-      | student1 | Student | 1 | student1@asd.com |
-      | student2 | Student | 2 | student2@asd.com |
+      | student1 | Student | 1 | student1@example.com |
+      | student2 | Student | 2 | student2@example.com |
     And the following "cohorts" exist:
       | name            | idnumber |
       | System cohort A | CHSA     |
@@ -312,6 +322,7 @@ Feature: Set up contextual data for tests
       | fullname | course | gradecategory |
       | Grade sub category 2 | C1 | Grade category 1 |
     When I log in as "admin"
+    And I am on site homepage
     And I follow "Courses"
     And I follow "Course 1"
     And I navigate to "Grades" node in "Course administration"
@@ -336,6 +347,7 @@ Feature: Set up contextual data for tests
       | Test Grade Item 2 | C1 | Grade category 1 |
       | Test Grade Item 3 | C1 | Grade sub category 2 |
     When I log in as "admin"
+    And I am on site homepage
     And I follow "Course 1"
     And I follow "Grades"
     And I expand "Setup" node
@@ -366,6 +378,7 @@ Feature: Set up contextual data for tests
       | name | scale |
       | Test Scale 1 | Disappointing, Good, Very good, Excellent |
     When I log in as "admin"
+    And I am on site homepage
     And I follow "Course 1"
     And I follow "Grades"
     And I follow "Scales"
@@ -388,7 +401,7 @@ Feature: Set up contextual data for tests
     And the following config values are set as admin:
       | enableoutcomes | 1 |
     When I log in as "admin"
-    And I follow "Home"
+    And I am on site homepage
     And I follow "Course 1"
     And I follow "Outcomes"
     Then I should see "Grade outcome 1" in the "#addoutcomes" "css_element"
@@ -417,7 +430,7 @@ Feature: Set up contextual data for tests
     And the following config values are set as admin:
       | enableoutcomes | 1 |
     When I log in as "admin"
-    And I follow "Home"
+    And I am on site homepage
     And I follow "Course 1"
     And I follow "Grades"
     And I expand "Setup" node
index d16e543..26d4f42 100644 (file)
@@ -7,7 +7,7 @@ Feature: Edit capabilities
   Background:
     Given the following "users" exist:
       | username | firstname | lastname | email |
-      | teacher1 | Teacher | 1 | teacher1@asd.com |
+      | teacher1 | Teacher | 1 | teacher1@example.com |
     And the following "courses" exist:
       | fullname | shortname | category |
       | Course 1 | C1 | 0 |
index 5e281be..40c1cbe 100644 (file)
@@ -10,9 +10,9 @@ Feature: Verify that all form fields values can be get and set
       | Course 1 | C1 | 0 |
     And the following "users" exist:
       | username | email | firstname | lastname |
-      | student1 | s1@asd.com | Student | 1 |
-      | student2 | s2@asd.com | Student | 2 |
-      | student3 | s3@asd.com | Student | 3 |
+      | student1 | s1@example.com | Student | 1 |
+      | student2 | s2@example.com | Student | 2 |
+      | student3 | s3@example.com | Student | 3 |
     And the following "course enrolments" exist:
       | user | course | role |
       | student1 | C1 | student |
@@ -39,7 +39,7 @@ Feature: Verify that all form fields values can be get and set
     # Select (multi-select) - We will check "I set the field...".
     And I set the field "otagsadd" to "OT1, OT2, OT3, OT4, OT5"
     And I press "Add official tags"
-    And I am on homepage
+    And I am on site homepage
     And I follow "Course 1"
     And I turn editing mode on
     And I follow "Test this one"
index 952b65a..9aa451f 100644 (file)
@@ -7,13 +7,14 @@ Feature: Forms manipulation
   @javascript
   Scenario: Basic forms manipulation
     Given I log in as "admin"
-    And I navigate to "Edit profile" node in "My profile settings"
+    And I follow "My preferences" in the user menu
+    And I follow "Edit profile"
     When I set the field "First name" to "Field value"
-    And I set the field "Text editor" to "Plain text area"
+    And I set the field "Select a country" to "Japan"
     And I set the field "Unmask" to "1"
     And I expand all fieldsets
     Then the field "First name" matches value "Field value"
-    And the "Text editor" select box should contain "Plain text area"
+    And the "Select a country" select box should contain "Japan"
     And the field "Unmask" matches value "1"
     And I set the field "Unmask" to ""
     And the field "Unmask" matches value ""
@@ -25,6 +26,7 @@ Feature: Forms manipulation
       | fullname | shortname | category |
       | Course 1 | C1 | 0 |
     And I log in as "admin"
+    And I am on site homepage
     And I follow "Course 1"
     And I turn editing mode on
     And I add a "Quiz" to section "1"
index 5466d42..f6cdb33 100644 (file)
@@ -5,13 +5,15 @@ Feature: Transform steps arguments
   I need to apply some transformations to the steps arguments
 
   Background:
-    Given I am on homepage
+    Given I am on site homepage
     And the following "courses" exist:
       | fullname | shortname | category |
       | Course 1 | C1 | 0 |
     And I log in as "admin"
-    And I navigate to "Edit profile" node in "My profile settings"
+    And I follow "My preferences" in the user menu
+    And I follow "Edit profile"
 
+  @javascript
   Scenario: Use nasty strings on steps arguments
     When I set the field "Surname" to "$NASTYSTRING1"
     And I set the field "Description" to "$NASTYSTRING2"
@@ -22,6 +24,7 @@ Feature: Transform steps arguments
     And the field "Surname" matches value "$NASTYSTRING1"
     And the field "City/town" matches value "$NASTYSTRING3"
 
+  @javascript
   Scenario: Use nasty strings on table nodes
     When I set the following fields to these values:
       | Surname | $NASTYSTRING1 |
@@ -33,6 +36,7 @@ Feature: Transform steps arguments
     And the field "Surname" matches value "$NASTYSTRING1"
     And the field "City/town" matches value "$NASTYSTRING3"
 
+  @javascript
   Scenario: Use double quotes
     When I set the following fields to these values:
       | First name | va"lue1 |
index 1fa202b..c338f43 100644 (file)
@@ -5,5 +5,5 @@ Feature: Set up the testing environment
   I need to use the test environment instead of the regular environment
 
   Scenario: Accessing the site
-    When I am on homepage
+    When I am on site homepage
     Then I should see "Acceptance test site"
index ca52f01..3710f0c 100644 (file)
@@ -121,7 +121,7 @@ Feature: Add customised file types
       | Custom description | Froggy file                               |
     And I press "Save changes"
     # Create a resource activity and add it to a course
-    And I am on homepage
+    And I am on site homepage
     And I follow "Course 1"
     And I turn editing mode on
     When I add a "File" to section "1"
index 30d6b66..551ca1f 100644 (file)
@@ -56,7 +56,7 @@ class renderer extends \plugin_renderer_base {
      * @return string to display on the mangesubs page.
      */
     protected function render_rules(rules $renderable) {
-        $o = $this->render_course_select($renderable);
+        $o = '';
         if (!empty($renderable->totalcount)) {
             $o .= $this->render_table($renderable);
         }
index b298abf..c0c031a 100644 (file)
@@ -215,13 +215,17 @@ class rules extends \table_sql implements \renderable {
             return false;
         }
         $orderby = 'visible DESC, sortorder ASC';
-        $options = array(0 => get_string('site'));
+        $options = array();
         if ($courses = get_user_capability_course('tool/monitor:subscribe', null, true, 'fullname', $orderby)) {
             foreach ($courses as $course) {
                 $options[$course->id] = format_string($course->fullname, true,
                     array('context' => \context_course::instance($course->id)));
             }
         }
+        // If there are no options to display, then don't display anything.
+        if (count($options) === 0) {
+            return false;
+        }
         $url = new \moodle_url('/admin/tool/monitor/index.php');
         $select = new \single_select($url, 'courseid', $options, $this->courseid);
         $select->set_label(get_string('selectacourse', 'tool_monitor'));
index 3e06a33..5dcc916 100644 (file)
 require_once(__DIR__ . '/../../../config.php');
 require_once($CFG->libdir.'/adminlib.php');
 
-$courseid = optional_param('courseid', 0, PARAM_INT);
+$courseid = optional_param('courseid', SITEID, PARAM_INT);
 $action = optional_param('action', '', PARAM_ALPHA);
 $cmid = optional_param('cmid', 0, PARAM_INT);
 $ruleid = optional_param('ruleid', 0, PARAM_INT);
 $subscriptionid = optional_param('subscriptionid', 0, PARAM_INT);
 $confirm = optional_param('confirm', false, PARAM_BOOL);
 
-// Validate course id.
+require_login();
+
+// We need to explicitly check that the course id is something legitimate.
 if (empty($courseid)) {
-    require_login();
-} else {
-    // They might want to see rules for this course.
-    $course = get_course($courseid);
-    require_login($course);
-    $coursecontext = context_course::instance($course->id);
-    // Check for caps.
-    require_capability('tool/monitor:subscribe', $coursecontext);
-    $coursename = format_string($course->fullname, true, array('context' => $coursecontext));
+    $courseid = SITEID;
 }
 
+$coursecontext = context_course::instance($courseid);
+
 if (!get_config('tool_monitor', 'enablemonitor')) {
     // This should never happen as the this page does not appear in navigation when the tool is disabled.
     throw new coding_exception('Event monitoring is disabled');
 }
 
-// Always build the page in site context.
-$context = context_system::instance();
-$sitename = format_string($SITE->fullname, true, array('context' => $context));
-$PAGE->set_context($context);
+$PAGE->set_context(context_user::instance($USER->id));
 
 // Set up the page.
 $indexurl = new moodle_url('/admin/tool/monitor/index.php', array('courseid' => $courseid));
 $PAGE->set_url($indexurl);
 $PAGE->set_pagelayout('report');
-$PAGE->set_title($sitename);
-$PAGE->set_heading($sitename);
+$PAGE->set_title(get_string('managesubscriptions', 'tool_monitor'));
+$PAGE->set_heading(fullname($USER));
+$settingsnode = $PAGE->settingsnav->find('monitor', null)->make_active();
 
 // Create/delete subscription if needed.
 if (!empty($action)) {
@@ -91,7 +85,7 @@ if (!empty($action)) {
             } else {
                 $subscription = \tool_monitor\subscription_manager::get_subscription($subscriptionid);
                 echo $OUTPUT->header();
-                echo $OUTPUT->confirm(get_string('subareyousure', 'tool_monitor', $subscription->get_name($context)),
+                echo $OUTPUT->confirm(get_string('subareyousure', 'tool_monitor', $subscription->get_name($coursecontext)),
                     $confirmurl, $cancelurl);
                 echo $OUTPUT->footer();
                 exit();
@@ -103,9 +97,22 @@ if (!empty($action)) {
     echo $OUTPUT->header();
 }
 
+$renderer = $PAGE->get_renderer('tool_monitor', 'managesubs');
+
+// Render the course selector.
+$totalrules = \tool_monitor\rule_manager::count_rules_by_courseid($courseid);
+$rules = new \tool_monitor\output\managesubs\rules('toolmonitorrules', $indexurl, $courseid);
+
+$usercourses = $rules->get_user_courses_select();
+if (!empty($usercourses)) {
+    echo $renderer->render($usercourses);
+} else {
+    // Nothing to show at all. Show a notification.
+    echo $OUTPUT->notification(get_string('rulenopermission', 'tool_monitor'), 'notifyproblem');
+}
+
 // Render the current subscriptions list.
 $totalsubs = \tool_monitor\subscription_manager::count_user_subscriptions();
-$renderer = $PAGE->get_renderer('tool_monitor', 'managesubs');
 if (!empty($totalsubs)) {
     // Show the subscriptions section only if there are subscriptions.
     $subs = new \tool_monitor\output\managesubs\subs('toolmonitorsubs', $indexurl, $courseid);
@@ -114,17 +121,15 @@ if (!empty($totalsubs)) {
 }
 
 // Render the potential rules list.
-$totalrules = \tool_monitor\rule_manager::count_rules_by_courseid($courseid);
-echo $OUTPUT->heading(get_string('rulescansubscribe', 'tool_monitor'), 3);
-$rules = new \tool_monitor\output\managesubs\rules('toolmonitorrules', $indexurl, $courseid);
-echo $renderer->render($rules);
+// Check the capability here before displaying any rules to subscribe to.
+if (has_capability('tool/monitor:subscribe', $coursecontext)) {
+    echo $OUTPUT->heading(get_string('rulescansubscribe', 'tool_monitor'), 3);
+    echo $renderer->render($rules);
+}
 
 // Check if the user can manage the course rules we are viewing.
-if (empty($courseid)) {
-    $canmanagerules = has_capability('tool/monitor:managerules', $context);
-} else {
-    $canmanagerules = has_capability('tool/monitor:managerules', $coursecontext);
-}
+$canmanagerules = has_capability('tool/monitor:managerules', $coursecontext);
+
 if (empty($totalrules)) {
     // No rules present. Show a link to manage rules page if permissions permit.
     echo html_writer::start_div();
index 77cd215..c0fbf7f 100644 (file)
@@ -87,6 +87,7 @@ $string['rulecopysuccess'] = 'Rule successfully duplicated';
 $string['ruledeletesuccess'] = 'Rule successfully deleted';
 $string['rulehelp'] = 'Rule details';
 $string['rulehelp_help'] = 'This rule listens for when the event \'{$a->eventname}\' in \'{$a->eventcomponent}\' has been triggered {$a->frequency} time(s) in {$a->minutes} minute(s).';
+$string['rulenopermission'] = 'You do not have permission to subscribe to any events.';
 $string['rulenopermissions'] = 'You do not have permissions to "{$a} a rule"';
 $string['rulescansubscribe'] = 'Rules you can subscribe to';
 $string['selectacourse'] = 'Select a course';
index 4b4ec31..4091ef2 100644 (file)
@@ -76,8 +76,9 @@ function tool_monitor_extend_navigation_frontpage($navigation, $course, $context
  */
 function tool_monitor_extend_navigation_user_settings($navigation, $user, $usercontext, $course, $coursecontext) {
     global $USER, $SITE;
-    if (($USER->id == $user->id) && (has_capability('tool/monitor:subscribe', $coursecontext)
-            && get_config('tool_monitor', 'enablemonitor'))) {
+
+    // Don't show the setting if the event monitor isn't turned on. No access to other peoples subscriptions.
+    if (get_config('tool_monitor', 'enablemonitor') && $USER->id == $user->id) {
         // The $course->id will always be the course that corresponds to the current context.
         $courseid = $course->id;
         // A $course->id of $SITE->id might either be the frontpage or the site. So if we get the site ID back, check the...
@@ -87,7 +88,7 @@ function tool_monitor_extend_navigation_user_settings($navigation, $user, $userc
         }
         $url = new moodle_url('/admin/tool/monitor/index.php', array('courseid' => $courseid));
         $subsnode = navigation_node::create(get_string('managesubscriptions', 'tool_monitor'), $url,
-                navigation_node::TYPE_SETTING, null, null, new pix_icon('i/settings', ''));
+                navigation_node::TYPE_SETTING, null, 'monitor', new pix_icon('i/settings', ''));
 
         if (isset($subsnode) && !empty($navigation)) {
             $navigation->add_node($subsnode);
index 5125284..0d25c54 100644 (file)
@@ -10,14 +10,14 @@ Feature: tool_monitor_rule
       | Course 1 | C1        |
     And the following "users" exist:
       | username | firstname | lastname | email |
-      | teacher1 | Teacher | 1 | teacher1@asd.com |
+      | teacher1 | Teacher | 1 | teacher1@example.com |
     And the following "course enrolments" exist:
       | user | course | role |
       | teacher1 | C1 | editingteacher |
     And I log in as "admin"
     And I navigate to "Event monitoring rules" node in "Site administration > Reports"
     And I click on "Enable" "link"
-    And I am on homepage
+    And I am on site homepage
     And I follow "Course 1"
     And I navigate to "Event monitoring rules" node in "Course administration > Reports"
     And I press "Add a new rule"
@@ -45,7 +45,7 @@ Feature: tool_monitor_rule
 
   Scenario: Add a rule on course level
     Given I log in as "teacher1"
-    And I am on homepage
+    And I am on site homepage
     And I follow "Course 1"
     And I navigate to "Event monitoring rules" node in "Course administration > Reports"
     When I press "Add a new rule"
index 253689c..27029aa 100644 (file)
@@ -11,8 +11,8 @@ Feature: tool_monitor_subscriptions
       | Course 2 | C2        |
     And the following "users" exist:
       | username | firstname | lastname | email |
-      | teacher1 | Teacher | 1 | teacher1@asd.com |
-      | teacher2 | Teacher | 2 | teacher2@asd.com |
+      | teacher1 | Teacher | 1 | teacher1@example.com |
+      | teacher2 | Teacher | 2 | teacher2@example.com |
     And the following "course enrolments" exist:
       | user | course | role |
       | teacher1 | C1 | editingteacher |
@@ -22,7 +22,7 @@ Feature: tool_monitor_subscriptions
     And I log in as "admin"
     And I navigate to "Event monitoring rules" node in "Site administration > Reports"
     And I click on "Enable" "link"
-    And I am on homepage
+    And I am on site homepage
     And I follow "Course 1"
     And I navigate to "Event monitoring rules" node in "Course administration > Reports"
     And I press "Add a new rule"
@@ -55,8 +55,8 @@ Feature: tool_monitor_subscriptions
 
   Scenario: Subscribe to a rule on course level
     Given I log in as "teacher1"
-    And I follow "Course 1"
-    And I navigate to "Event monitoring" node in "My profile settings"
+    And I follow "My preferences" in the user menu
+    And I follow "Event monitoring"
     And I set the field "Select a course" to "Course 1"
     When I follow "Subscribe to rule \"New rule course level\""
     Then I should see "Subscription successfully created"
@@ -64,8 +64,8 @@ Feature: tool_monitor_subscriptions
 
   Scenario: Delete a subscription on course level
     Given I log in as "teacher1"
-    And I follow "Course 1"
-    And I navigate to "Event monitoring" node in "My profile settings"
+    And I follow "My preferences" in the user menu
+    And I follow "Event monitoring"
     And I set the field "Select a course" to "Course 1"
     And I follow "Subscribe to rule \"New rule course level\""
     And I should see "Subscription successfully created"
@@ -77,16 +77,18 @@ Feature: tool_monitor_subscriptions
 
   Scenario: Subscribe to a rule on site level
     Given I log in as "admin"
-    And I navigate to "Event monitoring" node in "My profile settings"
-    And I set the field "Select a course" to "Site"
+    And I follow "My preferences" in the user menu
+    And I follow "Event monitoring"
+    And I set the field "Select a course" to "Acceptance test site"
     When I follow "Subscribe to rule \"New rule site level\""
     Then I should see "Subscription successfully created"
     And "#toolmonitorsubs_r0" "css_element" should exist
 
   Scenario: Delete a subscription on site level
     Given I log in as "admin"
-    And I navigate to "Event monitoring" node in "My profile settings"
-    And I set the field "Select a course" to "Site"
+    And I follow "My preferences" in the user menu
+    And I follow "Event monitoring"
+    And I set the field "Select a course" to "Acceptance test site"
     And I follow "Subscribe to rule \"New rule site level\""
     And I should see "Subscription successfully created"
     And "#toolmonitorsubs_r0" "css_element" should exist
@@ -98,82 +100,87 @@ Feature: tool_monitor_subscriptions
 
   Scenario: Receiving notification on site level
     Given I log in as "admin"
-    And I navigate to "Messaging" node in "My profile settings"
+    And I follow "My preferences" in the user menu
+    And I follow "Messaging"
     And I click on "input[name^=tool_monitor_notification_loggedin]" "css_element"
-    And I press "Update profile"
-    And I am on homepage
-    And I follow "Course 1"
-    And I navigate to "Event monitoring" node in "My profile settings"
-    And I set the field "Select a course" to "Site"
+    And I press "Save changes"
+    And I follow "My preferences" in the user menu
+    And I follow "Event monitoring"
+    And I set the field "Select a course" to "Acceptance test site"
     And I follow "Subscribe to rule \"New rule site level\""
     And I should see "Subscription successfully created"
     And "#toolmonitorsubs_r0" "css_element" should exist
-    And I am on homepage
+    And I am on site homepage
     And I trigger cron
-    And I am on homepage
-    When I navigate to "Messages" node in "My profile"
+    And I am on site homepage
+    When I follow "Messages" in the user menu
     And I follow "Do not reply to this email (1)"
     Then I should see "The course was viewed."
 
   Scenario: Receiving notification on course level
     Given I log in as "teacher1"
-    And I navigate to "Messaging" node in "My profile settings"
+    And I follow "My preferences" in the user menu
+    And I follow "Messaging"
     And I click on "input[name^=tool_monitor_notification_loggedin]" "css_element"
-    And I press "Update profile"
-    And I am on homepage
-    And I follow "Course 1"
-    And I navigate to "Event monitoring" node in "My profile settings"
+    And I press "Save changes"
+    And I follow "My preferences" in the user menu
+    And I follow "Event monitoring"
     And I set the field "Select a course" to "Course 1"
     And I follow "Subscribe to rule \"New rule course level\""
     And I should see "Subscription successfully created"
     And "#toolmonitorsubs_r0" "css_element" should exist
-    And I am on homepage
+    And I am on site homepage
     And I follow "Course 1"
     And I trigger cron
-    And I am on homepage
-    When I navigate to "Messages" node in "My profile"
+    And I am on site homepage
+    When I follow "Messages" in the user menu
     And I follow "Do not reply to this email (1)"
     Then I should see "The course was viewed."
 
   Scenario: Navigating via quick link to rules
     Given I log in as "admin"
-    When I navigate to "Event monitoring" node in "My profile settings"
+    And I follow "My preferences" in the user menu
+    When I follow "Event monitoring"
+    And I set the field "Select a course" to "Course 1"
     Then I should see "You can manage rules from the Event monitoring rules page."
     And I follow "Event monitoring rules"
     And I should see "You can subscribe to rules from the Event monitoring page."
     And I log out
     And I log in as "teacher1"
-    And I follow "Course 1"
-    And I navigate to "Event monitoring" node in "My profile settings"
+    And I follow "My preferences" in the user menu
+    And I follow "Event monitoring"
+    And I set the field "Select a course" to "Course 1"
     And I should see "You can manage rules from the Event monitoring rules page."
     And I follow "Event monitoring rules"
     And I should see "You can subscribe to rules from the Event monitoring page."
     And I click on "//a[text()='Event monitoring']" "xpath_element"
     And the field "courseid" matches value "Course 1"
-    And I set the field "courseid" to "Site"
+    And I set the field "courseid" to "Choose..."
     And I should not see "You can manage rules from the Event monitoring rules page."
     And I log out
     And I log in as "teacher2"
-    And I follow "Course 1"
-    And I navigate to "Event monitoring" node in "My profile settings"
+    And I follow "My preferences" in the user menu
+    And I follow "Event monitoring"
+    And I set the field "Select a course" to "Course 1"
     And I should not see "You can manage rules the from the Event monitoring rules page."
 
   Scenario: No manage rules link when user does not have permission
-    Given I log in as "teacher1"
-    When I follow "Course 1"
-    And I navigate to "Event monitoring" node in "My profile settings"
+    Given I log in as "admin"
+    And I set the following system permissions of "Non-editing teacher" role:
+      | tool/monitor:managerules | Prohibit |
+    And I log out
+    And I log in as "teacher1"
+    And I follow "My preferences" in the user menu
+    And I follow "Event monitoring"
+    When I set the field "Select a course" to "Course 1"
     Then I should see "You can manage rules from the Event monitoring rules page."
+    And I set the field "Select a course" to "Course 2"
+    And I should not see "You can manage rules from the Event monitoring rules page."
     And I log out
     And I log in as "teacher2"
-    And I follow "Course 1"
-    And I navigate to "Event monitoring" node in "My profile settings"
+    And I follow "My preferences" in the user menu
+    And I follow "Event monitoring"
+    And I set the field "Select a course" to "Course 1"
     And I should not see "You can manage rules from the Event monitoring rules page."
-    And I follow "Home"
-    And I follow "Course 2"
-    And I navigate to "Event monitoring" node in "My profile settings"
+    And I set the field "Select a course" to "Course 2"
     And I should see "You can manage rules from the Event monitoring rules page."
-    And I log out
-    And I log in as "teacher1"
-    And I follow "Course 2"
-    And I navigate to "Event monitoring" node in "My profile settings"
-    And I should not see "You can manage rules from the Event monitoring rules page."
diff --git a/admin/tool/templatelibrary/amd/build/display.min.js b/admin/tool/templatelibrary/amd/build/display.min.js
new file mode 100644 (file)
index 0000000..3bc7ab4
Binary files /dev/null and b/admin/tool/templatelibrary/amd/build/display.min.js differ
diff --git a/admin/tool/templatelibrary/amd/build/search.min.js b/admin/tool/templatelibrary/amd/build/search.min.js
new file mode 100644 (file)
index 0000000..062e585
Binary files /dev/null and b/admin/tool/templatelibrary/amd/build/search.min.js differ
diff --git a/admin/tool/templatelibrary/amd/src/display.js b/admin/tool/templatelibrary/amd/src/display.js
new file mode 100644 (file)
index 0000000..a6c4a70
--- /dev/null
@@ -0,0 +1,116 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This module adds ajax display functions to the template library page.
+ *
+ * @module     tool_templatelibrary/display
+ * @package    tool_templatelibrary
+ * @copyright  2015 Damyon Wiese <damyon@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['jquery', 'core/ajax', 'core/log', 'core/notification', 'core/templates', 'core/config', 'core/str'],
+       function($, ajax, log, notification, templates, config, str) {
+
+    /**
+     * Handle a template loaded response.
+     *
+     * @param {String} templateName The template name
+     * @param {String} source The template source
+     */
+    var templateLoaded = function(templateName, source) {
+        str.get_string('templateselected', 'tool_templatelibrary', templateName).done(function(s) {
+            $('[data-region="displaytemplateheader"]').text(s);
+        }).fail(notification.exception);
+
+        // Find the comment section marked with @template component/template.
+        var marker = "@template " + templateName;
+
+        var sections = source.match(/{{!([\s\S]*?)}}/g);
+        var i = 0;
+
+        // If no sections match - show the entire file.
+        if (sections !== null) {
+            for (i = 0; i < sections.length; i++) {
+                var section = sections[i];
+                var start = section.indexOf(marker);
+                if (start !== -1) {
+                    // Remove {{! and }} from start and end.
+                    var offset = start + marker.length + 1;
+                    section = section.substr(offset, section.length - 2 - offset);
+                    source = section;
+                    break;
+                }
+            }
+        }
+
+        $('[data-region="displaytemplatesource"]').text(source);
+
+        // Now search the text for a json example.
+
+        var example = source.match(/Example context \(json\):([\s\S]*)/);
+        var context = false;
+        if (example) {
+            var rawJSON = example[1].trim();
+            try {
+                context = $.parseJSON(rawJSON);
+            } catch (e) {
+                log.debug('Could not parse json example context for template.');
+                log.debug(e);
+            }
+        }
+        if (context) {
+            templates.render(templateName, context).done(function(html, js) {
+                $('[data-region="displaytemplateexample"]').empty();
+                $('[data-region="displaytemplateexample"]').append(html);
+                templates.runTemplateJS(js);
+            }).fail(notification.exception);
+        } else {
+            str.get_string('templatehasnoexample', 'tool_templatelibrary').done(function(s) {
+                $('[data-region="displaytemplateexample"]').text(s);
+            }).fail(notification.exception);
+        }
+    };
+
+    /**
+     * Load the a template source from Moodle.
+     * @param {String} templateName
+     */
+    var loadTemplate = function(templateName) {
+        var parts = templateName.split('/');
+        var component = parts.shift();
+        var name = parts.shift();
+
+        ajax.call([{
+            methodname: 'core_output_load_template',
+            args:{
+                    component: component,
+                    template: name,
+                    themename: config.theme
+            },
+            done: function(source) { templateLoaded(templateName, source); },
+            fail: notification.exception
+        }]);
+    };
+
+    // Add the event listeners.
+    $('[data-region="list-templates"]').on('click', '[data-templatename]', function() {
+        var templatename = $(this).data('templatename');
+        loadTemplate(templatename);
+    });
+
+    // This module does not expose anything.
+    return {};
+});
diff --git a/admin/tool/templatelibrary/amd/src/search.js b/admin/tool/templatelibrary/amd/src/search.js
new file mode 100644 (file)
index 0000000..d4eefe6
--- /dev/null
@@ -0,0 +1,89 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This module adds ajax search functions to the template library page.
+ *
+ * @module     tool_templatelibrary/search
+ * @package    tool_templatelibrary
+ * @copyright  2015 Damyon Wiese <damyon@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['jquery', 'core/ajax', 'core/log', 'core/notification', 'core/templates'],
+       function($, ajax, log, notification, templates) {
+
+    /**
+     * The ajax call has returned with a new list of templates.
+     *
+     * @method reloadListTemplate
+     * @param String[] templates List of template ids.
+     */
+    var reloadListTemplate = function(templateList) {
+        templates.render('tool_templatelibrary/search_results', { templates: templateList })
+            .done(function (result) {
+                $('[data-region="searchresults"]').replaceWith(result);
+            }).fail(notification.exception);
+    };
+
+    /**
+     * Get the current values for the form inputs and refresh the list of matching templates.
+     *
+     * @method refreshSearch
+     */
+    var refreshSearch = function() {
+        var componentStr = $('[data-field="component"]').val();
+        var searchStr = $('[data-field="search"]').val();
+
+        // Trigger the search.
+
+        ajax.call([
+            { methodname: 'tool_templatelibrary_list_templates',
+              args: { component: componentStr, search: searchStr },
+              done: reloadListTemplate,
+              fail: notification.exception }
+        ]);
+    };
+
+    var throttle = null;
+
+    /**
+     * Call the specified function after a delay. If this function is called again before the function is executed,
+     * the function will only be executed once.
+     *
+     * @method queueRefresh
+     * @param function callback
+     * @param int delay The time in milliseconds to delay.
+     */
+    var queueRefresh = function(callback, delay) {
+        if (throttle !== null) {
+            window.clearTimeout(throttle);
+        }
+
+        throttle = window.setTimeout(function() {
+            callback();
+            throttle = null;
+        }, delay);
+    };
+
+    var changeHandler = function() {
+        queueRefresh(refreshSearch, 400);
+    };
+    // Add change handlers to refresh the list.
+    $('[data-region="list-templates"]').on('change', '[data-field="component"]', changeHandler);
+    $('[data-region="list-templates"]').on('input', '[data-field="search"]', changeHandler);
+
+    refreshSearch();
+    return {};
+});
diff --git a/admin/tool/templatelibrary/classes/api.php b/admin/tool/templatelibrary/classes/api.php
new file mode 100644 (file)
index 0000000..c818c86
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Class for listing mustache templates.
+ *
+ * @package    tool_templatelibrary
+ * @copyright  2015 Damyon Wiese
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace tool_templatelibrary;
+
+use stdClass;
+use core_component;
+use coding_exception;
+use required_capability_exception;
+
+/**
+ * API exposed by tool_templatelibrary
+ *
+ * @copyright  2015 Damyon Wiese
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class api {
+
+    /**
+     * Return a list of details about installed templates.
+     *
+     * @param string $component Filter the list to a single component.
+     * @param string $search Search string to optionally filter the list of templates.
+     * @return array[string] Where each template is in the form "component/templatename".
+     */
+    public static function list_templates($component = '', $search = '') {
+        global $CFG;
+
+        $templatedirs = array();
+        $results = array();
+
+        if ($component != '') {
+            // Just look at one component for templates.
+            $dir = core_component::get_component_directory($component);
+            if (!$dir) {
+                return $templatedirs;
+            }
+
+            $templatedirs[$component] = $dir . '/templates';
+        } else {
+
+            // Look at all the templates dirs for all installed plugins.
+            $dir = $CFG->libdir . '/templates';
+            if (!empty($dir) && is_dir($dir)) {
+                $templatedirs['core'] = $dir;
+            }
+            $plugintypes = core_component::get_plugin_types();
+            foreach ($plugintypes as $type => $dir) {
+                $plugins = core_component::get_plugin_list_with_file($type, 'templates', false);
+                foreach ($plugins as $plugin => $dir) {
+                    if (!empty($dir) && is_dir($dir)) {
+                        $templatedirs[$type . '_' . $plugin] = $dir;
+                    }
+                }
+            }
+        }
+
+        foreach ($templatedirs as $templatecomponent => $dir) {
+            // List it.
+            $files = glob($dir . '/*.mustache');
+
+            foreach ($files as $file) {
+                $templatename = basename($file, '.mustache');
+                if ($search == '' || strpos($templatename, $search) !== false) {
+                    $results[] = $templatecomponent . '/' . $templatename;
+                }
+            }
+        }
+        return $results;
+    }
+
+}
diff --git a/admin/tool/templatelibrary/classes/external.php b/admin/tool/templatelibrary/classes/external.php
new file mode 100644 (file)
index 0000000..630f040
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This is the external API for this tool.
+ *
+ * @package    tool_templatelibrary
+ * @copyright  2015 Damyon Wiese
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace tool_templatelibrary;
+
+require_once("$CFG->libdir/externallib.php");
+
+use external_api;
+use external_function_parameters;
+use external_value;
+use external_format_value;
+use external_single_structure;
+use external_multiple_structure;
+use invalid_parameter_exception;
+
+/**
+ * This is the external API for this tool.
+ *
+ * @copyright  2015 Damyon Wiese
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class external extends external_api {
+
+    /**
+     * Returns description of list_templates() parameters.
+     *
+     * @return external_function_parameters
+     */
+    public static function list_templates_parameters() {
+        $component = new external_value(
+            PARAM_COMPONENT,
+            'The component to search',
+            VALUE_DEFAULT,
+            ''
+        );
+        $search = new external_value(
+            PARAM_RAW,
+            'The search string',
+            VALUE_DEFAULT,
+            ''
+        );
+        $params = array('component' => $component, 'search' => $search);
+        return new external_function_parameters($params);
+    }
+
+    /**
+     * Expose to AJAX
+     * @return boolean
+     */
+    public static function list_templates_is_allowed_from_ajax() {
+        return true;
+    }
+
+    /**
+     * Loads the list of templates.
+     * @param string $component Limit the search to a component.
+     * @param string $search The search string.
+     * @return array[string]
+     */
+    public static function list_templates($component, $search) {
+        $params = self::validate_parameters(self::list_templates_parameters(),
+                                            array(
+                                                'component' => $component,
+                                                'search' => $search,
+                                            ));
+
+        return api::list_templates($component, $search);
+    }
+
+    /**
+     * Returns description of list_templates() result value.
+     *
+     * @return external_description
+     */
+    public static function list_templates_returns() {
+        return new external_multiple_structure(new external_value(PARAM_RAW, 'The template name (format is component/templatename)'));
+    }
+}
diff --git a/admin/tool/templatelibrary/classes/output/list_templates_page.php b/admin/tool/templatelibrary/classes/output/list_templates_page.php
new file mode 100644 (file)
index 0000000..8377e8b
--- /dev/null
@@ -0,0 +1,72 @@
+<?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/>.
+
+/**
+ * Class containing data for list_templates page
+ *
+ * @package    tool_templatelibrary
+ * @copyright  2015 Damyon Wiese
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace tool_templatelibrary\output;
+
+use renderable;
+use templatable;
+use renderer_base;
+use stdClass;
+use core_plugin_manager;
+use tool_templatelibrary\api;
+
+/**
+ * Class containing data for list_templates page
+ *
+ * @copyright  2015 Damyon Wiese
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class list_templates_page implements renderable, templatable {
+
+    /**
+     * Export this data so it can be used as the context for a mustache template.
+     *
+     * @return stdClass
+     */
+    public function export_for_template(renderer_base $output) {
+        $data = new stdClass();
+        $data->allcomponents = array();
+        $fulltemplatenames = api::list_templates();
+        $pluginmanager = core_plugin_manager::instance();
+        $components = array();
+
+        foreach ($fulltemplatenames as $templatename) {
+            list($component, $templatename) = explode('/', $templatename, 2);
+            $components[$component] = 1;
+        }
+
+        $components = array_keys($components);
+        foreach ($components as $component) {
+            $info = new stdClass();
+            $info->component = $component;
+            if ($component == 'core') {
+                $info->name = get_string('core_component', 'tool_templatelibrary');
+            } else {
+                $info->name = $pluginmanager->plugin_name($component);
+            }
+            $data->allcomponents[] = $info;
+        }
+
+        return $data;
+    }
+}
diff --git a/admin/tool/templatelibrary/classes/output/renderer.php b/admin/tool/templatelibrary/classes/output/renderer.php
new file mode 100644 (file)
index 0000000..1fc0735
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Renderer class for template library.
+ *
+ * @package    tool_templatelibrary
+ * @copyright  2015 Damyon Wiese
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace tool_templatelibrary\output;
+
+defined('MOODLE_INTERNAL') || die;
+
+use plugin_renderer_base;
+
+/**
+ * Renderer class for template library.
+ *
+ * @package    tool_templatelibrary
+ * @copyright  2015 Damyon Wiese
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class renderer extends plugin_renderer_base {
+
+    /**
+     * Defer to template.
+     *
+     * @param list_templates_page $page
+     *
+     * @return string html for the page
+     */
+    public function render_list_templates_page($page) {
+        $data = $page->export_for_template($this);
+        return parent::render_from_template('tool_templatelibrary/list_templates_page', $data);
+    }
+
+}
diff --git a/admin/tool/templatelibrary/db/services.php b/admin/tool/templatelibrary/db/services.php
new file mode 100644 (file)
index 0000000..fdecc01
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Template library webservice definitions.
+ *
+ *
+ * @package    tool_templatelibrary
+ * @copyright  2015 Damyon Wiese
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$functions = array(
+
+    'tool_templatelibrary_list_templates' => array(
+        'classname'   => 'tool_templatelibrary\external',
+        'methodname'  => 'list_templates',
+        'classpath'   => '',
+        'description' => 'List/search templates by component.',
+        'type'        => 'read',
+        'capabilities'=> '',
+    ),
+);
+
diff --git a/admin/tool/templatelibrary/index.php b/admin/tool/templatelibrary/index.php
new file mode 100644 (file)
index 0000000..b7703ba
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This page lets users to manage site wide competencies.
+ *
+ * @package    tool_templatelibrary
+ * @copyright  2015 Damyon Wiese
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(__DIR__ . '/../../../config.php');
+require_once($CFG->libdir.'/adminlib.php');
+
+admin_externalpage_setup('tooltemplatelibrary');
+
+$component = optional_param('component', '', PARAM_COMPONENT);
+$search = optional_param('search', '', PARAM_RAW);
+
+$title = get_string('templates', 'tool_templatelibrary');
+$pagetitle = get_string('searchtemplates', 'tool_templatelibrary');
+// Set up the page.
+$url = new moodle_url("/admin/tool/templatelibrary/index.php", array('component' => $component, 'search' => $search));
+$PAGE->set_url($url);
+$PAGE->set_title($title);
+$PAGE->set_heading($title);
+$output = $PAGE->get_renderer('tool_templatelibrary');
+echo $output->header();
+echo $output->heading($pagetitle);
+
+$page = new \tool_templatelibrary\output\list_templates_page($component, $search);
+echo $output->render($page);
+
+echo $output->footer();
diff --git a/admin/tool/templatelibrary/lang/en/tool_templatelibrary.php b/admin/tool/templatelibrary/lang/en/tool_templatelibrary.php
new file mode 100644 (file)
index 0000000..87b8ea0
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'tool_templatelibrary', language 'en'
+ *
+ * @package    tool_templatelibrary
+ * @copyright  2015 Damyon Wiese
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['all'] = 'All components';
+$string['component'] = 'Component';
+$string['core_component'] = 'Moodle core';
+$string['documentation'] = 'Documentation';
+$string['example'] = 'Example';
+$string['noresults'] = 'No results';
+$string['notemplateselected'] = 'No template selected';
+$string['pluginname'] = 'Template library';
+$string['search'] = 'Search';
+$string['searchtemplates'] = 'Search templates';
+$string['templatehasnoexample'] = 'This template has no example context, so it cannot be rendered here. To add an example context to this template, insert in a Mustache comment "Example context (json):", followed by the json encoded sample context for the template.';
+$string['templates'] = 'Templates';
+$string['templateselected'] = 'Template: {$a}';
diff --git a/admin/tool/templatelibrary/settings.php b/admin/tool/templatelibrary/settings.php
new file mode 100644 (file)
index 0000000..764aa03
--- /dev/null
@@ -0,0 +1,33 @@
+<?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/>.
+
+/**
+ * Links and settings
+ *
+ * This file contains links and settings used by tool_templatelibrary
+ *
+ * @package    tool_templatelibrary
+ * @copyright  2015 Damyon Wiese
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+defined('MOODLE_INTERNAL') || die;
+// Template library page.
+$temp = new admin_externalpage(
+    'tooltemplatelibrary',
+    get_string('pluginname', 'tool_templatelibrary'),
+    new moodle_url('/admin/tool/templatelibrary/index.php')
+);
+$ADMIN->add('development', $temp);
diff --git a/admin/tool/templatelibrary/styles.css b/admin/tool/templatelibrary/styles.css
new file mode 100644 (file)
index 0000000..5dad936
--- /dev/null
@@ -0,0 +1,5 @@
+[data-region="displaytemplateexample"] {
+    border-radius: 4px;
+    border: 1px inset #e3e3e3;
+    padding: 1em;
+}
diff --git a/admin/tool/templatelibrary/templates/display_template.mustache b/admin/tool/templatelibrary/templates/display_template.mustache
new file mode 100644 (file)
index 0000000..d5044a5
--- /dev/null
@@ -0,0 +1,50 @@
+{{!
+    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/>.
+}}
+{{!
+    @template tool_templatelibrary/display_template
+
+    Moodle template to display another template.
+
+    The purpose of this template is to put scafolding in the page, so the javascript can fetch templates and
+    insert them into this part of the page.
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * data-region
+
+    Context variables required for this template:
+    * none
+
+    Example context (json):
+    { }
+
+}}
+<div data-region="displaytemplate">
+        <h3 data-region="displaytemplateheader">{{#str}}notemplateselected, tool_templatelibrary{{/str}}</h3>
+        <div>
+            <h4>{{#str}}example, tool_templatelibrary{{/str}}</h4>
+            <div data-region="displaytemplateexample">
+                -
+            </div>
+        </div>
+        <div>
+            <h4>{{#str}}documentation, tool_templatelibrary{{/str}}</h4>
+            <pre data-region="displaytemplatesource"> - </pre>
+        </div>
+</div>
diff --git a/admin/tool/templatelibrary/templates/list_templates_page.mustache b/admin/tool/templatelibrary/templates/list_templates_page.mustache
new file mode 100644 (file)
index 0000000..0526c94
--- /dev/null
@@ -0,0 +1,63 @@
+{{!
+    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/>.
+}}
+{{!
+    @template tool_templatelibrary/list_templates_page
+
+    Moodle template to the template library
+
+    The purpose of this template is build the entire page for the template library (by including smaller templates).
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * data-region, data-field
+
+    Context variables required for this template:
+    * allcomponents - array of components containing templates. Each component has a name and a component attribute.
+
+}}
+<div data-region="list-templates">
+    <form class="form-horizontal">
+        <div class="control-group">
+            <label for="selectcomponent" class="control-label">{{#str}}component, tool_templatelibrary{{/str}}</label>
+            <div class="controls">
+                <select id="selectcomponent" data-field="component">
+                    <option value="">{{#str}}all, tool_templatelibrary{{/str}}</option>
+                    {{#allcomponents}}
+                        <option value="{{component}}">{{name}}</option>
+                    {{/allcomponents}}
+                </select>
+            </div>
+        </div>
+        <div class="control-group">
+            <label for="search" class="control-label">{{#str}}search, tool_templatelibrary{{/str}}</label>
+            <div class="controls">
+                <input type="text" id="search" data-field="search"/>
+            </div>
+        </div>
+    </form>
+    <hr/>
+    {{> tool_templatelibrary/search_results }}
+
+    <hr/>
+    {{> tool_templatelibrary/display_template }}
+
+</div>
+{{#js}}
+    require(['tool_templatelibrary/search', 'tool_templatelibrary/display']);
+{{/js}}
diff --git a/admin/tool/templatelibrary/templates/search_results.mustache b/admin/tool/templatelibrary/templates/search_results.mustache
new file mode 100644 (file)
index 0000000..c879ae8
--- /dev/null
@@ -0,0 +1,46 @@
+{{!
+    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/>.
+}}
+{{!
+    @template tool_templatelibrary/search_results
+
+    Moodle template to display results of template search.
+
+    This template gets rendered by javascript when it has searched for templates.
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * data-region, data-templatename
+
+    Context variables required for this template:
+    * templates - And array of template names.
+
+    Example context (json):
+    { "templates" : [ "core/pix_icon", "tool_templatelibrary/display_template" ] }
+
+}}
+<div data-region="searchresults" aria-live="off" class="no-overflow" style="max-height: 10em">
+{{^templates}}
+<p class="text-warning">{{#str}}noresults, tool_templatelibrary{{/str}}</p>
+{{/templates}}
+<ul>
+{{#templates}}
+<li data-templatename="{{.}}"><a href="#">{{.}}</a></li>
+{{/templates}}
+</ul>
+</div>
diff --git a/admin/tool/templatelibrary/tests/externallib_test.php b/admin/tool/templatelibrary/tests/externallib_test.php
new file mode 100644 (file)
index 0000000..db9d4df
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+
+require_once($CFG->dirroot . '/webservice/tests/helpers.php');
+
+use tool_templatelibrary\external;
+
+/**
+ * External learning plans webservice API tests.
+ *
+ * @package tool_templatelibrary
+ * @copyright 2015 Damyon Wiese
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class tool_templatelibrary_external_testcase extends externallib_advanced_testcase {
+
+    /**
+     * Test list all.
+     */
+    public function test_list_templates() {
+        $result = external::list_templates('', '');
+        $count = count($result);
+        // We have 3 templates in this tool - and there must be more else where.
+        $this->assertGreaterThan(3, $count);
+    }
+
+    /**
+     * Test we can filter by component.
+     */
+    public function test_list_templates_for_component() {
+        $result = external::list_templates('tool_templatelibrary', '');
+        $count = count($result);
+        $this->assertEquals(3, $count);
+
+        $this->assertContains("tool_templatelibrary/display_template", $result);
+        $this->assertContains("tool_templatelibrary/search_results", $result);
+        $this->assertContains("tool_templatelibrary/list_templates_page", $result);
+    }
+
+    /**
+     * Test we can filter by a string.
+     */
+    public function test_list_templates_with_filter() {
+        $result = external::list_templates('tool_templatelibrary', 'page');
+        $count = count($result);
+        // Should be only one matching template.
+        $this->assertEquals(1, $count);
+        $this->assertEquals($result[0], "tool_templatelibrary/list_templates_page");
+    }
+
+
+}
diff --git a/admin/tool/templatelibrary/version.php b/admin/tool/templatelibrary/version.php
new file mode 100644 (file)
index 0000000..085d347
--- /dev/null
@@ -0,0 +1,26 @@
+<?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/>.
+/**
+ * Plugin version info
+ *
+ * @package    tool_templatelibrary
+ * @copyright  2015 Damyon Wiese
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+defined('MOODLE_INTERNAL') || die();
+$plugin->version   = 2015021623; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2014110400; // Requires this Moodle version.
+$plugin->component = 'tool_templatelibrary'; // Full name of the plugin (used for diagnostics).
index eed6fab..b1e26f3 100644 (file)
@@ -21,7 +21,7 @@ Feature: An admin can create courses using a CSV file
     And I should see "Courses total: 3"
     And I should see "Courses created: 2"
     And I should see "Courses errors: 1"
-    And I follow "Home"
+    And I am on site homepage
     And I should see "Course 2"
     And I should see "Course 3"
 
@@ -38,7 +38,7 @@ Feature: An admin can create courses using a CSV file
     And I should see "Courses total: 3"
     And I should see "Courses created: 3"
     And I should see "Courses errors: 0"
-    And I follow "Home"
+    And I am on site homepage
     And I should see "Course 1"
     And I should see "Course 2"
     And I should see "Course 3"
index b574b66..73d2394 100644 (file)
@@ -24,7 +24,7 @@ Feature: An admin can update courses using a CSV file
     And I should see "Courses updated: 1"
     And I should see "Courses created: 0"
     And I should see "Courses errors: 2"
-    And I follow "Home"
+    And I am on site homepage
     And I should see "Course 1"
     And I should not see "Course 2"
     And I should not see "Course 3"
index 287ebb2..ae3dfe3 100644 (file)
@@ -421,8 +421,14 @@ function uu_pre_process_custom_profile_data($data) {
 function uu_check_custom_profile_data(&$data) {
     global $CFG, $DB;
     $noerror = true;
+    $testuserid = null;
 
-    // find custom profile fields and check if data needs to converted.
+    if (!empty($data['username'])) {
+        if (preg_match('/id=(.*)"/i', $data['username'], $result)) {
+            $testuserid = $result[1];
+        }
+    }
+    // Find custom profile fields and check if data needs to converted.
     foreach ($data as $key => $value) {
         if (preg_match('/^profile_field_/', $key)) {
             $shortname = str_replace('profile_field_', '', $key);
@@ -436,9 +442,20 @@ function uu_check_custom_profile_data(&$data) {
                         $data['status'][] = get_string('invaliduserfield', 'error', $shortname);
                         $noerror = false;
                     }
+                    // Check for duplicate value.
+                    if (method_exists($formfield, 'edit_validate_field') ) {
+                        $testuser = new stdClass();
+                        $testuser->{$key} = $value;
+                        $testuser->id = $testuserid;
+                        $err = $formfield->edit_validate_field($testuser);
+                        if (!empty($err[$key])) {
+                            $data['status'][] = $err[$key].' ('.$key.')';
+                            $noerror = false;
+                        }
+                    }
                 }
             }
         }
     }
     return $noerror;
-}
\ No newline at end of file
+}
index 5c919b9..444da9a 100644 (file)
@@ -58,5 +58,18 @@ function xmldb_auth_cas_upgrade($oldversion) {
     // Moodle v2.8.0 release upgrade line.
     // Put any upgrade step following this.
 
+    if ($oldversion < 2014111001) {
+        global $DB;
+        // From now on the default LDAP objectClass setting for AD has been changed, from 'user' to '(samaccounttype=805306368)'.
+        if (is_enabled_auth('cas')
+                && ($DB->get_field('config_plugins', 'value', array('name' => 'user_type', 'plugin' => 'auth/cas')) === 'ad')
+                && ($DB->get_field('config_plugins', 'value', array('name' => 'objectclass', 'plugin' => 'auth/cas')) === '')) {
+            // Save the backwards-compatible default setting.
+            set_config('objectclass', 'user', 'auth/cas');
+        }
+
+        upgrade_plugin_savepoint(true, 2014111001, 'auth', 'cas');
+    }
+
     return true;
 }
index 874605c..f2c0008 100644 (file)
@@ -26,7 +26,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014111000;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2014111001;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2014110400;        // Requires this Moodle version
 $plugin->component = 'auth_cas';        // Full name of the plugin (used for diagnostics)
 
index 6104551..1170c8e 100644 (file)
@@ -24,7 +24,7 @@
 
 $string['auth_emaildescription'] = '<p>Email-based self-registration enables a user to create their own account via a \'Create new account\' button on the login page. The user then receives an email containing a secure link to a page where they can confirm their account. Future logins just check the username and password against the stored values in the Moodle database.</p><p>Note: In addition to enabling the plugin, email-based self-registration must also be selected from the self registration drop-down menu on the \'Manage authentication\' page.</p>';
 $string['auth_emailnoemail'] = 'Tried to send you an email but failed!';
-$string['auth_emailrecaptcha'] = 'Adds a visual/audio confirmation form element to the signup page for email self-registering users. This protects your site against spammers and contributes to a worthwhile cause. See http://www.google.com/recaptcha/learnmore for more details. <br /><em>PHP cURL extension is required.</em>';
+$string['auth_emailrecaptcha'] = 'Adds a visual/audio confirmation form element to the sign-up page for email self-registering users. This protects your site against spammers and contributes to a worthwhile cause. See http://www.google.com/recaptcha for more details.';
 $string['auth_emailrecaptcha_key'] = 'Enable reCAPTCHA element';
 $string['auth_emailsettings'] = 'Settings';
 $string['pluginname'] = 'Email-based self-registration';
index 95364f2..ae894ba 100644 (file)
@@ -48,5 +48,18 @@ function xmldb_auth_ldap_upgrade($oldversion) {
     // Moodle v2.8.0 release upgrade line.
     // Put any upgrade step following this.
 
+    if ($oldversion < 2014111001) {
+        global $DB;
+        // From now on the default LDAP objectClass setting for AD has been changed, from 'user' to '(samaccounttype=805306368)'.
+        if (is_enabled_auth('ldap')
+                && ($DB->get_field('config_plugins', 'value', array('name' => 'user_type', 'plugin' => 'auth/ldap')) === 'ad')
+                && ($DB->get_field('config_plugins', 'value', array('name' => 'objectclass', 'plugin' => 'auth/ldap')) === '')) {
+            // Save the backwards-compatible default setting.
+            set_config('objectclass', 'user', 'auth/ldap');
+        }
+
+        upgrade_plugin_savepoint(true, 2014111001, 'auth', 'ldap');
+    }
+
     return true;
 }
index ebb6f31..59a1f9d 100644 (file)
@@ -296,7 +296,7 @@ class auth_ldap_plugin_testcase extends advanced_testcase {
             'lastnamephonetic' => '最後のお名前のテスト一号',
             'firstnamephonetic' => 'お名前のテスト一号',
             'alternatename' => 'Alternate Name User Test 1',
-            'email' => 'usersignuptest1@email.com',
+            'email' => 'usersignuptest1@example.com',
             'description' => 'This is a description for user 1',
             'city' => 'Perth',
             'country' => 'au',
index 2b10708..76b267d 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014111000;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2014111001;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2014110400;        // Requires this Moodle version
 $plugin->component = 'auth_ldap';       // Full name of the plugin (used for diagnostics)
index 3641b91..6970800 100644 (file)
@@ -16,8 +16,8 @@ Feature: Authentication
   Scenario: Log in as an existing admin user filling the form
     Given the following "users" exist:
       | username | password | firstname | lastname | email |
-      | testuser | testuser | Test | User | moodle@moodlemoodle.com |
-    And I am on homepage
+      | testuser | testuser | Test | User | moodle@example.com |
+    And I am on site homepage
     When I follow "Log in"
     And I set the field "Username" to "testuser"
     And I set the field "Password" to "testuser"
@@ -27,8 +27,8 @@ Feature: Authentication
   Scenario: Log in as an unexisting user filling the form
     Given the following "users" exist:
       | username | password | firstname | lastname | email |
-      | testuser | testuser | Test | User | moodle@moodlemoodle.com |
-    And I am on homepage
+      | testuser | testuser | Test | User | moodle@example.com |
+    And I am on site homepage
     When I follow "Log in"
     And I set the field "Username" to "testuser"
     And I set the field "Password" to "unexisting"
index b31b7c6..3d95470 100644 (file)
@@ -24,6 +24,7 @@ Feature: availability_completion
   Scenario: Test condition
     # Basic setup.
     Given I log in as "teacher1"
+    And I am on site homepage
     And I follow "Course 1"
     And I turn editing mode on
 
@@ -50,6 +51,7 @@ Feature: availability_completion
     # Log back in as student.
     When I log out
     And I log in as "student1"
+    And I am on site homepage
     And I follow "Course 1"
 
     # Page 2 should not appear yet.
index d026849..925781d 100644 (file)
@@ -23,6 +23,7 @@ Feature: availability_date
   Scenario: Test condition
     # Basic setup.
     Given I log in as "teacher1"
+    And I am on site homepage
     And I follow "Course 1"
     And I turn editing mode on
 
@@ -56,6 +57,7 @@ Feature: availability_date
     # Log back in as student.
     When I log out
     And I log in as "student1"
+    And I am on site homepage
     And I follow "Course 1"
 
     # Page 1 should appear, but page 2 does not.
index 01681d7..967e7c8 100644 (file)
@@ -10,8 +10,8 @@ Feature: availability_grade
       | Course 1 | C1        | topics | 1                |
     And the following "users" exist:
       | username | email         |
-      | teacher1 | t@example.org |
-      | student1 | s@example.org |
+      | teacher1 | t@example.com |
+      | student1 | s@example.com |
     And the following "course enrolments" exist:
       | user     | course | role           |
       | teacher1 | C1     | editingteacher |
@@ -23,6 +23,7 @@ Feature: availability_grade
   Scenario: Test condition
     # Basic setup.
     Given I log in as "teacher1"
+    And I am on site homepage
     And I follow "Course 1"
     And I turn editing mode on
 
@@ -58,8 +59,22 @@ Feature: availability_grade
     And I set the field "Grade" to "A1"
     And I click on "min" "checkbox" in the ".availability-item" "css_element"
     And I set the field "Minimum grade percentage (inclusive)" to "50"
+    And I click on "max" "checkbox" in the ".availability-item" "css_element"
+    And I set the field "Maximum grade percentage (exclusive)" to "80"
     And I press "Save and return to course"
 
+    # Check if disabling a part of the restriction is get saved.
+    And I open "P3" actions menu
+    And I click on "Edit settings" "link" in the "P3" activity
+    And I expand all fieldsets
+    And I click on "max" "checkbox" in the ".availability-item" "css_element"
+    And I press "Save and return to course"
+    And I open "P3" actions menu
+    And I click on "Edit settings" "link" in the "P3" activity
+    And I expand all fieldsets
+    And the field "Maximum grade percentage (exclusive)" matches value ""
+    And I follow "Course 1"
+
     # Add a Page with a grade condition for 10%.
     And I add a "Page" to section "4"
     And I set the following fields to these values:
@@ -78,6 +93,7 @@ Feature: availability_grade
     # Log in as student without a grade yet.
     When I log out
     And I log in as "student1"
+    And I am on site homepage
     And I follow "Course 1"
 
     # Do the assignment.
@@ -96,19 +112,21 @@ Feature: availability_grade
     # Log back in as teacher.
     When I log out
     And I log in as "teacher1"
+    And I am on site homepage
     And I follow "Course 1"
 
     # Give the assignment 40%.
     And I follow "A1"
     And I follow "View/grade all submissions"
-    # Pick the grade link in the row that has s@example.org in it.
-    And I click on "//a[contains(@href, 'action=grade') and ancestor::tr/td[normalize-space(.) = 's@example.org']]/img" "xpath_element"
+    # Pick the grade link in the row that has s@example.com in it.
+    And I click on "//a[contains(@href, 'action=grade') and ancestor::tr/td[normalize-space(.) = 's@example.com']]/img" "xpath_element"
     And I set the field "Grade out of 100" to "40"
     And I click on "Save changes" "button"
 
     # Log back in as student.
     And I log out
     And I log in as "student1"
+    And I am on site homepage
     And I follow "Course 1"
 
     # Check pages are visible.
index ad24176..196e02f 100644 (file)
Binary files a/availability/condition/grade/yui/build/moodle-availability_grade-form/moodle-availability_grade-form-debug.js and b/availability/condition/grade/yui/build/moodle-availability_grade-form/moodle-availability_grade-form-debug.js differ
index 57654e4..c7467b5 100644 (file)
Binary files a/availability/condition/grade/yui/build/moodle-availability_grade-form/moodle-availability_grade-form-min.js and b/availability/condition/grade/yui/build/moodle-availability_grade-form/moodle-availability_grade-form-min.js differ
index ad24176..196e02f 100644 (file)
Binary files a/availability/condition/grade/yui/build/moodle-availability_grade-form/moodle-availability_grade-form.js and b/availability/condition/grade/yui/build/moodle-availability_grade-form/moodle-availability_grade-form.js differ
index 92108aa..b8717b1 100644 (file)
@@ -92,6 +92,7 @@ M.availability_grade.form.getNode = function(json) {
 
         root.delegate('click', function() {
             updateCheckbox(this, true);
+            M.core_availability.form.update();
         }, '.availability_grade input[type=checkbox]');
 
         root.delegate('valuechange', function() {
index d2637d6..d3c2b06 100644 (file)
@@ -23,6 +23,7 @@ Feature: availability_group
   Scenario: Test condition
     # Basic setup.
     Given I log in as "teacher1"
+    And I am on site homepage
     And I follow "Course 1"
     And I turn editing mode on
 
@@ -40,7 +41,7 @@ Feature: availability_group
       | G2       | C1     | GI2      |
     # This step used to be 'And I follow "C1"', but Chrome thinks the breadcrumb
     # is not clickable, so we'll go via the home page instead.
-    And I am on homepage
+    And I am on site homepage
     And I follow "Course 1"
     And I add a "Page" to section "1"
     And I expand all fieldsets
@@ -86,6 +87,7 @@ Feature: availability_group
     # Log back in as student.
     When I log out
     And I log in as "student1"
+    And I am on site homepage
     And I follow "Course 1"
 
     # No pages should appear yet.
@@ -99,6 +101,7 @@ Feature: availability_group
       | student1 | GI1   |
     And I log out
     And I log in as "student1"
+    And I am on site homepage
     And I follow "Course 1"
 
     # P1 (any groups) and P2 should show but not P3.