Compare commits
91 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a2fe75a270 | |||
| 6b632fef09 | |||
| bc3e140d8b | |||
| b53f12d8c9 | |||
| f9c700eb9f | |||
| 0d3495e6b2 | |||
| 72eac30148 | |||
| e19f451723 | |||
| db0073291b | |||
| 984e3fc510 | |||
| 698142b1f5 | |||
| 8669b0ebb7 | |||
| 2204ea8afe | |||
| 142e12bee7 | |||
| 2bdebbf6e7 | |||
| f47ec5d0a9 | |||
| 52da2d6eaa | |||
| 78b0f6e204 | |||
| 7030fa5972 | |||
| 2bd53efc1b | |||
| 9ccb3a2af9 | |||
| 3354f46fd6 | |||
| 9fb1e3d300 | |||
| e4b11bf852 | |||
| 28cf3f9119 | |||
| 1a885a1756 | |||
| 753035e090 | |||
| cb98541563 | |||
| 2729301721 | |||
| 54a2d7df22 | |||
| 59f97a627f | |||
| 362c67f84d | |||
| cbe5ec5a51 | |||
| 201eff4d98 | |||
| 22e52ebb55 | |||
| 493d3c218e | |||
| 97ff875c83 | |||
| 8a5601722d | |||
| 68aa19ba73 | |||
| c8d12c3217 | |||
| f9d08701fb | |||
| 324e1fbb78 | |||
| b58a4e8da4 | |||
| e7c0ddb942 | |||
| e9d63ac29c | |||
| fce440eeed | |||
| 5fae2fc7a1 | |||
| 913eb31830 | |||
| 68fbcaf303 | |||
| 20403e0e43 | |||
| 2740e06920 | |||
| a84b51046a | |||
| a19092e71c | |||
| b41a748a98 | |||
| cd96cb300e | |||
| e3c031023f | |||
| c5b4da7257 | |||
| 7edc33a8ce | |||
| 61e9318339 | |||
| f254b2b88f | |||
| 264fe69743 | |||
| 80e2f8473e | |||
| b9b5f4b489 | |||
| dc871f251e | |||
| f972485484 | |||
| 1f9488ccb5 | |||
| 1d8512bc0e | |||
| b751583087 | |||
| 94b897a176 | |||
| 4c6b771c2f | |||
| b8122e1de3 | |||
| a9eae7edf4 | |||
| a7a9150b62 | |||
| c283ed04e0 | |||
| f65e706662 | |||
| 49e1731fbe | |||
| cd320b32b5 | |||
| 8dea153c6b | |||
| ae9fea0b47 | |||
| dc9258574d | |||
| 5b94aaed06 | |||
| a099c8d921 | |||
| 36a3c41b8b | |||
| d7208f8dd0 | |||
| df9c7f755d | |||
| a76583296b | |||
| b56affcfe6 | |||
| 4799f8b7c4 | |||
| 62758b8224 | |||
| cf6aeae427 | |||
| 8ea5b30a5d |
+1
-1
@@ -10,7 +10,7 @@ language: php
|
||||
|
||||
os: linux
|
||||
|
||||
dist: xenial
|
||||
dist: bionic
|
||||
|
||||
services:
|
||||
- mysql
|
||||
|
||||
@@ -3531,4 +3531,189 @@
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.0" requires="3.6">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.2.29" />
|
||||
<VENDOR name="mysql" version="5.7" />
|
||||
<VENDOR name="postgres" version="10" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="oracle" version="11.2" />
|
||||
</DATABASE>
|
||||
<PHP version="7.3.0" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="mbstringrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="opensslrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlrpc" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="xmlrpcrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="intlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
<PHP_EXTENSION name="fileinfo" level="required"/>
|
||||
<PHP_EXTENSION name="sodium" level="optional"/>
|
||||
<PHP_EXTENSION name="exif" level="optional"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<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_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="libcurlwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfileformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfilepertable" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddblargeprefix" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="ishttpswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="incompleteunicodesupport" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="sixtyfourbitswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
@@ -48,7 +48,7 @@ Feature: Verify that all form fields values can be get and set
|
||||
And the "Unenrol users" select box should not contain "Baker"
|
||||
And the "Unenrol users" select box should not contain "President, Baker"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "Test this one"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I press "Create page"
|
||||
# Text (textarea & editor) & Select (multi-select) - Checking "I set the following fields to these values".
|
||||
When I set the following fields to these values:
|
||||
@@ -61,8 +61,7 @@ Feature: Verify that all form fields values can be get and set
|
||||
# Checkbox - Checking "I set the field" and "The field matches value" ticked.
|
||||
And I set the field "Force format" to "1"
|
||||
And I press "Save and return to course"
|
||||
And I should see "Test this one"
|
||||
And I follow "Test this one"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And the field "Force format" matches value "1"
|
||||
@@ -70,8 +69,7 @@ Feature: Verify that all form fields values can be get and set
|
||||
# Checkbox - Checking "I set the field" and "The field matches value" unticked.
|
||||
And I set the field "Force format" to ""
|
||||
And I press "Save and return to course"
|
||||
And I should see "Test this one"
|
||||
And I follow "Test this one"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And the field "Force format" matches value ""
|
||||
@@ -80,8 +78,7 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I set the following fields to these values:
|
||||
| Force format | 1 |
|
||||
And I press "Save and return to course"
|
||||
And I should see "Test this one"
|
||||
And I follow "Test this one"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And the following fields match these values:
|
||||
@@ -92,8 +89,7 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I set the following fields to these values:
|
||||
| Force format | |
|
||||
And I press "Save and return to course"
|
||||
And I should see "Test this one"
|
||||
And I follow "Test this one"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And the following fields match these values:
|
||||
@@ -115,20 +111,21 @@ Feature: Verify that all form fields values can be get and set
|
||||
| Wiki name | Test this one baby |
|
||||
| Default format | HTML |
|
||||
And I press "Cancel"
|
||||
And I am on "Course 1" course homepage
|
||||
# Radio - Checking "I set the field" and "the field matches value".
|
||||
And I add a "Choice" to section "1" and I fill the form with:
|
||||
| Choice name | Test choice name |
|
||||
| Description | Test choice description |
|
||||
| Allow choice to be updated | Yes |
|
||||
| Option 1 | one |
|
||||
| Option 2 | two |
|
||||
| Option 3 | three |
|
||||
And I follow "Test choice name"
|
||||
And I set the field "one" to "1"
|
||||
And the following "activity" exists:
|
||||
| activity | choice |
|
||||
| course | C1 |
|
||||
| idnumber | choice1 |
|
||||
| intro | Test choice description |
|
||||
| name | Test choice name |
|
||||
| option | Option 1, Option 2, Option 3 |
|
||||
| section | 1 |
|
||||
| allowupdate | 1 |
|
||||
And I am on the "Test choice name" "choice activity" page
|
||||
And I set the field "Option 1" to "1"
|
||||
And I press "Save my choice"
|
||||
And the field "one" matches value "1"
|
||||
And the field "two" matches value ""
|
||||
And the field "Option 1" matches value "1"
|
||||
And the field "Option 2" matches value ""
|
||||
# Check if field xpath set/match works.
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
@@ -174,31 +171,23 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I press "Cancel"
|
||||
# Advanced checkbox requires real browser to allow uncheck to work. MDL-58681. MDL-55386.
|
||||
# Advanced checkbox - Checking "I set the field" and "The field matches value" ticked.
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test this one"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test choice name" "choice activity editing" page
|
||||
And I set the field "Display description on course page" to "1"
|
||||
And I press "Save and return to course"
|
||||
And I should see "Test this one"
|
||||
And I follow "Test this one"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test choice name" "choice activity editing" page
|
||||
And the field "Display description on course page" matches value "1"
|
||||
And the field "Display description on course page" does not match value ""
|
||||
# Advanced checkbox - Checking "I set the field" and "The field matches value" unticked.
|
||||
And I set the field "Display description on course page" to ""
|
||||
And I press "Save and return to course"
|
||||
And I should see "Test this one"
|
||||
And I follow "Test this one"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test choice name" "choice activity editing" page
|
||||
And the field "Display description on course page" matches value ""
|
||||
And the field "Display description on course page" does not match value "1"
|
||||
# Advanced checkbox - Checking "I set the following fields to these values:" and "The following fields match these values" ticked.
|
||||
And I set the following fields to these values:
|
||||
| Display description on course page | 1 |
|
||||
And I press "Save and return to course"
|
||||
And I should see "Test this one"
|
||||
And I follow "Test this one"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test choice name" "choice activity editing" page
|
||||
And the following fields match these values:
|
||||
| Display description on course page | 1 |
|
||||
And the following fields do not match these values:
|
||||
@@ -207,9 +196,7 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I set the following fields to these values:
|
||||
| Display description on course page | |
|
||||
And I press "Save and return to course"
|
||||
And I should see "Test this one"
|
||||
And I follow "Test this one"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test choice name" "choice activity editing" page
|
||||
And the following fields match these values:
|
||||
| Display description on course page | |
|
||||
And the following fields do not match these values:
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
@tool @tool_behat
|
||||
Feature: Use core page resolvers for the I am on the page steps
|
||||
In order to write tests correctly
|
||||
As a developer
|
||||
I need to have steps which take me straight to a page
|
||||
|
||||
Scenario Outline: When I am on an instance
|
||||
Given the following "categories" exist:
|
||||
| name | category | idnumber |
|
||||
| Cat 1 | 0 | CAT1 |
|
||||
And the following "course" exists:
|
||||
| fullname | Economics 101 |
|
||||
| shortname | ECON101 |
|
||||
| idnumber | 2021-econ101 |
|
||||
And the following "activity" exists:
|
||||
| course | ECON101 |
|
||||
| activity | forum |
|
||||
| name | Fundamentals of Economics |
|
||||
| idnumber | fundamentalsofeconomics |
|
||||
And I log in as "admin"
|
||||
When I am on the <identifier> <type> page
|
||||
Then I should see "<shouldsee>"
|
||||
|
||||
Examples:
|
||||
| description | identifier | type | shouldsee |
|
||||
| Course Category idnumber | CAT1 | category | Add a new course |
|
||||
| Course Category name | "Cat 1" | Category | Add a new course |
|
||||
| Course Full name | "Economics 101" | course | Fundamentals of Economics |
|
||||
| Course Short name | ECON101 | COURSE | Fundamentals of Economics |
|
||||
| Course idnumber | "2021-econ101" | Course | Fundamentals of Economics |
|
||||
| Forum idnumber | fundamentalsofeconomics | Activity | Add a new discussion |
|
||||
| Generic activity editing | fundamentalsofeconomics | "Activity editing" | Updating: Forum |
|
||||
| Forum name | "Fundamentals of Economics" | "Forum activity" | Add a new discussion |
|
||||
| Forum name editing | "Fundamentals of Economics" | "Forum activity editing" | Updating: Forum |
|
||||
| Forum name permissions | "Fundamentals of Economics" | "Forum activity permissions" | Permissions in Forum: Fun |
|
||||
| Forum name roles | "Fundamentals of Economics" | "Forum activity roles" | Assign roles in Forum: Fun |
|
||||
|
||||
Scenario Outline: When I am on an instance logged in as
|
||||
Given the following "categories" exist:
|
||||
| name | category | idnumber |
|
||||
| Cat 1 | 0 | CAT1 |
|
||||
And the following "course" exists:
|
||||
| fullname | Economics 101 |
|
||||
| shortname | ECON101 |
|
||||
| idnumber | 2021-econ101 |
|
||||
And the following "activity" exists:
|
||||
| course | ECON101 |
|
||||
| activity | forum |
|
||||
| name | Fundamentals of Economics |
|
||||
| idnumber | fundamentalsofeconomics |
|
||||
When I am on the <identifier> <type> page logged in as admin
|
||||
Then I should see "<shouldsee>"
|
||||
|
||||
Examples:
|
||||
| description | identifier | type | shouldsee |
|
||||
| Course Category idnumber | CAT1 | category | Add a new course |
|
||||
| Course Category name | "Cat 1" | Category | Add a new course |
|
||||
| Course Full name | "Economics 101" | course | Fundamentals of Economics |
|
||||
| Course Short name | ECON101 | COURSE | Fundamentals of Economics |
|
||||
| Course idnumber | "2021-econ101" | Course | Fundamentals of Economics |
|
||||
| Forum idnumber | fundamentalsofeconomics | Activity | Add a new discussion |
|
||||
| Generic activity editing | fundamentalsofeconomics | "Activity editing" | Updating: Forum |
|
||||
| Forum name | "Fundamentals of Economics" | "Forum activity" | Add a new discussion |
|
||||
| Forum name editing | "Fundamentals of Economics" | "Forum activity editing" | Updating: Forum |
|
||||
| Forum name permissions | "Fundamentals of Economics" | "Forum activity permissions" | Permissions in Forum: Fun |
|
||||
| Forum name roles | "Fundamentals of Economics" | "Forum activity roles" | Assign roles in Forum: Fun |
|
||||
|
||||
Scenario Outline: When I am on a named page
|
||||
Given I log in as "admin"
|
||||
When I am on the <identifier> page
|
||||
Then I should see "<shouldsee>"
|
||||
|
||||
Examples:
|
||||
| description | identifier | shouldsee |
|
||||
| Admin page | "Admin notifications" | Check for available updates |
|
||||
| Home page | Homepage | Recently accessed courses |
|
||||
|
||||
Scenario Outline: When I am on a named page logged in as
|
||||
When I am on the <identifier> page logged in as admin
|
||||
Then I should see "<shouldsee>"
|
||||
|
||||
Examples:
|
||||
| description | identifier | shouldsee |
|
||||
| Admin page | "Admin notifications" | Check for available updates |
|
||||
| Home page | Homepage | Recently accessed courses |
|
||||
@@ -24,9 +24,7 @@ Feature: See the competencies for an activity on the course competencies page.
|
||||
| activity | name | intro | course | idnumber | completion | completionview |
|
||||
| page | PageName1 | PageDesc1 | C1 | PAGE1 | 1 | 1 |
|
||||
| page | PageName2 | PageDesc2 | C1 | PAGE2 | 1 | 1 |
|
||||
And I log in as "admin"
|
||||
And I am on site homepage
|
||||
And I follow "Course 1"
|
||||
And I am on the "Course 1" course page logged in as admin
|
||||
And I follow "Competencies"
|
||||
And I press "Add competencies to course"
|
||||
And "Competency picker" "dialogue" should be visible
|
||||
@@ -36,9 +34,7 @@ Feature: See the competencies for an activity on the course competencies page.
|
||||
And "Competency picker" "dialogue" should be visible
|
||||
And I select "Test-Comp2" of the competency tree
|
||||
And I click on "Add" "button" in the "Competency picker" "dialogue"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the PageName1 "page activity editing" page
|
||||
And I follow "Expand all"
|
||||
And I set the field "Course competencies" to "Test-Comp1"
|
||||
And I press "Save and return to course"
|
||||
@@ -46,10 +42,8 @@ Feature: See the competencies for an activity on the course competencies page.
|
||||
|
||||
@javascript
|
||||
Scenario: Go to the competency course competencies page.
|
||||
When I log in as "student1"
|
||||
And I am on site homepage
|
||||
And I follow "Course 1"
|
||||
And I follow "Competencies"
|
||||
Given I am on the "Course 1" course page logged in as student1
|
||||
When I follow "Competencies"
|
||||
Then I should see "Test-Comp1"
|
||||
And I should see "Test-Comp2"
|
||||
And I set the field "Filter competencies by resource or activity" to "PageName1"
|
||||
@@ -64,12 +58,5 @@ Feature: See the competencies for an activity on the course competencies page.
|
||||
|
||||
@javascript
|
||||
Scenario: None course competencies page.
|
||||
When I log in as "student1"
|
||||
And I am on site homepage
|
||||
And I follow "Course 1"
|
||||
And I follow "PageName1"
|
||||
Then I should see "Test page content"
|
||||
And I am on site homepage
|
||||
And I follow "Course 1"
|
||||
And I follow "PageName1"
|
||||
When I am on the PageName1 "page activity" page logged in as student1
|
||||
Then I should see "Test page content"
|
||||
|
||||
@@ -42,9 +42,7 @@ Feature: Backup user data
|
||||
| Feedback for the response 'True'. | So you think it is true |
|
||||
| Feedback for the response 'False'. | So you think it is false |
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Quiz 1"
|
||||
When I am on the "Quiz 1" "quiz activity" page logged in as student1
|
||||
And I press "Attempt quiz now"
|
||||
And I click on "True" "radio" in the "First question" "question"
|
||||
And I click on "False" "radio" in the "Second question" "question"
|
||||
|
||||
@@ -68,7 +68,9 @@ if ($dataformat) {
|
||||
$downloadusers = new ArrayObject($SESSION->bulk_users);
|
||||
$iterator = $downloadusers->getIterator();
|
||||
|
||||
\core\dataformat::download_data($filename, $dataformat, $fields, $iterator, function($userid) use ($extrafields, $fields) {
|
||||
\core\dataformat::download_data($filename, $dataformat, $fields, $iterator, function($userid, $supportshtml)
|
||||
use ($extrafields, $fields) {
|
||||
|
||||
global $DB;
|
||||
|
||||
if (!$user = $DB->get_record('user', array('id' => $userid))) {
|
||||
@@ -86,6 +88,8 @@ if ($dataformat) {
|
||||
// We only take the text.
|
||||
if (is_array($user->$field)) {
|
||||
$userprofiledata[$field] = reset($user->$field);
|
||||
} else if ($supportshtml) {
|
||||
$userprofiledata[$field] = s($user->$field);
|
||||
} else {
|
||||
$userprofiledata[$field] = $user->$field;
|
||||
}
|
||||
|
||||
@@ -113,11 +113,22 @@ class helper {
|
||||
*/
|
||||
private static function unserializesession($serializedstring) {
|
||||
$variables = array();
|
||||
$a = preg_split("/(\w+)\|/", $serializedstring, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
|
||||
$counta = count($a);
|
||||
for ($i = 0; $i < $counta; $i = $i + 2) {
|
||||
$variables[$a[$i]] = unserialize($a[$i + 1]);
|
||||
|
||||
$index = 0;
|
||||
|
||||
// Find next delimiter after current index. It's key being the characters between those points.
|
||||
while ($delimiterpos = strpos($serializedstring, '|', $index)) {
|
||||
$key = substr($serializedstring, $index, $delimiterpos - $index);
|
||||
|
||||
// Start unserializing immediately after the delimiter. PHP will read as much valid data as possible.
|
||||
$value = unserialize(substr($serializedstring, $delimiterpos + 1),
|
||||
['allowed_classes' => ['stdClass']]);
|
||||
$variables[$key] = $value;
|
||||
|
||||
// Advance index beyond the length of the previously captured serialized value.
|
||||
$index = $delimiterpos + 1 + strlen(serialize($value));
|
||||
}
|
||||
|
||||
return $variables;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,10 +48,10 @@ Feature: Confirm that conditions on completion no longer cause a bug
|
||||
And I click on "Activity completion" "button" in the "Add restriction..." "dialogue"
|
||||
And I set the field with xpath "//div[contains(concat(' ', normalize-space(@class), ' '), ' availability-item ')][preceding-sibling::div]//select[@name='cm']" to "Page2"
|
||||
And I press "Save and return to course"
|
||||
And I should see "Not available unless:" in the ".activity.glossary" "css_element"
|
||||
Then I should see "Not available unless:" in the ".activity.glossary" "css_element"
|
||||
And I should see "The activity Page1 is marked complete" in the ".activity.glossary" "css_element"
|
||||
And I should see "The activity Page2 is marked complete" in the ".activity.glossary" "css_element"
|
||||
And I follow "TestGlossary"
|
||||
|
||||
# Behat will automatically check there is no error on this page.
|
||||
Then I should see "TestGlossary"
|
||||
And I am on the TestGlossary "glossary activity" page
|
||||
And I should see "TestGlossary"
|
||||
|
||||
@@ -86,13 +86,12 @@ Feature: availability_grade
|
||||
And I set the field "Minimum grade percentage (inclusive)" to "10"
|
||||
And I press "Save and return to course"
|
||||
|
||||
And I log out
|
||||
|
||||
# Log in as student without a grade yet.
|
||||
When I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
When I am on the "A1" "assign activity" page logged in as student1
|
||||
|
||||
# Do the assignment.
|
||||
And I follow "A1"
|
||||
And I click on "Add submission" "button"
|
||||
And I set the field "Online text" to "Q"
|
||||
And I click on "Save changes" "button"
|
||||
@@ -103,14 +102,12 @@ Feature: availability_grade
|
||||
And I should not see "P3" in the "region-main" "region"
|
||||
And I should not see "P4" in the "region-main" "region"
|
||||
And I should see "A1" in the "region-main" "region"
|
||||
And I log out
|
||||
|
||||
# Log back in as teacher.
|
||||
When I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
When I am on the "A1" "assign activity" page logged in as teacher1
|
||||
|
||||
# Give the assignment 40%.
|
||||
And I follow "A1"
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
# Pick the grade link in the row that has s@example.com in it.
|
||||
And I click on "Grade" "link" in the "s@example.com" "table_row"
|
||||
@@ -118,11 +115,10 @@ Feature: availability_grade
|
||||
And I click on "Save changes" "button"
|
||||
And I press "OK"
|
||||
And I click on "Edit settings" "link"
|
||||
And I log out
|
||||
|
||||
# Log back in as student.
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
|
||||
# Check pages are visible.
|
||||
Then I should see "P2" in the "region-main" "region"
|
||||
|
||||
@@ -95,8 +95,7 @@ Feature: availability_profile
|
||||
And I click on "Save and return to course" "button"
|
||||
|
||||
# Edit it again and check the setting still works.
|
||||
When I follow "P1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
When I am on the P1 "page activity editing" page
|
||||
And I expand all fieldsets
|
||||
Then the field "User profile field" matches value "Super field"
|
||||
And the field "Value to compare against" matches value "Bananaman"
|
||||
|
||||
@@ -51,18 +51,18 @@ Feature: Award badges based on activity completion
|
||||
And I log out
|
||||
|
||||
Scenario: Student earns a badge using activity completion, but does not get passing grade
|
||||
When I log in as "student1"
|
||||
Given I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And the "Test quiz name" "quiz" activity with "auto" completion should be marked as not complete
|
||||
And I follow "Test quiz name"
|
||||
When I am on the "Test quiz name" "quiz activity" page
|
||||
And I press "Re-attempt quiz"
|
||||
And I set the field "False" to "1"
|
||||
And I press "Finish attempt ..."
|
||||
And I press "Submit all and finish"
|
||||
And I click on "Submit all and finish" "button" in the "Confirmation" "dialogue"
|
||||
And I log out
|
||||
Then I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
And I navigate to "Badges > Manage badges" in current page administration
|
||||
And I follow "Course Badge"
|
||||
And I should see "Recipients (1)"
|
||||
Then I should see "Recipients (1)"
|
||||
|
||||
@@ -64,6 +64,7 @@ Feature: Award badges based on competency completion
|
||||
And I set the following fields to these values:
|
||||
| Rating | C |
|
||||
And I click on "Rate" "button" in the "Rate" "dialogue"
|
||||
And I should see "The competency rating was manually set in the course"
|
||||
And I log out
|
||||
# See if we got the badge
|
||||
Then I log in as "user1"
|
||||
@@ -114,8 +115,8 @@ Feature: Award badges based on competency completion
|
||||
And I press "Rate"
|
||||
And I set the following fields to these values:
|
||||
| Rating | C |
|
||||
And I wait until the page is ready
|
||||
And I click on "Rate" "button" in the "Rate" "dialogue"
|
||||
And I should see "The competency rating was manually set in the course"
|
||||
And I log out
|
||||
# See if we got the badge
|
||||
Then I log in as "user1"
|
||||
@@ -168,8 +169,8 @@ Feature: Award badges based on competency completion
|
||||
And I press "Rate"
|
||||
And I set the following fields to these values:
|
||||
| Rating | C |
|
||||
And I wait until the page is ready
|
||||
And I click on "Rate" "button" in the "Rate" "dialogue"
|
||||
And I should see "The competency rating was manually set in the course"
|
||||
And I log out
|
||||
# We should not get the badge yet.
|
||||
Then I log in as "user1"
|
||||
@@ -184,8 +185,8 @@ Feature: Award badges based on competency completion
|
||||
And I press "Rate"
|
||||
And I set the following fields to these values:
|
||||
| Rating | C |
|
||||
And I wait until the page is ready
|
||||
And I click on "Rate" "button" in the "Rate" "dialogue"
|
||||
And I should see "The competency rating was manually set in the course"
|
||||
And I log out
|
||||
# See if we got the badge now.
|
||||
Then I log in as "user1"
|
||||
|
||||
@@ -147,7 +147,6 @@ Feature: My overview block pagination
|
||||
| student1 | C13 | student |
|
||||
When I log in as "student1"
|
||||
And I click on "[data-control='next']" "css_element" in the "Course overview" "block"
|
||||
And I wait until ".block_myoverview [data-control='next']" "css_element" exists
|
||||
Then the "class" attribute of ".block_myoverview [data-control='next']" "css_element" should contain "disabled"
|
||||
And I log out
|
||||
|
||||
@@ -181,7 +180,6 @@ Feature: My overview block pagination
|
||||
| student1 | C25 | student |
|
||||
When I log in as "student1"
|
||||
And I click on "[data-control='next']" "css_element" in the "Course overview" "block"
|
||||
And I wait until ".block_myoverview [data-control='next']" "css_element" exists
|
||||
Then the "class" attribute of ".block_myoverview [data-control='next']" "css_element" should not contain "disabled"
|
||||
And the "class" attribute of ".block_myoverview [data-control='previous']" "css_element" should not contain "disabled"
|
||||
And I should see "Course 13" in the "Course overview" "block"
|
||||
|
||||
@@ -27,9 +27,7 @@ Feature: Course overview block show users their progress on courses
|
||||
Then I should not see "0%" in the "Course overview" "block"
|
||||
|
||||
Scenario: User complete activity and verify his progress
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "Test choice 1"
|
||||
Given I am on the "Test choice 1" "choice activity" page logged in as teacher1
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Completion tracking | Show activity as complete when conditions are met |
|
||||
@@ -40,8 +38,8 @@ Feature: Course overview block show users their progress on courses
|
||||
And I click on "All (except removed from view)" "button" in the "Course overview" "block"
|
||||
Then I should see "Course 1" in the "Course overview" "block"
|
||||
And I should see "0%" in the "Course overview" "block"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test choice 1"
|
||||
|
||||
And I am on the "Test choice 1" "choice activity" page
|
||||
And I follow "Dashboard" in the user menu
|
||||
And I click on "All (except removed from view)" "button" in the "Course overview" "block"
|
||||
And I should see "100%" in the "Course overview" "block"
|
||||
|
||||
@@ -19,7 +19,7 @@ Feature: The private files block allows users to store files privately in moodle
|
||||
| page | C1 | page1 | Test page name | Test page description |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "Test page name"
|
||||
And I am on the "Test page name" "page activity" page
|
||||
And I add the "Private files" block
|
||||
And I should see "No files available" in the "Private files" "block"
|
||||
When I follow "Manage private files..."
|
||||
|
||||
+8
-12
@@ -16,24 +16,20 @@ Feature: The recently accessed items block allows users to easily access their m
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
| student1 | C2 | student |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I turn editing mode on
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name |
|
||||
| Forum type | Standard forum for general use |
|
||||
| Description | Test forum description |
|
||||
And I log out
|
||||
And the following "activity" exists:
|
||||
| course | C1 |
|
||||
| activity | forum |
|
||||
| idnumber | Test forum name |
|
||||
| name | Test forum name |
|
||||
And I log in as "student1"
|
||||
When I press "Customise this page"
|
||||
And I press "Customise this page"
|
||||
And I add the "Recently accessed items" block
|
||||
|
||||
Scenario: User has not accessed any item
|
||||
Then I should see "No recent items" in the "Recently accessed items" "block"
|
||||
|
||||
Scenario: User has accessed some items
|
||||
Given I am on "Course 1" course homepage
|
||||
When I follow "Test forum name"
|
||||
Given I change window size to "large"
|
||||
When I am on the "Test forum name" "forum activity" page
|
||||
And I follow "Dashboard" in the user menu
|
||||
And I change window size to "large"
|
||||
Then I should see "Test forum name" in the "Recently accessed items" "block"
|
||||
|
||||
+2
-1
@@ -3204,6 +3204,7 @@ function calendar_update_subscription($subscription) {
|
||||
* @return bool true if current user can edit the subscription else false
|
||||
*/
|
||||
function calendar_can_edit_subscription($subscriptionorid) {
|
||||
global $USER;
|
||||
if (is_array($subscriptionorid)) {
|
||||
$subscription = (object)$subscriptionorid;
|
||||
} else if (is_object($subscriptionorid)) {
|
||||
@@ -3224,7 +3225,7 @@ function calendar_can_edit_subscription($subscriptionorid) {
|
||||
calendar_get_allowed_types($allowed, $courseid, null, $category);
|
||||
switch ($subscription->eventtype) {
|
||||
case 'user':
|
||||
return $allowed->user;
|
||||
return ($USER->id == $subscription->userid && $allowed->user);
|
||||
case 'course':
|
||||
if (isset($allowed->courses[$courseid])) {
|
||||
return $allowed->courses[$courseid];
|
||||
|
||||
@@ -36,12 +36,10 @@ Feature: Restrict activity availability through date conditions
|
||||
| x[year] | 2037 |
|
||||
And I press "Save and return to course"
|
||||
And I log out
|
||||
When I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
When I am on the "Course 1" course page logged in as student1
|
||||
Then I should see "Available from 31 December 2037"
|
||||
And "Test assignment 1" "link" should not exist in the "page" "region"
|
||||
And "Test assignment 1" activity should be dimmed
|
||||
And "Test assignment 1" "link" should not exist
|
||||
And I log out
|
||||
|
||||
@javascript
|
||||
Scenario: Show activity hidden to students when available until date is in past
|
||||
@@ -60,6 +58,5 @@ Feature: Restrict activity availability through date conditions
|
||||
And I click on ".availability-item .availability-eye img" "css_element"
|
||||
And I press "Save and return to course"
|
||||
And I log out
|
||||
When I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
Then I should not see "Test assignment 2"
|
||||
When I am on the "Course 1" course page logged in as student1
|
||||
Then I should not see "Test assignment 2" in the "page" "region"
|
||||
|
||||
@@ -17,13 +17,16 @@ Feature: Restrict activity availability through grade conditions
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And I log in as "teacher1"
|
||||
And the following "activity" exists:
|
||||
| course | C1 |
|
||||
| activity | assign |
|
||||
| idnumber | Grade assignment |
|
||||
| name | Grade assignment |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| submissiondrafts | 0 |
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Grade assignment |
|
||||
| Description | Grade this assignment to revoke restriction on restricted assignment |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
# Adding the page like this because id_availableform_enabled needs to be clicked to trigger the action.
|
||||
And I add a "Page" to section "2"
|
||||
And I expand all fieldsets
|
||||
@@ -31,15 +34,15 @@ Feature: Restrict activity availability through grade conditions
|
||||
And I click on "Grade" "button" in the "Add restriction..." "dialogue"
|
||||
And I click on "min" "checkbox"
|
||||
And I set the following fields to these values:
|
||||
| Name | Test page name |
|
||||
| Description | Restricted page, till grades in Grade assignment is at least 20% |
|
||||
| Page content | Test page contents |
|
||||
| id | Grade assignment |
|
||||
| minval | 20 |
|
||||
| Name | Test page name |
|
||||
| Description | Restricted page, till grades in Grade assignment is at least 20% |
|
||||
| Page content | Test page contents |
|
||||
| id | Grade assignment |
|
||||
| minval | 20 |
|
||||
And I press "Save and return to course"
|
||||
And I log out
|
||||
When I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
|
||||
When I am on the "Course 1" course page logged in as student1
|
||||
Then I should see "Not available unless: You achieve a required score in Grade assignment"
|
||||
And "Test page name" activity should be dimmed
|
||||
And "Test page name" "link" should not exist
|
||||
@@ -50,9 +53,8 @@ Feature: Restrict activity availability through grade conditions
|
||||
And I press "Save changes"
|
||||
And I should see "Submitted for grading"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Grade assignment"
|
||||
|
||||
And I am on the "Grade assignment" "assign activity" page logged in as teacher1
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Student First" "table_row"
|
||||
And I set the following fields to these values:
|
||||
@@ -61,7 +63,7 @@ Feature: Restrict activity availability through grade conditions
|
||||
And I press "OK"
|
||||
And I follow "Edit settings"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And "Test page name" activity should be visible
|
||||
And I should not see "Not available unless: You achieve a required score in Grade assignment"
|
||||
|
||||
@@ -76,16 +76,14 @@ Feature: Restrict sections availability through completion or grade conditions
|
||||
And I am on "Course 1" course homepage
|
||||
Then I should see "Not available unless: You achieve a required score in Grade assignment"
|
||||
And "Test page name" activity should be hidden
|
||||
And I follow "Grade assignment"
|
||||
And I am on the "Grade assignment" "assign activity" page
|
||||
And I press "Add submission"
|
||||
And I set the following fields to these values:
|
||||
| Online text | I'm the student submission |
|
||||
And I press "Save changes"
|
||||
And I should see "Submitted for grading"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Grade assignment"
|
||||
And I am on the "Grade assignment" "assign activity" page logged in as teacher1
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Student First" "table_row"
|
||||
And I set the following fields to these values:
|
||||
@@ -94,7 +92,6 @@ Feature: Restrict sections availability through completion or grade conditions
|
||||
And I press "OK"
|
||||
And I follow "Edit settings"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" Course page logged in as student1
|
||||
And "Test page name" activity should be visible
|
||||
And I should not see "Not available unless: You achieve a required score in Grade assignment"
|
||||
|
||||
+24
-6
@@ -4720,21 +4720,39 @@ function course_get_recent_courses(int $userid = null, int $limit = 0, int $offs
|
||||
$basefields = array('id', 'idnumber', 'summary', 'summaryformat', 'startdate', 'enddate', 'category',
|
||||
'shortname', 'fullname', 'timeaccess', 'component', 'visible');
|
||||
|
||||
$sort = trim($sort);
|
||||
if (empty($sort)) {
|
||||
$sort = 'timeaccess DESC';
|
||||
} else {
|
||||
// The SQL string for sorting can define sorting by multiple columns.
|
||||
$rawsorts = explode(',', $sort);
|
||||
$sorts = array();
|
||||
// Validate and trim the sort parameters in the SQL string for sorting.
|
||||
foreach ($rawsorts as $rawsort) {
|
||||
$rawsort = trim($rawsort);
|
||||
$sorts[] = trim($rawsort);
|
||||
$sort = trim($rawsort);
|
||||
$sortparams = explode(' ', $sort);
|
||||
// A valid sort statement can not have more than 2 params (ex. 'summary desc' or 'timeaccess').
|
||||
if (count($sortparams) > 2) {
|
||||
throw new invalid_parameter_exception(
|
||||
'Invalid structure of the sort parameter, allowed structure: fieldname [ASC|DESC].');
|
||||
}
|
||||
$sortfield = trim($sortparams[0]);
|
||||
// Validate the value which defines the field to sort by.
|
||||
if (!in_array($sortfield, $basefields)) {
|
||||
throw new invalid_parameter_exception('Invalid field in the sort parameter, allowed fields: ' .
|
||||
implode(', ', $basefields) . '.');
|
||||
}
|
||||
$sortdirection = isset($sortparams[1]) ? trim($sortparams[1]) : '';
|
||||
// Validate the value which defines the sort direction (if present).
|
||||
$allowedsortdirections = ['asc', 'desc'];
|
||||
if (!empty($sortdirection) && !in_array(strtolower($sortdirection), $allowedsortdirections)) {
|
||||
throw new invalid_parameter_exception('Invalid sort direction in the sort parameter, allowed values: ' .
|
||||
implode(', ', $allowedsortdirections) . '.');
|
||||
}
|
||||
$sorts[] = $sort;
|
||||
}
|
||||
$sort = implode(',', $sorts);
|
||||
}
|
||||
|
||||
$orderby = "ORDER BY $sort";
|
||||
|
||||
$ctxfields = context_helper::get_preload_record_columns_sql('ctx');
|
||||
|
||||
$coursefields = 'c.' .join(',', $basefields);
|
||||
@@ -4767,7 +4785,7 @@ function course_get_recent_courses(int $userid = null, int $limit = 0, int $offs
|
||||
AND ue.timestart < :now1
|
||||
AND (ue.timeend = 0 OR ue.timeend > :now2)
|
||||
))
|
||||
$orderby";
|
||||
ORDER BY $sort";
|
||||
|
||||
$now = round(time(), -2); // Improves db caching.
|
||||
$params = ['userid' => $userid, 'contextlevel' => CONTEXT_COURSE, 'visible' => 1, 'status' => ENROL_USER_ACTIVE,
|
||||
|
||||
@@ -8,32 +8,26 @@ Feature: Edit completion settings of an activity
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | enablecompletion |
|
||||
| Course 1 | C1 | 1 |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Page" to section "1" and I fill the form with:
|
||||
| Name | TestPage |
|
||||
| Description | x |
|
||||
| Page content | x |
|
||||
| Completion tracking | 2 |
|
||||
| Require view | 1 |
|
||||
And I am on "Course 1" course homepage
|
||||
And the following "activities" exist:
|
||||
| activity | course | idnumber | intro | name | completion | completionview |
|
||||
| page | C1 | p1 | x | TestPage | 2 | 1 |
|
||||
|
||||
Scenario: Completion is not locked when the activity has not yet been viewed
|
||||
Given I click on "Edit settings" "link" in the "TestPage" activity
|
||||
Given I am on the TestPage "Page Activity editing" page logged in as admin
|
||||
When I expand all fieldsets
|
||||
Then I should see "Completion tracking"
|
||||
And I should not see "Completion options locked"
|
||||
|
||||
Scenario: Completion is locked after the activity has been viewed
|
||||
Given I follow "TestPage"
|
||||
When I follow "Edit settings"
|
||||
Given I am on the TestPage "Page Activity" page logged in as admin
|
||||
When I am on the TestPage "Page Activity editing" page
|
||||
And I expand all fieldsets
|
||||
Then I should see "Completion options locked"
|
||||
|
||||
@javascript
|
||||
Scenario: Pressing the unlock button allows the user to edit completion settings
|
||||
Given I follow "TestPage"
|
||||
When I navigate to "Edit settings" in current page administration
|
||||
Given I am on the TestPage "Page Activity" page logged in as admin
|
||||
When I am on the TestPage "Page Activity editing" page
|
||||
And I expand all fieldsets
|
||||
And I press "Unlock completion options"
|
||||
Then I should see "Completion options unlocked"
|
||||
@@ -45,8 +39,8 @@ Feature: Edit completion settings of an activity
|
||||
|
||||
@javascript
|
||||
Scenario: Even when completion is locked, the user can still set the date
|
||||
Given I follow "TestPage"
|
||||
When I navigate to "Edit settings" in current page administration
|
||||
Given I am on the TestPage "Page Activity" page logged in as admin
|
||||
And I am on the TestPage "Page Activity editing" page
|
||||
And I expand all fieldsets
|
||||
When I click on "id_completionexpected_enabled" "checkbox"
|
||||
And I set the field "id_completionexpected_year" to "2013"
|
||||
|
||||
@@ -45,9 +45,7 @@ Feature: Activity navigation involving activities with access restrictions
|
||||
|
||||
@javascript
|
||||
Scenario: Activity navigation involving activities with access restrictions
|
||||
Given I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
When I follow "Page 1"
|
||||
Given I am on the "Page 1" "page activity" page logged in as student1
|
||||
Then I should see "Page 2" in the "#next-activity-link" "css_element"
|
||||
# Activity that has access restriction should not show up in the dropdown.
|
||||
And the "Jump to..." select box should not contain "Page 3"
|
||||
@@ -56,7 +54,7 @@ Feature: Activity navigation involving activities with access restrictions
|
||||
And I should see "Page 2" in the "#prev-activity-link" "css_element"
|
||||
And the "Jump to..." select box should not contain "Page 3"
|
||||
# Navigate to Page 2.
|
||||
And I follow "Page 2"
|
||||
And I click on "Page 2" "link" in the "page-content" "region"
|
||||
# Since Page 2 has now been viewed and deemed completed, Page 3 can now be accessed.
|
||||
And I should see "Page 3" in the "#next-activity-link" "css_element"
|
||||
And the "Jump to..." select box should contain "Page 3"
|
||||
|
||||
@@ -1346,44 +1346,6 @@ class behat_course extends behat_base {
|
||||
return $this->getSession()->getPage()->findButton(get_string('turneditingoff')) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the category with the given idnumber.
|
||||
*
|
||||
* Please note that this function requires the category to exist. If it does not exist an ExpectationException is thrown.
|
||||
*
|
||||
* @param string $idnumber
|
||||
* @return string
|
||||
* @throws ExpectationException
|
||||
*/
|
||||
protected function get_category_id($idnumber) {
|
||||
global $DB;
|
||||
try {
|
||||
return $DB->get_field('course_categories', 'id', array('idnumber' => $idnumber), MUST_EXIST);
|
||||
} catch (dml_missing_record_exception $ex) {
|
||||
throw new ExpectationException(sprintf("There is no category in the database with the idnumber '%s'", $idnumber),
|
||||
$this->getSession());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the course with the given idnumber.
|
||||
*
|
||||
* Please note that this function requires the category to exist. If it does not exist an ExpectationException is thrown.
|
||||
*
|
||||
* @param string $idnumber
|
||||
* @return string
|
||||
* @throws ExpectationException
|
||||
*/
|
||||
protected function get_course_id($idnumber) {
|
||||
global $DB;
|
||||
try {
|
||||
return $DB->get_field('course', 'id', array('idnumber' => $idnumber), MUST_EXIST);
|
||||
} catch (dml_missing_record_exception $ex) {
|
||||
throw new ExpectationException(sprintf("There is no course in the database with the idnumber '%s'", $idnumber),
|
||||
$this->getSession());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the category node from within the listing on the management page.
|
||||
*
|
||||
|
||||
@@ -20,15 +20,12 @@ Feature: Managers can create courses
|
||||
When I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add the "Latest announcements" block
|
||||
Then "Latest announcements" "block" should exist
|
||||
And I follow "Announcements"
|
||||
And I am on the Announcements "forum activity" page
|
||||
And "Add a new topic" "link" should exist
|
||||
And "Subscription mode > Forced subscription" "link" should not exist in current page administration
|
||||
And "Subscription mode > Forced subscription" "text" should exist in current page administration
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Announcements"
|
||||
And I am on the Announcements "forum activity" page logged in as student1
|
||||
And "Add a new topic" "link" should not exist
|
||||
And "Forced subscription" "text" should exist in current page administration
|
||||
|
||||
|
||||
@@ -20,8 +20,7 @@ Feature: View subfolders in a course in-line
|
||||
| Name | Test folder |
|
||||
| Display folder contents | On a separate page |
|
||||
| Show subfolders expanded | |
|
||||
And I should see "Test folder"
|
||||
And I follow "Test folder"
|
||||
And I am on the "Test folder" "folder activity" page
|
||||
And I press "Edit"
|
||||
And I press "Create folder"
|
||||
And I set the field "New folder name" to "Test subfolder 1"
|
||||
@@ -32,7 +31,7 @@ Feature: View subfolders in a course in-line
|
||||
Scenario: Add a folder with two subfolders - view on separate page
|
||||
Given I am on "Course 1" course homepage
|
||||
And I should not see "Test subfolder 1"
|
||||
And I follow "Test folder"
|
||||
And I am on the "Test folder" "folder activity" page
|
||||
And I should see "Test subfolder 1"
|
||||
And I press "Edit"
|
||||
And I press "Create folder"
|
||||
@@ -41,13 +40,13 @@ Feature: View subfolders in a course in-line
|
||||
And I press "Save changes"
|
||||
When I am on "Course 1" course homepage
|
||||
Then I should not see "Test subfolder 2"
|
||||
And I follow "Test folder"
|
||||
And I am on the "Test folder" "folder activity" page
|
||||
And I should see "Test subfolder 2"
|
||||
Given I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test folder" "folder activity editing" page
|
||||
And I set the field "Show subfolders expanded" to "1"
|
||||
When I am on "Course 1" course homepage
|
||||
Then I should not see "Test subfolder 2"
|
||||
And I follow "Test folder"
|
||||
And I am on the "Test folder" "folder activity" page
|
||||
And I should see "Test subfolder 2"
|
||||
|
||||
@javascript
|
||||
@@ -63,8 +62,7 @@ Feature: View subfolders in a course in-line
|
||||
And I press "Save and return to course"
|
||||
Then I should see "Test subfolder 1"
|
||||
And I should not see "Test sub subfolder"
|
||||
Given I open "Test folder" actions menu
|
||||
When I click on "Edit settings" "link" in the "Test folder" activity
|
||||
And I am on the "Test folder" "folder activity editing" page
|
||||
And I set the field "Show subfolders expanded" to "1"
|
||||
And I press "Save and return to course"
|
||||
Then I should see "Test subfolder 1"
|
||||
|
||||
@@ -4550,7 +4550,7 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
'totalcourses' => 0,
|
||||
'limit' => 0,
|
||||
'offset' => 0,
|
||||
'expecteddbqueries' => 1,
|
||||
'expecteddbqueries' => 4,
|
||||
'expectedresult' => $buildexpectedresult(0, 0)
|
||||
],
|
||||
'less than query limit' => [
|
||||
@@ -4558,7 +4558,7 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
'totalcourses' => 2,
|
||||
'limit' => 0,
|
||||
'offset' => 0,
|
||||
'expecteddbqueries' => 1,
|
||||
'expecteddbqueries' => 2,
|
||||
'expectedresult' => $buildexpectedresult(2, 0)
|
||||
],
|
||||
'more than query limit' => [
|
||||
@@ -4566,7 +4566,7 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
'totalcourses' => 7,
|
||||
'limit' => 0,
|
||||
'offset' => 0,
|
||||
'expecteddbqueries' => 3,
|
||||
'expecteddbqueries' => 4,
|
||||
'expectedresult' => $buildexpectedresult(7, 0)
|
||||
],
|
||||
'limit less than query limit' => [
|
||||
@@ -4574,7 +4574,7 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
'totalcourses' => 7,
|
||||
'limit' => 2,
|
||||
'offset' => 0,
|
||||
'expecteddbqueries' => 1,
|
||||
'expecteddbqueries' => 2,
|
||||
'expectedresult' => $buildexpectedresult(2, 0)
|
||||
],
|
||||
'limit less than query limit with offset' => [
|
||||
@@ -4582,7 +4582,7 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
'totalcourses' => 7,
|
||||
'limit' => 2,
|
||||
'offset' => 2,
|
||||
'expecteddbqueries' => 1,
|
||||
'expecteddbqueries' => 2,
|
||||
'expectedresult' => $buildexpectedresult(2, 2)
|
||||
],
|
||||
'limit less than total' => [
|
||||
@@ -4590,7 +4590,7 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
'totalcourses' => 9,
|
||||
'limit' => 6,
|
||||
'offset' => 0,
|
||||
'expecteddbqueries' => 2,
|
||||
'expecteddbqueries' => 3,
|
||||
'expectedresult' => $buildexpectedresult(6, 0)
|
||||
],
|
||||
'less results than limit' => [
|
||||
@@ -4598,7 +4598,7 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
'totalcourses' => 9,
|
||||
'limit' => 20,
|
||||
'offset' => 0,
|
||||
'expecteddbqueries' => 3,
|
||||
'expecteddbqueries' => 4,
|
||||
'expectedresult' => $buildexpectedresult(9, 0)
|
||||
],
|
||||
'less results than limit exact divisible' => [
|
||||
@@ -4606,7 +4606,7 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
'totalcourses' => 9,
|
||||
'limit' => 20,
|
||||
'offset' => 0,
|
||||
'expecteddbqueries' => 4,
|
||||
'expecteddbqueries' => 5,
|
||||
'expectedresult' => $buildexpectedresult(9, 0)
|
||||
],
|
||||
'less results than limit with offset' => [
|
||||
@@ -4614,7 +4614,7 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
'totalcourses' => 9,
|
||||
'limit' => 10,
|
||||
'offset' => 5,
|
||||
'expecteddbqueries' => 2,
|
||||
'expecteddbqueries' => 3,
|
||||
'expectedresult' => $buildexpectedresult(4, 5)
|
||||
],
|
||||
];
|
||||
@@ -5442,7 +5442,16 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
// Every course accessed, order by shortname DESC. The last create course ($course[2]) should have the greater shortname.
|
||||
$result = course_get_recent_courses($student->id, 0, 0, 'shortname DESC');
|
||||
$this->assertCount(3, $result);
|
||||
$this->assertEquals($courses[2]->id, array_shift($result)->id);
|
||||
$this->assertEquals($courses[2]->id, array_values($result)[0]->id);
|
||||
$this->assertEquals($courses[1]->id, array_values($result)[1]->id);
|
||||
$this->assertEquals($courses[0]->id, array_values($result)[2]->id);
|
||||
|
||||
// Every course accessed, order by shortname ASC.
|
||||
$result = course_get_recent_courses($student->id, 0, 0, 'shortname ASC');
|
||||
$this->assertCount(3, $result);
|
||||
$this->assertEquals($courses[0]->id, array_values($result)[0]->id);
|
||||
$this->assertEquals($courses[1]->id, array_values($result)[1]->id);
|
||||
$this->assertEquals($courses[2]->id, array_values($result)[2]->id);
|
||||
|
||||
$guestcourse = $generator->create_course(
|
||||
(object)array('shortname' => 'guestcourse',
|
||||
@@ -5464,6 +5473,56 @@ class core_course_courselib_testcase extends advanced_testcase {
|
||||
$this->assertArrayNotHasKey($courses[0]->id, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the validation of the sort value in course_get_recent_courses().
|
||||
*
|
||||
* @dataProvider course_get_recent_courses_sort_validation_provider
|
||||
* @param string $sort The sort value
|
||||
* @param string $expectedexceptionmsg The expected exception message
|
||||
*/
|
||||
public function test_course_get_recent_courses_sort_validation(string $sort, string $expectedexceptionmsg) {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
|
||||
if (!empty($expectedexceptionmsg)) {
|
||||
$this->expectException('invalid_parameter_exception');
|
||||
$this->expectExceptionMessage($expectedexceptionmsg);
|
||||
}
|
||||
course_get_recent_courses($user->id, 0, 0, $sort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_course_get_recent_courses_sort_validation().
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function course_get_recent_courses_sort_validation_provider() {
|
||||
return [
|
||||
'Invalid sort format (SQL injection attempt)' =>
|
||||
[
|
||||
'shortname DESC LIMIT 1--',
|
||||
'Invalid structure of the sort parameter, allowed structure: fieldname [ASC|DESC].',
|
||||
],
|
||||
'Sort uses \'sort by\' field that does not exist' =>
|
||||
[
|
||||
'shortname DESC, xyz ASC',
|
||||
'Invalid field in the sort parameter, allowed fields: id, idnumber, summary, summaryformat, ' .
|
||||
'startdate, enddate, category, shortname, fullname, timeaccess, component, visible.',
|
||||
],
|
||||
'Sort uses invalid value for the sorting direction' =>
|
||||
[
|
||||
'shortname xyz, lastaccess',
|
||||
'Invalid sort direction in the sort parameter, allowed values: asc, desc.',
|
||||
],
|
||||
'Valid sort format' =>
|
||||
[
|
||||
'shortname asc, timeaccess',
|
||||
''
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the course_get_recent_courses function.
|
||||
*/
|
||||
|
||||
@@ -2765,7 +2765,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
/**
|
||||
* Test cases for the get_enrolled_courses_by_timeline_classification test.
|
||||
*/
|
||||
public function get_get_enrolled_courses_by_timeline_classification_test_cases() {
|
||||
public function get_get_enrolled_courses_by_timeline_classification_test_cases():array {
|
||||
$now = time();
|
||||
$day = 86400;
|
||||
|
||||
@@ -2864,6 +2864,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
'classification' => 'future',
|
||||
'limit' => 2,
|
||||
'offset' => 0,
|
||||
'sort' => 'shortname ASC',
|
||||
'expectedcourses' => [],
|
||||
'expectednextoffset' => 0
|
||||
],
|
||||
@@ -2873,6 +2874,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
'classification' => 'future',
|
||||
'limit' => 0,
|
||||
'offset' => 0,
|
||||
'sort' => 'shortname ASC',
|
||||
'expectedcourses' => ['afuture', 'bfuture', 'cfuture', 'dfuture', 'efuture'],
|
||||
'expectednextoffset' => 15
|
||||
],
|
||||
@@ -2881,6 +2883,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
'classification' => 'future',
|
||||
'limit' => 2,
|
||||
'offset' => 0,
|
||||
'sort' => 'shortname ASC',
|
||||
'expectedcourses' => ['afuture', 'bfuture'],
|
||||
'expectednextoffset' => 4
|
||||
],
|
||||
@@ -2889,6 +2892,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
'classification' => 'future',
|
||||
'limit' => 2,
|
||||
'offset' => 2,
|
||||
'sort' => 'shortname ASC',
|
||||
'expectedcourses' => ['bfuture', 'cfuture'],
|
||||
'expectednextoffset' => 7
|
||||
],
|
||||
@@ -2897,6 +2901,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
'classification' => 'future',
|
||||
'limit' => 5,
|
||||
'offset' => 0,
|
||||
'sort' => 'shortname ASC',
|
||||
'expectedcourses' => ['afuture', 'bfuture', 'cfuture', 'dfuture', 'efuture'],
|
||||
'expectednextoffset' => 13
|
||||
],
|
||||
@@ -2905,6 +2910,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
'classification' => 'future',
|
||||
'limit' => 10,
|
||||
'offset' => 0,
|
||||
'sort' => 'shortname ASC',
|
||||
'expectedcourses' => ['afuture', 'bfuture', 'cfuture', 'dfuture', 'efuture'],
|
||||
'expectednextoffset' => 15
|
||||
],
|
||||
@@ -2913,6 +2919,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
'classification' => 'future',
|
||||
'limit' => 10,
|
||||
'offset' => 5,
|
||||
'sort' => 'shortname ASC',
|
||||
'expectedcourses' => ['cfuture', 'dfuture', 'efuture'],
|
||||
'expectednextoffset' => 15
|
||||
],
|
||||
@@ -2921,6 +2928,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
'classification' => 'all',
|
||||
'limit' => 0,
|
||||
'offset' => 0,
|
||||
'sort' => 'shortname ASC',
|
||||
'expectedcourses' => [
|
||||
'afuture',
|
||||
'ainprogress',
|
||||
@@ -2945,6 +2953,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 0,
|
||||
'sort' => 'shortname ASC',
|
||||
'expectedcourses' => [
|
||||
'afuture',
|
||||
'ainprogress',
|
||||
@@ -2959,6 +2968,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 5,
|
||||
'sort' => 'shortname ASC',
|
||||
'expectedcourses' => [
|
||||
'bpast',
|
||||
'cfuture',
|
||||
@@ -2973,9 +2983,161 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 50,
|
||||
'sort' => 'shortname ASC',
|
||||
'expectedcourses' => [],
|
||||
'expectednextoffset' => 50
|
||||
],
|
||||
'all limit and offset with sort ul.timeaccess desc' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'inprogress',
|
||||
'limit' => 0,
|
||||
'offset' => 0,
|
||||
'sort' => 'ul.timeaccess desc',
|
||||
'expectedcourses' => [
|
||||
'ainprogress',
|
||||
'binprogress',
|
||||
'cinprogress',
|
||||
'dinprogress',
|
||||
'einprogress'
|
||||
],
|
||||
'expectednextoffset' => 15
|
||||
],
|
||||
'all limit and offset with sort sql injection for sort or 1==1' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 5,
|
||||
'sort' => 'ul.timeaccess desc or 1==1',
|
||||
'expectedcourses' => [],
|
||||
'expectednextoffset' => 0,
|
||||
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()'
|
||||
],
|
||||
'all limit and offset with sql injection of sort a custom one' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 5,
|
||||
'sort' => "ul.timeaccess LIMIT 1--",
|
||||
'expectedcourses' => [],
|
||||
'expectednextoffset' => 0,
|
||||
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()'
|
||||
],
|
||||
'all limit and offset with wrong sort direction' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 5,
|
||||
'sort' => "ul.timeaccess abcdasc",
|
||||
'expectedcourses' => [],
|
||||
'expectednextoffset' => 0,
|
||||
'expectedexception' => 'Invalid sort direction in $sort parameter in enrol_get_my_courses()'
|
||||
],
|
||||
'all limit and offset with wrong sort direction' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 5,
|
||||
'sort' => "ul.timeaccess.foo ascd",
|
||||
'expectedcourses' => [],
|
||||
'expectednextoffset' => 0,
|
||||
'expectedexception' => 'Invalid sort direction in $sort parameter in enrol_get_my_courses()'
|
||||
],
|
||||
'all limit and offset with wrong sort param' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 5,
|
||||
'sort' => "foobar",
|
||||
'expectedcourses' => [],
|
||||
'expectednextoffset' => 0,
|
||||
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()'
|
||||
],
|
||||
'all limit and offset with wrong field name' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 5,
|
||||
'sort' => "ul.foobar",
|
||||
'expectedcourses' => [],
|
||||
'expectednextoffset' => 0,
|
||||
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()'
|
||||
],
|
||||
'all limit and offset with wrong field separator' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 5,
|
||||
'sort' => "ul.timeaccess.foo",
|
||||
'expectedcourses' => [],
|
||||
'expectednextoffset' => 0,
|
||||
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()'
|
||||
],
|
||||
'all limit and offset with wrong field separator #' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 5,
|
||||
'sort' => "ul#timeaccess",
|
||||
'expectedcourses' => [],
|
||||
'expectednextoffset' => 0,
|
||||
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()'
|
||||
],
|
||||
'all limit and offset with wrong field separator $' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 5,
|
||||
'sort' => 'ul$timeaccess',
|
||||
'expectedcourses' => [],
|
||||
'expectednextoffset' => 0,
|
||||
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()'
|
||||
],
|
||||
'all limit and offset with wrong field name' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 5,
|
||||
'sort' => 'timeaccess123',
|
||||
'expectedcourses' => [],
|
||||
'expectednextoffset' => 0,
|
||||
'expectedexception' => 'Invalid $sort parameter in enrol_get_my_courses()'
|
||||
],
|
||||
'all limit and offset with no sort direction for ul' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'inprogress',
|
||||
'limit' => 0,
|
||||
'offset' => 0,
|
||||
'sort' => "ul.timeaccess",
|
||||
'expectedcourses' => ['ainprogress', 'binprogress', 'cinprogress', 'dinprogress', 'einprogress'],
|
||||
'expectednextoffset' => 15,
|
||||
],
|
||||
'all limit and offset with valid field name and no prefix, test for ul' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'inprogress',
|
||||
'limit' => 0,
|
||||
'offset' => 0,
|
||||
'sort' => "timeaccess",
|
||||
'expectedcourses' => ['ainprogress', 'binprogress', 'cinprogress', 'dinprogress', 'einprogress'],
|
||||
'expectednextoffset' => 15,
|
||||
],
|
||||
'all limit and offset with valid field name and no prefix' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 5,
|
||||
'sort' => "fullname",
|
||||
'expectedcourses' => ['bpast', 'cpast', 'dfuture', 'dpast', 'efuture'],
|
||||
'expectednextoffset' => 10,
|
||||
],
|
||||
'all limit and offset with valid field name and no prefix and with sort direction' => [
|
||||
'coursedata' => $coursedata,
|
||||
'classification' => 'all',
|
||||
'limit' => 5,
|
||||
'offset' => 5,
|
||||
'sort' => "fullname desc",
|
||||
'expectedcourses' => ['bpast', 'cpast', 'dfuture', 'dpast', 'efuture'],
|
||||
'expectednextoffset' => 10,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -2987,16 +3149,20 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
* @param string $classification Timeline classification
|
||||
* @param int $limit Maximum number of results
|
||||
* @param int $offset Offset the unfiltered courses result set by this amount
|
||||
* @param string $sort sort the courses
|
||||
* @param array $expectedcourses Expected courses in result
|
||||
* @param int $expectednextoffset Expected next offset value in result
|
||||
* @param string|null $expectedexception Expected exception string
|
||||
*/
|
||||
public function test_get_enrolled_courses_by_timeline_classification(
|
||||
$coursedata,
|
||||
$classification,
|
||||
$limit,
|
||||
$offset,
|
||||
$sort,
|
||||
$expectedcourses,
|
||||
$expectednextoffset
|
||||
$expectednextoffset,
|
||||
$expectedexception = null
|
||||
) {
|
||||
$this->resetAfterTest();
|
||||
$generator = $this->getDataGenerator();
|
||||
@@ -3013,6 +3179,11 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
|
||||
$this->setUser($student);
|
||||
|
||||
if (isset($expectedexception)) {
|
||||
$this->expectException('coding_exception');
|
||||
$this->expectExceptionMessage($expectedexception);
|
||||
}
|
||||
|
||||
// NOTE: The offset applies to the unfiltered full set of courses before the classification
|
||||
// filtering is done.
|
||||
// E.g. In our example if an offset of 2 is given then it would mean the first
|
||||
@@ -3021,7 +3192,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
$classification,
|
||||
$limit,
|
||||
$offset,
|
||||
'shortname ASC'
|
||||
$sort
|
||||
);
|
||||
$result = external_api::clean_returnvalue(
|
||||
core_course_external::get_enrolled_courses_by_timeline_classification_returns(),
|
||||
@@ -3032,7 +3203,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
return $course['shortname'];
|
||||
}, $result['courses']);
|
||||
|
||||
$this->assertEquals($expectedcourses, $actual);
|
||||
$this->assertEqualsCanonicalizing($expectedcourses, $actual);
|
||||
$this->assertEquals($expectednextoffset, $result['nextoffset']);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
This files describes API changes in /dataformat/ download system,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 3.9.8 ===
|
||||
* Optional $callback for the following \core\dataformat methods now receive a second argument to define
|
||||
whether the current format writer supports HTML:
|
||||
- download_data()
|
||||
- write_data()
|
||||
- write_data_to_filearea()
|
||||
|
||||
=== 3.9 ===
|
||||
* The following methods have been added to the base dataformat class to allow instances to export to a local
|
||||
file. They can be overridden in extending classes to define how files should be created:
|
||||
|
||||
@@ -24,10 +24,7 @@ Feature: Render H5P content using filters
|
||||
|
||||
@javascript @external
|
||||
Scenario: Render an external H5P content URL.
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
Given I am on the PageName1 "page activity editing" page logged in as teacher1
|
||||
And I set the field "Page content" to "<div>Go for it</div>https://moodle.h5p.com/content/1290772960722742119/embed"
|
||||
When I click on "Save and display" "button"
|
||||
And I wait until the page is ready
|
||||
@@ -36,10 +33,7 @@ Feature: Render H5P content using filters
|
||||
|
||||
@javascript
|
||||
Scenario: Add an external H5P content URL in a link with the URL. Should be rendered.
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
Given I am on the PageName1 "page activity editing" page logged in as teacher1
|
||||
# This content won't be displayed, so this scenario shouldn't be labeled as external.
|
||||
And I set the field "Page content" to "<a href='https://moodle.h5p.com/content/1290772960722742119/embed'>https://moodle.h5p.com/content/1290772960722742119/embed</a>"
|
||||
When I click on "Save and display" "button"
|
||||
@@ -48,10 +42,7 @@ Feature: Render H5P content using filters
|
||||
Then I should see "Lorum ipsum"
|
||||
|
||||
Scenario: Add an external H5P content URL in a link with text. Shouldn't be rendered.
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
Given I am on the PageName1 "page activity editing" page logged in as teacher1
|
||||
# This content won't be displayed, so this scenario shouldn't be labeled as external.
|
||||
And I set the field "Page content" to "<a href='https://moodle.h5p.com/content/1290772960722742119/embed'>Here you are the content</a>"
|
||||
When I click on "Save and display" "button"
|
||||
@@ -67,8 +58,7 @@ Feature: Render H5P content using filters
|
||||
| Name | ipsumFile |
|
||||
And I upload "h5p/tests/fixtures/ipsums.h5p" file to "Select files" filemanager
|
||||
And I press "Save and return to course"
|
||||
And I follow "PageName1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the PageName1 "page activity editing" page
|
||||
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
|
||||
And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
|
||||
And I click on "Server files" "link" in the ".fp-repo-area" "css_element"
|
||||
@@ -85,9 +75,7 @@ Feature: Render H5P content using filters
|
||||
Then I should see "Lorum ipsum"
|
||||
And I switch to the main frame
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
And I am on the PageName1 "page activity" page logged in as student1
|
||||
# Switch to iframe created by filter
|
||||
And I switch to "h5p-iframe" class iframe
|
||||
# Switch to iframe created by embed.php page
|
||||
@@ -104,8 +92,7 @@ Feature: Render H5P content using filters
|
||||
| Name | ipsumFile |
|
||||
And I upload "h5p/tests/fixtures/ipsums.h5p" file to "Select files" filemanager
|
||||
And I press "Save and return to course"
|
||||
And I follow "PageName1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the PageName1 "page activity editing" page
|
||||
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
|
||||
And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
|
||||
And I click on "Server files" "link" in the ".fp-repo-area" "css_element"
|
||||
@@ -129,8 +116,7 @@ Feature: Render H5P content using filters
|
||||
| Name | ipsumFileTeacher |
|
||||
And I upload "h5p/tests/fixtures/ipsums.h5p" file to "Select files" filemanager
|
||||
And I press "Save and return to course"
|
||||
And I follow "PageName1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the PageName1 "page activity editing" page
|
||||
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
|
||||
And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
|
||||
And I click on "Server files" "link" in the ".fp-repo-area" "css_element"
|
||||
@@ -153,8 +139,7 @@ Feature: Render H5P content using filters
|
||||
| Name | ipsumFile |
|
||||
And I upload "h5p/tests/fixtures/ipsums.h5p" file to "Select files" filemanager
|
||||
And I press "Save and return to course"
|
||||
And I follow "PageName2"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the PageName2 "page activity editing" page
|
||||
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
|
||||
And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
|
||||
And I click on "Server files" "link" in the ".fp-repo-area" "css_element"
|
||||
@@ -172,9 +157,7 @@ Feature: Render H5P content using filters
|
||||
And I should see "Lorum ipsum"
|
||||
And I switch to the main frame
|
||||
And I log out
|
||||
When I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
And I am on the PageName1 "page activity" page logged in as teacher1
|
||||
# Switch to iframe created by filter
|
||||
And I switch to "h5p-iframe" class iframe
|
||||
# Switch to iframe created by embed.php page
|
||||
|
||||
@@ -50,7 +50,8 @@ Feature: Marking guides can be created and edited
|
||||
@javascript
|
||||
Scenario: Deleting criterion and comment
|
||||
# Deleting criterion
|
||||
When I go to "Test assignment 1 name" advanced grading definition page
|
||||
When I am on "Course 1" course homepage
|
||||
And I go to "Test assignment 1 name" advanced grading definition page
|
||||
And I click on "Delete criterion" "button" in the "Guide criterion B" "table_row"
|
||||
And I press "Yes"
|
||||
And I press "Save"
|
||||
@@ -59,7 +60,8 @@ Feature: Marking guides can be created and edited
|
||||
And I should see "WARNING: Your marking guide has a maximum grade of 70 points"
|
||||
But I should not see "Guide criterion B"
|
||||
# Deleting a frequently used comment
|
||||
When I go to "Test assignment 1 name" advanced grading definition page
|
||||
When I am on "Course 1" course homepage
|
||||
And I go to "Test assignment 1 name" advanced grading definition page
|
||||
And I click on "Delete comment" "button" in the "Comment 3" "table_row"
|
||||
And I press "Yes"
|
||||
And I press "Save"
|
||||
@@ -91,9 +93,7 @@ Feature: Marking guides can be created and edited
|
||||
Then I should see "80" in the "Student 1" "table_row"
|
||||
And I log out
|
||||
# Viewing it as a student.
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment 1 name"
|
||||
And I am on the "Test assignment 1 name" "assign activity" page logged in as student1
|
||||
And I should see "80" in the ".feedback" "css_element"
|
||||
And I should see "Marking guide test description" in the ".feedback" "css_element"
|
||||
And I should see "Very good"
|
||||
|
||||
@@ -70,9 +70,7 @@ Feature: Rubrics can be created and edited
|
||||
And I should see "35" in the "Student 1" "table_row"
|
||||
And I log out
|
||||
# Viewing it as a student.
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment 1 name"
|
||||
And I am on the "Test assignment 1 name" "assign activity" page logged in as student1
|
||||
And I should see "35" in the ".feedback" "css_element"
|
||||
And I should see "Rubric test description" in the ".feedback" "css_element"
|
||||
And I should see "In general... work harder..."
|
||||
@@ -80,8 +78,7 @@ Feature: Rubrics can be created and edited
|
||||
And the level with "20" points is selected for the rubric criterion "Criterion 1"
|
||||
And the level with "5" points is selected for the rubric criterion "Criterion 3"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
# Editing a rubric definition without regrading students.
|
||||
And I go to "Test assignment 1 name" advanced grading definition page
|
||||
And "Save as draft" "button" should not exist
|
||||
@@ -93,9 +90,7 @@ Feature: Rubrics can be created and edited
|
||||
And I press "Continue"
|
||||
And I log out
|
||||
# Check that the student still sees the grade.
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment 1 name"
|
||||
And I am on the "Test assignment 1 name" "assign activity" page logged in as student1
|
||||
And I should see "35" in the ".feedback" "css_element"
|
||||
And the level with "20" points is selected for the rubric criterion "Criterion 1"
|
||||
And I log out
|
||||
@@ -110,30 +105,23 @@ Feature: Rubrics can be created and edited
|
||||
And I press "Continue"
|
||||
And I log out
|
||||
# Check that the student doesn't see the grade.
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment 1 name"
|
||||
And I am on the "Test assignment 1 name" "assign activity" page logged in as student1
|
||||
And I should see "35" in the ".feedback" "css_element"
|
||||
And the level with "20" points is not selected for the rubric criterion "Criterion 1"
|
||||
And I log out
|
||||
# Regrade student.
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment 1 name"
|
||||
And I am on the "Test assignment 1 name" "assign activity" page logged in as teacher1
|
||||
And I go to "Student 1" "Test assignment 1 name" activity advanced grading page
|
||||
And I should see "The rubric definition was changed after this student had been graded. The student can not see this rubric until you check the rubric and update the grade."
|
||||
And I save the advanced grading form
|
||||
And I log out
|
||||
# Check that the student sees the grade again.
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment 1 name"
|
||||
And I am on the "Test assignment 1 name" "assign activity" page logged in as student1
|
||||
And I should see "31.82" in the ".feedback" "css_element"
|
||||
And the level with "20" points is not selected for the rubric criterion "Criterion 1"
|
||||
# Hide all rubric info for students
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
And I go to "Test assignment 1 name" advanced grading definition page
|
||||
And I set the field "Allow users to preview rubric (otherwise it will only be displayed after grading)" to ""
|
||||
And I set the field "Display rubric description during evaluation" to ""
|
||||
@@ -145,9 +133,7 @@ Feature: Rubrics can be created and edited
|
||||
And I press "Continue"
|
||||
And I log out
|
||||
# Students should not see anything.
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment 1 name"
|
||||
And I am on the "Test assignment 1 name" "assign activity" page logged in as student1
|
||||
And I should not see "Criterion 1" in the ".submissionstatustable" "css_element"
|
||||
And I should not see "Criterion 2" in the ".submissionstatustable" "css_element"
|
||||
And I should not see "Criterion 3" in the ".submissionstatustable" "css_element"
|
||||
|
||||
@@ -14,12 +14,14 @@ Feature: Reuse my rubrics in other activities
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment 1 name |
|
||||
| Description | Test assignment 1 description |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | section | idnumber |
|
||||
| assign | Test assignment 1 name | Test assignment 1 description | C1 | 1 | assign1 |
|
||||
| assign | Test assignment 2 name | Test assignment 2 description | C1 | 1 | assign1 |
|
||||
And I am on the "Test assignment 1 name" "assign activity editing" page logged in as teacher1
|
||||
And I set the following fields to these values:
|
||||
| Grading method | Rubric |
|
||||
And I press "Save and return to course"
|
||||
And I go to "Test assignment 1 name" advanced grading definition page
|
||||
And I set the following fields to these values:
|
||||
| Name | Assignment 1 rubric |
|
||||
@@ -29,11 +31,10 @@ Feature: Reuse my rubrics in other activities
|
||||
| Criterion 2 | Level 21 | 21 | Level 22 | 22 | Level 3 | 23 |
|
||||
| Criterion 3 | Level 31 | 31 | Level 32 | 32 | | |
|
||||
And I press "Save rubric and make it ready"
|
||||
And I am on "Course 1" course homepage
|
||||
When I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment 2 name |
|
||||
| Description | Test assignment 2 description |
|
||||
And I am on the "Test assignment 2 name" "assign activity editing" page
|
||||
And I set the following fields to these values:
|
||||
| Grading method | Rubric |
|
||||
And I press "Save and return to course"
|
||||
And I set "Test assignment 2 name" activity to use "Assignment 1 rubric" grading form
|
||||
Then I should see "Ready for use"
|
||||
And I should see "Criterion 1"
|
||||
@@ -44,7 +45,6 @@ Feature: Reuse my rubrics in other activities
|
||||
And I should see "Criterion 1"
|
||||
And I should see "Criterion 2"
|
||||
And I should see "Criterion 3"
|
||||
And I press "Cancel"
|
||||
|
||||
@javascript
|
||||
Scenario: A teacher can reuse one of his/her previously created rubrics, with Javascript enabled
|
||||
|
||||
@@ -28,16 +28,13 @@ Feature: We can change what we are viewing on the grader report
|
||||
| Description | Submit your online text |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name 1"
|
||||
And I am on the "Test assignment name 1" "assign activity" page logged in as student1
|
||||
When I press "Add submission"
|
||||
And I set the following fields to these values:
|
||||
| Online text | This is a submission for assignment 1 |
|
||||
And I press "Save changes"
|
||||
Then I should see "Submitted for grading"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name 2"
|
||||
And I am on the "Test assignment name 2" "assign activity" page
|
||||
When I press "Add submission"
|
||||
And I set the following fields to these values:
|
||||
| Online text | This is a submission for assignment 2 |
|
||||
@@ -55,7 +52,7 @@ Feature: We can change what we are viewing on the grader report
|
||||
|
||||
@javascript
|
||||
Scenario: View and minimise the grader report containing hidden activities
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I am on "Course 1" course homepage with editing mode on
|
||||
And I open "Test assignment name 2" actions menu
|
||||
And I click on "Hide" "link" in the "Test assignment name 2" activity
|
||||
And I am on "Course 1" course homepage
|
||||
@@ -83,7 +80,7 @@ Feature: We can change what we are viewing on the grader report
|
||||
|
||||
@javascript
|
||||
Scenario: View and minimise the grader report containing hidden activities without the 'moodle/grade:viewhidden' capability
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I am on "Course 1" course homepage with editing mode on
|
||||
And I open "Test assignment name 2" actions menu
|
||||
And I click on "Hide" "link" in the "Test assignment name 2" activity
|
||||
And I log out
|
||||
|
||||
@@ -30,9 +30,7 @@ Feature: We can bulk insert grades for students in a course
|
||||
| assign | C1 | a4 | Test assignment four | Submit nothing! |
|
||||
|
||||
Scenario: I can bulk insert grades and check their override flags for grade view.
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment one"
|
||||
Given I am on the "Test assignment one" "assign activity" page logged in as teacher1
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
And I set the following fields to these values:
|
||||
@@ -71,9 +69,7 @@ Feature: We can bulk insert grades for students in a course
|
||||
And the field "Override for Student 4" matches value "1"
|
||||
|
||||
Scenario: I can bulk insert grades and check their override flags for user view.
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment two"
|
||||
Given I am on the "Test assignment two" "assign activity" page logged in as teacher1
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
And I set the following fields to these values:
|
||||
@@ -103,8 +99,7 @@ Feature: We can bulk insert grades for students in a course
|
||||
And the field "Override for Test assignment four" matches value "1"
|
||||
|
||||
Scenario: I can not update grades if the value is out of bounds.
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
Given I am on the "Course 1" course page logged in as teacher1
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I follow "Single view for Test assignment one"
|
||||
And I set the field "Perform bulk insert" to "1"
|
||||
|
||||
@@ -11,8 +11,8 @@ Feature: We can change the grading type and maximum grade point values
|
||||
| fullname | shortname | category | format |
|
||||
| Course 1 | C1 | 0 | topics |
|
||||
Given the following "activities" exist:
|
||||
| activity | course | idnumber | name | intro |
|
||||
| assign | C1 | assign1| Test Assignment 1 | Test Assignment 1 |
|
||||
| activity | course | idnumber | name | intro |
|
||||
| assign | C1 | assign1 | Test Assignment 1 | Test Assignment 1 |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Grades > General settings" in site administration
|
||||
And I set the following fields to these values:
|
||||
@@ -23,9 +23,8 @@ Feature: We can change the grading type and maximum grade point values
|
||||
|
||||
@javascript
|
||||
Scenario: Validate that switching the type of grading used correctly disables input form elements
|
||||
When I follow "Test Assignment 1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
Given I am on the "Test Assignment 1" "assign activity editing" page
|
||||
When I expand all fieldsets
|
||||
And I set the field "grade[modgrade_type]" to "Point"
|
||||
Then the "Scale" "select" should be disabled
|
||||
And the "Maximum grade" "field" should be enabled
|
||||
@@ -39,46 +38,42 @@ Feature: We can change the grading type and maximum grade point values
|
||||
|
||||
@javascript
|
||||
Scenario: Create an activity with a maximum grade point value less than the system maximum
|
||||
When I follow "Test Assignment 1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
Given I am on the "Test Assignment 1" "assign activity editing" page
|
||||
When I expand all fieldsets
|
||||
And I set the field "grade[modgrade_type]" to "point"
|
||||
And I set the field "grade[modgrade_point]" to "600"
|
||||
And I press "Save and display"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test Assignment 1" "assign activity editing" page
|
||||
Then the field "grade[modgrade_point]" matches value "600"
|
||||
And the "Scale" "select" should be disabled
|
||||
And I press "Save and return to course"
|
||||
|
||||
@javascript
|
||||
Scenario: Create an activity with a scale as the grade type
|
||||
When I follow "Test Assignment 1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
Given I am on the "Test Assignment 1" "assign activity editing" page
|
||||
When I expand all fieldsets
|
||||
And I set the field "grade[modgrade_type]" to "Scale"
|
||||
And I set the field "grade[modgrade_scale]" to "Separate and Connected ways of knowing"
|
||||
And I press "Save and display"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test Assignment 1" "assign activity editing" page
|
||||
Then the field "grade[modgrade_scale]" matches value "Separate and Connected ways of knowing"
|
||||
And the "Maximum grade" "field" should be disabled
|
||||
And I press "Save and return to course"
|
||||
|
||||
@javascript
|
||||
Scenario: Create an activity with no grade as the grade type
|
||||
When I follow "Test Assignment 1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
Given I am on the "Test Assignment 1" "assign activity editing" page
|
||||
When I expand all fieldsets
|
||||
And I set the field "grade[modgrade_type]" to "None"
|
||||
And I press "Save and display"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test Assignment 1" "assign activity editing" page
|
||||
And the "Scale" "select" should be disabled
|
||||
And the "Maximum grade" "field" should be disabled
|
||||
And I press "Save and return to course"
|
||||
|
||||
Scenario: Create an activity with a maximum grade point value higher than the system maximum
|
||||
When I follow "Test Assignment 1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
Given I am on the "Test Assignment 1" "assign activity editing" page
|
||||
When I expand all fieldsets
|
||||
And I set the field "grade[modgrade_type]" to "Point"
|
||||
And I set the field "grade[modgrade_point]" to "20000"
|
||||
And I press "Save and display"
|
||||
@@ -86,9 +81,8 @@ Feature: We can change the grading type and maximum grade point values
|
||||
And I press "Cancel"
|
||||
|
||||
Scenario: Create an activity with a valid maximum grade point and then change the system maximum to be lower
|
||||
When I follow "Test Assignment 1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
Given I am on the "Test Assignment 1" "assign activity editing" page
|
||||
When I expand all fieldsets
|
||||
And I set the field "grade[modgrade_type]" to "point"
|
||||
And I set the field "grade[modgrade_point]" to "600"
|
||||
And I press "Save and display"
|
||||
@@ -96,9 +90,7 @@ Feature: We can change the grading type and maximum grade point values
|
||||
And I set the following fields to these values:
|
||||
| Grade point maximum | 100 |
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test Assignment 1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test Assignment 1" "assign activity editing" page
|
||||
And I press "Save and display"
|
||||
Then I should see "Invalid grade value. This must be an integer between 1 and 100"
|
||||
And I press "Cancel"
|
||||
|
||||
@@ -23,8 +23,7 @@ Feature: Regrading grades does not unnecessarily mark some as overriden
|
||||
And I navigate to "Grades > Grade category settings" in site administration
|
||||
And I set the field "Available aggregation types" to "Weighted mean of grades"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Assignment 1"
|
||||
And I am on the "Assignment 1" "assign activity" page
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
And I set the field "Grade out of 100" to "80"
|
||||
@@ -59,8 +58,7 @@ Feature: Regrading grades does not unnecessarily mark some as overriden
|
||||
|
||||
@javascript
|
||||
Scenario: Confirm overridden course total does not get regraded when activity grade is changed
|
||||
Given I am on "Course 1" course homepage
|
||||
And I follow "Assignment 1"
|
||||
Given I am on the "Assignment 1" "assign activity" page
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
And I set the field "Grade out of 100" to "90"
|
||||
|
||||
@@ -43,10 +43,7 @@ Feature: View gradebook when scales are used
|
||||
And the following "activities" exist:
|
||||
| activity | course | idnumber | name | intro | gradecategory |
|
||||
| assign | C1 | a1 | Test assignment one | Submit something! | Sub category 1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment one"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test assignment one" "assign activity editing" page logged in as teacher1
|
||||
And I expand all fieldsets
|
||||
And I set the field "grade[modgrade_type]" to "Scale"
|
||||
And I set the field "grade[modgrade_scale]" to "EN Letterscale"
|
||||
|
||||
@@ -39,10 +39,7 @@ Feature: View gradebook when single item scales are used
|
||||
| assign | C1 | a1 | Test assignment one | Submit something! | <span lang="en" class="multilang">EN</span><span lang="fr" class="multilang">FR</span> Sub category 1 |
|
||||
And the "multilang" filter is "on"
|
||||
And the "multilang" filter applies to "content and headings"
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment one"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test assignment one" "assign activity editing" page logged in as teacher1
|
||||
And I expand all fieldsets
|
||||
And I set the field "grade[modgrade_type]" to "Scale"
|
||||
And I set the field "grade[modgrade_scale]" to "EN Singleitem"
|
||||
|
||||
@@ -29,5 +29,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = '';
|
||||
$string['thisdirection'] = 'ltr';
|
||||
$string['thislanguage'] = 'Afrikaans';
|
||||
|
||||
@@ -31,7 +31,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['clianswerno'] = 'لا';
|
||||
$string['cliansweryes'] = 'نعم';
|
||||
$string['cliincorrectvalueerror'] = 'خطأ، القيمة "{$a->value}" غير صحيحة من أجل "{$a->option}"';
|
||||
$string['cliincorrectvalueerror'] = 'خطأ، القيمة "{$a->value}" غير صحيحة لـ "{$a->option}"';
|
||||
$string['cliincorrectvalueretry'] = 'قيمة غير صحيحة، حاول مرة أخرى';
|
||||
$string['clitypevalue'] = 'اكتب قيمة';
|
||||
$string['clitypevaluedefault'] = 'اكتب قيمة أو اضغط زر الإدخال لاستخدام القيم الافتراضية ({$a})';
|
||||
|
||||
@@ -45,6 +45,6 @@ $string['invalidmd5'] = 'La variable de comprobación era incorrecta - inténtel
|
||||
$string['missingrequiredfield'] = 'Falta algún campo necesario';
|
||||
$string['remotedownloaderror'] = '<p>Falló la descarga del componente a su servidor. Se recomienda verificar los ajustes del proxy, extensión PHP cURL.</p>
|
||||
<p>Debe descargar el <a href="{$a->url}">{$a->url}</a> archivo manualmente, copiarlo en "{$a->dest}" en su servidor y descomprimirlo allí.</p>';
|
||||
$string['wrongdestpath'] = 'Ruta de destino errónea.';
|
||||
$string['wrongsourcebase'] = 'Base de fuente de URL errónea.';
|
||||
$string['wrongdestpath'] = 'Ruta de destino errónea';
|
||||
$string['wrongsourcebase'] = 'Base de URL de origen errónea';
|
||||
$string['wrongzipfilename'] = 'Nombre de fichero ZIP incorrecto';
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
// This file is part of Moodle - https://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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Automatically generated strings for Moodle installer
|
||||
*
|
||||
* Do not edit this file manually! It contains just a subset of strings
|
||||
* needed during the very first steps of installation. This file was
|
||||
* generated automatically by export-installer.php (which is part of AMOS
|
||||
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
|
||||
* list of strings defined in /install/stringnames.txt.
|
||||
*
|
||||
* @package installer
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['thislanguage'] = 'Hornjoserbsski';
|
||||
@@ -38,7 +38,7 @@ $string['cannotfindcomponent'] = 'Nincs meg az összetevő.';
|
||||
$string['cannotsavemd5file'] = 'Az md5 állományt nem lehet elmenteni.';
|
||||
$string['cannotsavezipfile'] = 'A tömörített állományt nem lehet elmenteni.';
|
||||
$string['cannotunzipfile'] = 'A tömörített állományt nem lehet kicsomagolni.';
|
||||
$string['componentisuptodate'] = 'Az összetevő a legújabb.';
|
||||
$string['componentisuptodate'] = 'Az összetevő a legfrissebb.';
|
||||
$string['dmlexceptiononinstall'] = '<p>Adatbázishiba történt [{$a->errorcode}].<br />{$a->debuginfo}</p>';
|
||||
$string['downloadedfilecheckfailed'] = 'A letöltött állomány ellenőrzése nem sikerült.';
|
||||
$string['invalidmd5'] = 'Az ellenőrző változó hibás volt – próbálkozzék ismét';
|
||||
|
||||
@@ -33,7 +33,7 @@ $string['admindirname'] = 'Rendszergazda-könyvtár';
|
||||
$string['availablelangs'] = 'Elérhető nyelvek listája';
|
||||
$string['chooselanguagehead'] = 'Nyelv kiválasztása';
|
||||
$string['chooselanguagesub'] = 'Válasszon nyelvet a telepítéshez! Ez lesz a portál alapbeállítás szerinti nyelve, de később módosíthatja.';
|
||||
$string['clialreadyconfigured'] = 'A config.php már létezik, a portál telepítéséhez használja az admin/cli/install_database.php állományt.';
|
||||
$string['clialreadyconfigured'] = 'A config.php már létezik, a Moodle portálra telepítéséhez használja az admin/cli/install_database.php állományt.';
|
||||
$string['clialreadyinstalled'] = 'A config.php már létezik, a portál frissítéséhez használja az admin/cli/upgrade.php állományt.';
|
||||
$string['cliinstallheader'] = 'A Moodle {$a} parancssori telepítő programja';
|
||||
$string['databasehost'] = 'Az adatbázis gazdagépe';
|
||||
@@ -56,7 +56,9 @@ $string['pathshead'] = 'Útvonalak megerősítése';
|
||||
$string['pathsrodataroot'] = 'Az adatok gyökérkönyvtára nem írható.';
|
||||
$string['pathsroparentdataroot'] = 'A felettes könyvtár ({$a->parent}) nem írható. A telepítő nem tudja létrehozni az adatkönyvtárat ({$a->dataroot}).';
|
||||
$string['pathssubadmindir'] = 'Egy pár webes gazdagép esetén az /admin speciális URL pl. a vezérlőpanel eléréséhez. Ez ütközik a Moodle admin oldalainak standard helyével. Javítás: a telepítésben nevezze át a rendszergazda könyvtárát, az új nevet pedig írja be ide. Például: <em>moodleadmin</em>. Ezzel helyrehozhatók a Moodle rendszergazdai hivatkozásai.';
|
||||
$string['pathssubdataroot'] = 'Szüksége van egy helyre, ahol a Moodle mentheti a feltöltött állományokat. Ez a könyvtár a webszerver felhasználója (általában \'nobody\' vagy \'apache\') számára legyen mind olvasható, MIND ÍRHATÓ. Ha nem létezik, a telepítő megpróbálja létrehozni.';
|
||||
$string['pathssubdataroot'] = 'Szüksége van egy helyre, ahol a Moodle mentheti a feltöltött állományokat. Ez a könyvtár a webszerver felhasználója (általában \'www-data\', \'nobody\' vagy \'apache\') számára legyen mind olvasható, mind írható.
|
||||
A könyvtár a webről közvetlenül nem lehet elérhető.
|
||||
Ha nem létezik, a telepítő megpróbálja létrehozni.';
|
||||
$string['pathssubdirroot'] = 'Teljes útvonal a Moodle telepítéséhez. ';
|
||||
$string['pathssubwwwroot'] = 'A Moodle elérésére használandó teljes webcím. A Moodle egyszerre több címről nem érhető el. Ha portálja több címet használ, a jelen cím kivételével az összeshez állandó
|
||||
átirányítást kell beállítania. Ha portálja mind intranetről, mind az internetről elérhető, a nyilvános címet itt adja meg, a DNS-t pedig úgy állítsa be, hogy az intranetről a nyilvános cím is elérhető legyen. Ha a cím hibás, módosítsa böngészőjében a webcímet, hogy a telepítés egy másik értékkel induljon újra.';
|
||||
|
||||
@@ -29,14 +29,16 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['clianswerno'] = 'T';
|
||||
$string['cliansweryes'] = 'Y';
|
||||
$string['cliincorrectvalueerror'] = 'Error, nilai yang salah "{$a->value}" untuk opsi "{$a->option}"';
|
||||
$string['cliincorrectvalueretry'] = 'Nilai input salah, silahkan coba lagi';
|
||||
$string['clianswerno'] = 't';
|
||||
$string['cliansweryes'] = 'y';
|
||||
$string['cliincorrectvalueerror'] = 'GALAT, nilai yang salah "{$a->value}" untuk opsi "{$a->option}"';
|
||||
$string['cliincorrectvalueretry'] = 'Nilai masukan salah, silakan coba lagi';
|
||||
$string['clitypevalue'] = 'tipe nilai';
|
||||
$string['clitypevaluedefault'] = 'tipe nilai, tekan enter untuk menggunakan nilai default ({$a})';
|
||||
$string['clitypevaluedefault'] = 'tipe nilai, tekan ENTER untuk menggunakan nilai bawaan ({$a})';
|
||||
$string['cliunknowoption'] = 'Opsi tidak dikenali :
|
||||
{$a}
|
||||
Silahkan gunakan opsi --help';
|
||||
Silakan gunakan opsi --help';
|
||||
$string['cliyesnoprompt'] = 'ketik y (Ya) atau t (Tidak)';
|
||||
$string['environmentrequireinstall'] = 'harus dipasang dan diaktifkan';
|
||||
$string['environmentrequireversion'] = 'versi {$a->needed} diperlukan dan Anda menjalankan {$a->current}';
|
||||
$string['upgradekeyset'] = 'Tingkatkan kunci (biarkan kosong untuk tidak mengaturnya)';
|
||||
|
||||
@@ -65,7 +65,7 @@ $string['pathsunsecuredataroot'] = 'Lokasi dataroot tidak aman';
|
||||
$string['pathswrongadmindir'] = 'Direktori admin tidak ada';
|
||||
$string['phpextension'] = 'Ekstensi PHP {$a}';
|
||||
$string['phpversion'] = 'Versi PHP';
|
||||
$string['phpversionhelp'] = '<p> Moodle membutuhkan versi PHP setidaknya 5.6.5 atau 7.1 (7.0.x memiliki beberapa keterbatasan mesin). </p> <p> Anda saat ini menjalankan versi {$a}. </p> <p> Anda harus meningkatkan versi PHP atau pindah ke host dengan versi PHP yang lebih baru. </p>';
|
||||
$string['phpversionhelp'] = '<p> Moodle membutuhkan versi PHP setidaknya 5.6.5 atau 7.1 (7.0.x memiliki beberapa keterbatasan mesin). </p> <p> Anda saat ini menjalankan versi {$a}. </p> <p> Anda harus meningkatkan versi PHP atau pindah ke hos dengan versi PHP yang lebih baru. </p>';
|
||||
$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
|
||||
$string['welcomep20'] = 'Anda melihat halaman ini karena Anda telah berhasil memasang dan meluncurkan paket <strong> {$a->packname} {$a->packversion}</strong> di komputer Anda. Selamat!';
|
||||
$string['welcomep30'] = 'Rilis <strong> {$a->installername}</strong> ini mencakup aplikasi untuk menciptakan lingkungan tempat <strong> Moodle </strong> yang akan digunakan, yaitu:';
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
// This file is part of Moodle - https://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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Automatically generated strings for Moodle installer
|
||||
*
|
||||
* Do not edit this file manually! It contains just a subset of strings
|
||||
* needed during the very first steps of installation. This file was
|
||||
* generated automatically by export-installer.php (which is part of AMOS
|
||||
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
|
||||
* list of strings defined in /install/stringnames.txt.
|
||||
*
|
||||
* @package installer
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['clitypevalue'] = 'တန်ဖိုး ထည့်သွင်းပါ';
|
||||
$string['clitypevaluedefault'] = 'တန်ဖိုး ထည့်သွင်းပါ၊ ပုံသေတန်ဖိုး ({$a}) ကိုအသုံးပြုလိုပါက ENTER ကိုနှိပ်ပါ';
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
// This file is part of Moodle - https://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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Automatically generated strings for Moodle installer
|
||||
*
|
||||
* Do not edit this file manually! It contains just a subset of strings
|
||||
* needed during the very first steps of installation. This file was
|
||||
* generated automatically by export-installer.php (which is part of AMOS
|
||||
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
|
||||
* list of strings defined in /install/stringnames.txt.
|
||||
*
|
||||
* @package installer
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['cannotcreatetempdir'] = 'temp directory ကို မတည်ဆောက်နိုင်ပါ၊၊';
|
||||
$string['cannotdownloadcomponents'] = 'အစိတ်အပိုင်းများကို ဒေါင်းလုတ်ဆွဲမရပါ။';
|
||||
$string['cannotdownloadzipfile'] = 'ZIP ဖိုင်ကိုဒေါင်းလုတ်ဆွဲမရပါ။';
|
||||
$string['cannotfindcomponent'] = 'အစိတ်အပိုင်းကို ရှာဖွေမတွေ့ရှိပါ။';
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
// This file is part of Moodle - https://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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Automatically generated strings for Moodle installer
|
||||
*
|
||||
* Do not edit this file manually! It contains just a subset of strings
|
||||
* needed during the very first steps of installation. This file was
|
||||
* generated automatically by export-installer.php (which is part of AMOS
|
||||
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
|
||||
* list of strings defined in /install/stringnames.txt.
|
||||
*
|
||||
* @package installer
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['language'] = 'ဘာသာစကား';
|
||||
$string['moodlelogo'] = 'Moodle Logo';
|
||||
$string['next'] = 'နောက်သို့';
|
||||
@@ -39,4 +39,4 @@ $string['cliunknowoption'] = 'Opções desconhecidas: {$a}. Por favor, use a op
|
||||
$string['cliyesnoprompt'] = 'digite s (para sim) ou n (para não)';
|
||||
$string['environmentrequireinstall'] = 'deve estar instalada e ativa';
|
||||
$string['environmentrequireversion'] = 'é requerida a versão {$a->needed} e está a correr a versão {$a->current}';
|
||||
$string['upgradekeyset'] = 'Chave de atualização (deixe em branco caso não pretenda definir uma)';
|
||||
$string['upgradekeyset'] = 'Chave de atualização (deixe em branco caso não pretenda definir)';
|
||||
|
||||
@@ -48,4 +48,4 @@ $string['missingrequiredfield'] = 'Det saknas några obligatoriska fält';
|
||||
$string['remotedownloaderror'] = 'Nedladdningen av en komponent till din server misslyckades. Vänligen verifiera inställningar för proxy. <br /><br />Du måste ladda ner <a href="{$a->url}">{$a->url}</a> filen manuellt, kopiera den till "{$a->dest}" på din server och packa upp den där.';
|
||||
$string['wrongdestpath'] = 'Fel målsökväg';
|
||||
$string['wrongsourcebase'] = 'Felaktig käll- URL rot';
|
||||
$string['wrongzipfilename'] = 'Fel namn på ZIP-filen';
|
||||
$string['wrongzipfilename'] = 'Felaktigt namn på ZIP-fil';
|
||||
|
||||
@@ -30,3 +30,6 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['language'] = 'زبان';
|
||||
$string['next'] = 'اگلے';
|
||||
$string['previous'] = 'پچھلا';
|
||||
$string['reload'] = 'دوبارہ لوڈ کریں';
|
||||
|
||||
+1
-1
@@ -604,7 +604,7 @@ $string['emailalreadysent'] = 'A password reset email has already been sent. Ple
|
||||
$string['emailactive'] = 'Email activated';
|
||||
$string['emailagain'] = 'Email (again)';
|
||||
$string['emailconfirm'] = 'Confirm your account';
|
||||
$string['emailconfirmation'] = 'Hi {$a->firstname},
|
||||
$string['emailconfirmation'] = 'Hi,
|
||||
|
||||
A new account has been requested at \'{$a->sitename}\'
|
||||
using your email address.
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
define ("core/paged_content_pages",["jquery","core/templates","core/notification","core/pubsub","core/paged_content_events"],function(a,b,c,d,e){var f={ROOT:"[data-region=\"page-container\"]",PAGE_REGION:"[data-region=\"paged-content-page\"]",ACTIVE_PAGE_REGION:"[data-region=\"paged-content-page\"].active"},g={PAGING_CONTENT_ITEM:"core/paged_content_page",LOADING:"core/overlay_loading"},h=function(a,b){return a.find("[data-page=\""+b+"\"]")},i=function(d){var e=a.Deferred();d.attr("aria-busy",!0);b.render(g.LOADING,{visible:!0}).then(function(b){var c=a(b),f=setTimeout(function(){d.css("position","relative");c.appendTo(d)},300);e.always(function(){clearTimeout(f);c.remove();d.css("position","");d.removeAttr("aria-busy")})}).fail(c.exception);return e},j=function(d,e,f){var i=a.Deferred();e.then(function(a,e){e=e||"";b.render(g.PAGING_CONTENT_ITEM,{page:f,content:a}).then(function(a){b.appendNodeContents(d,a,e);var c=h(d,f);i.resolve(c)}).fail(function(a){i.reject(a)}).fail(c.exception)}).fail(function(a){i.reject(a)}).fail(c.exception);return i.promise()},k=function(b,g,k,l){var m=[],n=[],o=a.Deferred();g.forEach(function(a){var c=a.pageNumber,d=h(b,c);if(d.length){m.push(d)}else{n.push(a)}});if(n.length&&"function"==typeof l){var p=l(n,{allItemsLoaded:function allItemsLoaded(a){d.publish(k+e.ALL_ITEMS_LOADED,a)}}),q=p.map(function(a,c){return j(b,a,n[c].pageNumber)});a.when.apply(a,q).then(function(){var a=Array.prototype.slice.call(arguments);o.resolve(a)}).fail(function(a){o.reject(a)}).fail(c.exception)}else{o.resolve([])}var r=i(b);o.then(function(a){var c=m.concat(a);b.find(f.PAGE_REGION).addClass("hidden");c.forEach(function(a){if(!0){a.removeClass("hidden")}})}).then(function(){d.publish(k+e.PAGES_SHOWN,g)}).fail(c.exception).always(function(){r.resolve()})};return{init:function init(b,c,f){b=a(b);d.subscribe(c+e.SHOW_PAGES,function(a){k(b,a,c,f)});d.subscribe(c+e.SET_ITEMS_PER_PAGE_LIMIT,function(){b.empty()})},rootSelector:f.ROOT}});
|
||||
define ("core/paged_content_pages",["jquery","core/templates","core/notification","core/pubsub","core/paged_content_events","core/pending"],function(a,b,c,d,e,f){var g={ROOT:"[data-region=\"page-container\"]",PAGE_REGION:"[data-region=\"paged-content-page\"]",ACTIVE_PAGE_REGION:"[data-region=\"paged-content-page\"].active"},h={PAGING_CONTENT_ITEM:"core/paged_content_page",LOADING:"core/overlay_loading"},i=function(a,b){return a.find("[data-page=\""+b+"\"]")},j=function(d){var e=a.Deferred();d.attr("aria-busy",!0);var g=new f("core/paged_content_pages:startLoading");b.render(h.LOADING,{visible:!0}).then(function(b){var c=a(b),f=setTimeout(function(){d.css("position","relative");c.appendTo(d)},300);e.always(function(){clearTimeout(f);c.remove();d.css("position","");d.removeAttr("aria-busy");g.resolve()})}).fail(c.exception);return e},k=function(d,e,f){var g=a.Deferred();e.then(function(a,e){e=e||"";b.render(h.PAGING_CONTENT_ITEM,{page:f,content:a}).then(function(a){b.appendNodeContents(d,a,e);var c=i(d,f);g.resolve(c)}).fail(function(a){g.reject(a)}).fail(c.exception)}).fail(function(a){g.reject(a)}).fail(c.exception);return g.promise()},l=function(b,h,l,m){var n=new f("core/paged_content_pages:showPages"),o=[],p=[],q=a.Deferred();h.forEach(function(a){var c=a.pageNumber,d=i(b,c);if(d.length){o.push(d)}else{p.push(a)}});if(p.length&&"function"==typeof m){var r=m(p,{allItemsLoaded:function allItemsLoaded(a){d.publish(l+e.ALL_ITEMS_LOADED,a)}}),s=r.map(function(a,c){return k(b,a,p[c].pageNumber)});a.when.apply(a,s).then(function(){var a=Array.prototype.slice.call(arguments);q.resolve(a)}).fail(function(a){q.reject(a)}).fail(c.exception)}else{q.resolve([])}var t=j(b);q.then(function(a){var c=o.concat(a);b.find(g.PAGE_REGION).addClass("hidden");c.forEach(function(a){if(!0){a.removeClass("hidden")}})}).then(function(){d.publish(l+e.PAGES_SHOWN,h)}).fail(c.exception).always(function(){t.resolve();n.resolve()}).catch()};return{init:function init(b,c,f){b=a(b);d.subscribe(c+e.SHOW_PAGES,function(a){l(b,a,c,f)});d.subscribe(c+e.SET_ITEMS_PER_PAGE_LIMIT,function(){b.empty()})},rootSelector:g.ROOT}});
|
||||
//# sourceMappingURL=paged_content_pages.min.js.map
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,2 +1,2 @@
|
||||
define ("core/paged_content_paging_bar",["jquery","core/custom_interaction_events","core/paged_content_events","core/str","core/pubsub"],function(a,b,c,d,e){var f={ROOT:"[data-region=\"paging-bar\"]",PAGE:"[data-page]",PAGE_ITEM:"[data-region=\"page-item\"]",PAGE_LINK:"[data-region=\"page-link\"]",FIRST_BUTTON:"[data-control=\"first\"]",LAST_BUTTON:"[data-control=\"last\"]",NEXT_BUTTON:"[data-control=\"next\"]",PREVIOUS_BUTTON:"[data-control=\"previous\"]",DOTS_BUTTONS:"[data-dots]",BEGINNING_DOTS_BUTTON:"[data-dots=\"beginning\"]",ENDING_DOTS_BUTTON:"[data-dots=\"ending\"]"},g=function(a,b){return a.find(f.PAGE_ITEM+"[data-page-number=\""+b+"\"]")},h=function(a){return a.find(f.NEXT_BUTTON)},i=function(a,b){a.attr("data-last-page-number",b)},j=function(a){return parseInt(a.attr("data-last-page-number"),10)},k=function(a){return parseInt(a.attr("data-active-page-number"),10)},l=function(a,b){a.attr("data-active-page-number",b)},m=function(a){var b=k(a);return!isNaN(b)&&0!=b},n=function(a,b){if(b.attr("data-page")!=void 0){return parseInt(b.attr("data-page-number"),10)}var c=1,d=null;switch(b.attr("data-control")){case"first":c=1;break;case"last":c=j(a);break;case"next":d=k(a);var e=j(a);if(!e){c=d+1}else if(d&&d<e){c=d+1}else{c=e}break;case"previous":d=k(a);if(d&&1<d){c=d-1}else{c=1}break;default:c=1;break;}return parseInt(c,10)},o=function(a){return parseInt(a.attr("data-items-per-page"),10)},p=function(a,b){a.attr("data-items-per-page",b)},q=function(a){a.removeClass("hidden")},r=function(a){a.addClass("hidden")},s=function(a){var b=a.find(f.NEXT_BUTTON),c=a.find(f.LAST_BUTTON);b.addClass("disabled");b.attr("aria-disabled",!0);c.addClass("disabled");c.attr("aria-disabled",!0)},t=function(a){var b=a.find(f.NEXT_BUTTON),c=a.find(f.LAST_BUTTON);b.removeClass("disabled");b.removeAttr("aria-disabled");c.removeClass("disabled");c.removeAttr("aria-disabled")},u=function(a){var b=a.find(f.PREVIOUS_BUTTON),c=a.find(f.FIRST_BUTTON);b.addClass("disabled");b.attr("aria-disabled",!0);c.addClass("disabled");c.attr("aria-disabled",!0)},v=function(b){var c=k(b),d=j(b),e=b.find(f.DOTS_BUTTONS),g=b.find(f.BEGINNING_DOTS_BUTTON),h=b.find(f.ENDING_DOTS_BUTTON),i=b.find(f.PAGE),l=parseInt(b.attr("data-bar-size"),10);if(l&&d>l){var m=Math.max(c-Math.round(l/2),1),n=m+l-1;if(n>=d){n=d;m=n-l+1}if(1<m){q(g);m++}else{r(g)}if(n<d){q(h);n--}else{r(h)}e.addClass("disabled");e.attr("aria-disabled",!0);r(i);i.each(function(b,c){c=a(c);if(b+1>=m&&b+1<=n){q(c)}})}else{r(e)}},w=function(a){var b=a.find(f.PREVIOUS_BUTTON),c=a.find(f.FIRST_BUTTON);b.removeClass("disabled");b.removeAttr("aria-disabled");c.removeClass("disabled");c.removeAttr("aria-disabled")},x=function(a){var b=a.attr("data-aria-label-components-pagination-item"),c=b.split(",").map(function(a){return a.trim()});return c},y=function(a){var b=a.attr("data-aria-label-components-pagination-active-item"),c=b.split(",").map(function(a){return a.trim()});return c},z=function(b,c){var d=0;l(b,0);c.each(function(c,e){var f=c+1;e=a(e);e.attr("data-page-number",f);d++;if(e.hasClass("active")){l(b,f)}});i(b,d)},A=function(b){var c=x(b),e=y(b),g=k(b),h=b.find(f.PAGE_ITEM),i=h.map(function(d,f){f=a(f);var h=n(b,f);if(h===g){return{key:e[0],component:e[1],param:h}}else{return{key:c[0],component:c[1],param:h}}});d.get_strings(i).then(function(b){h.each(function(c,d){d=a(d);var e=b[c];d.attr("aria-label",e);d.find(f.PAGE_LINK).attr("aria-label",e)});return b}).catch(function(){})},B=function(a,b,d){var h=j(a),i=b==k(a),m=o(a);if(!i){a.find(f.PAGE_ITEM).removeClass("active").removeAttr("aria-current");var n=g(a,b);n.addClass("active");n.attr("aria-current",!0);l(a,b);v(a)}if(h&&b>=h){s(a)}else{t(a)}if(1<b){w(a)}else{u(a)}A(a);e.publish(d+c.SHOW_PAGES,[{pageNumber:b,limit:m,offset:(b-1)*m}])},C=function(d,g){var h=d.attr("data-ignore-control-while-loading"),k=!1;if(""==h){h=!0}b.define(d,[b.events.activate]);d.on(b.events.activate,f.PAGE_ITEM,function(b,c){c.originalEvent.preventDefault();c.originalEvent.stopPropagation();if(h&&k){return}var e=a(b.target).closest(f.PAGE_ITEM);if(!e.hasClass("disabled")){var i=n(d,e);B(d,i,g);k=!0}});e.subscribe(g+c.ALL_ITEMS_LOADED,function(a){k=!1;var b=j(d);if(!b||a<b){i(d,a)}if(1===a&&d.attr("data-hide-control-on-single-page")){r(d);s(d);u(d)}else{q(d);s(d)}});e.subscribe(g+c.PAGES_SHOWN,function(){k=!1});e.subscribe(g+c.SET_ITEMS_PER_PAGE_LIMIT,function(a){p(d,a);i(d,0);l(d,0);q(d);B(d,1,g)})};return{init:function init(b,c){b=a(b);var d=b.find(f.PAGE);z(b,d);C(b,c);if(m(b)){var e=k(b);g(b,e).click();if(1==e){u(b)}}else{h(b).click()}v(b)},disableNextControlButtons:s,enableNextControlButtons:t,disablePreviousControlButtons:u,enablePreviousControlButtons:w,showPage:B,rootSelector:f.ROOT}});
|
||||
define ("core/paged_content_paging_bar",["jquery","core/custom_interaction_events","core/paged_content_events","core/str","core/pubsub","core/pending"],function(a,b,c,d,e,f){var g={ROOT:"[data-region=\"paging-bar\"]",PAGE:"[data-page]",PAGE_ITEM:"[data-region=\"page-item\"]",PAGE_LINK:"[data-region=\"page-link\"]",FIRST_BUTTON:"[data-control=\"first\"]",LAST_BUTTON:"[data-control=\"last\"]",NEXT_BUTTON:"[data-control=\"next\"]",PREVIOUS_BUTTON:"[data-control=\"previous\"]",DOTS_BUTTONS:"[data-dots]",BEGINNING_DOTS_BUTTON:"[data-dots=\"beginning\"]",ENDING_DOTS_BUTTON:"[data-dots=\"ending\"]"},h=function(a,b){return a.find(g.PAGE_ITEM+"[data-page-number=\""+b+"\"]")},i=function(a){return a.find(g.NEXT_BUTTON)},j=function(a,b){a.attr("data-last-page-number",b)},k=function(a){return parseInt(a.attr("data-last-page-number"),10)},l=function(a){return parseInt(a.attr("data-active-page-number"),10)},m=function(a,b){a.attr("data-active-page-number",b)},n=function(a){var b=l(a);return!isNaN(b)&&0!=b},o=function(a,b){if(b.attr("data-page")!=void 0){return parseInt(b.attr("data-page-number"),10)}var c=1,d=null;switch(b.attr("data-control")){case"first":c=1;break;case"last":c=k(a);break;case"next":d=l(a);var e=k(a);if(!e){c=d+1}else if(d&&d<e){c=d+1}else{c=e}break;case"previous":d=l(a);if(d&&1<d){c=d-1}else{c=1}break;default:c=1;break;}return parseInt(c,10)},p=function(a){return parseInt(a.attr("data-items-per-page"),10)},q=function(a,b){a.attr("data-items-per-page",b)},r=function(a){a.removeClass("hidden")},s=function(a){a.addClass("hidden")},t=function(a){var b=a.find(g.NEXT_BUTTON),c=a.find(g.LAST_BUTTON);b.addClass("disabled");b.attr("aria-disabled",!0);c.addClass("disabled");c.attr("aria-disabled",!0)},u=function(a){var b=a.find(g.NEXT_BUTTON),c=a.find(g.LAST_BUTTON);b.removeClass("disabled");b.removeAttr("aria-disabled");c.removeClass("disabled");c.removeAttr("aria-disabled")},v=function(a){var b=a.find(g.PREVIOUS_BUTTON),c=a.find(g.FIRST_BUTTON);b.addClass("disabled");b.attr("aria-disabled",!0);c.addClass("disabled");c.attr("aria-disabled",!0)},w=function(b){var c=l(b),d=k(b),e=b.find(g.DOTS_BUTTONS),f=b.find(g.BEGINNING_DOTS_BUTTON),h=b.find(g.ENDING_DOTS_BUTTON),i=b.find(g.PAGE),j=parseInt(b.attr("data-bar-size"),10);if(j&&d>j){var m=Math.max(c-Math.round(j/2),1),n=m+j-1;if(n>=d){n=d;m=n-j+1}if(1<m){r(f);m++}else{s(f)}if(n<d){r(h);n--}else{s(h)}e.addClass("disabled");e.attr("aria-disabled",!0);s(i);i.each(function(b,c){c=a(c);if(b+1>=m&&b+1<=n){r(c)}})}else{s(e)}},x=function(a){var b=a.find(g.PREVIOUS_BUTTON),c=a.find(g.FIRST_BUTTON);b.removeClass("disabled");b.removeAttr("aria-disabled");c.removeClass("disabled");c.removeAttr("aria-disabled")},y=function(a){var b=a.attr("data-aria-label-components-pagination-item"),c=b.split(",").map(function(a){return a.trim()});return c},z=function(a){var b=a.attr("data-aria-label-components-pagination-active-item"),c=b.split(",").map(function(a){return a.trim()});return c},A=function(b,c){var d=0;m(b,0);c.each(function(c,e){var f=c+1;e=a(e);e.attr("data-page-number",f);d++;if(e.hasClass("active")){m(b,f)}});j(b,d)},B=function(b){var c=y(b),e=z(b),f=l(b),h=b.find(g.PAGE_ITEM),i=h.map(function(d,g){g=a(g);var h=o(b,g);if(h===f){return{key:e[0],component:e[1],param:h}}else{return{key:c[0],component:c[1],param:h}}});d.get_strings(i).then(function(b){h.each(function(c,d){d=a(d);var e=b[c];d.attr("aria-label",e);d.find(g.PAGE_LINK).attr("aria-label",e)});return b}).catch(function(){})},C=function(a,b,d){var i=new f("core/paged_content_paging_bar:showPage"),j=k(a),n=b==l(a),o=p(a);if(!n){a.find(g.PAGE_ITEM).removeClass("active").removeAttr("aria-current");var q=h(a,b);q.addClass("active");q.attr("aria-current",!0);m(a,b);w(a)}if(j&&b>=j){t(a)}else{u(a)}if(1<b){x(a)}else{v(a)}B(a);e.publish(d+c.SHOW_PAGES,[{pageNumber:b,limit:o,offset:(b-1)*o}]);i.resolve()},D=function(d,f){var h=d.attr("data-ignore-control-while-loading"),i=!1;if(""==h){h=!0}b.define(d,[b.events.activate]);d.on(b.events.activate,g.PAGE_ITEM,function(b,c){c.originalEvent.preventDefault();c.originalEvent.stopPropagation();if(h&&i){return}var e=a(b.target).closest(g.PAGE_ITEM);if(!e.hasClass("disabled")){var j=o(d,e);C(d,j,f);i=!0}});e.subscribe(f+c.ALL_ITEMS_LOADED,function(a){i=!1;var b=k(d);if(!b||a<b){j(d,a)}if(1===a&&d.attr("data-hide-control-on-single-page")){s(d);t(d);v(d)}else{r(d);t(d)}});e.subscribe(f+c.PAGES_SHOWN,function(){i=!1});e.subscribe(f+c.SET_ITEMS_PER_PAGE_LIMIT,function(a){q(d,a);j(d,0);m(d,0);r(d);C(d,1,f)})};return{init:function init(b,c){b=a(b);var d=b.find(g.PAGE);A(b,d);D(b,c);if(n(b)){var e=l(b);h(b,e).click();if(1==e){v(b)}}else{i(b).click()}w(b)},disableNextControlButtons:t,enableNextControlButtons:u,disablePreviousControlButtons:v,enablePreviousControlButtons:x,showPage:C,rootSelector:g.ROOT}});
|
||||
//# sourceMappingURL=paged_content_paging_bar.min.js.map
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -26,14 +26,16 @@ define(
|
||||
'core/templates',
|
||||
'core/notification',
|
||||
'core/pubsub',
|
||||
'core/paged_content_events'
|
||||
'core/paged_content_events',
|
||||
'core/pending',
|
||||
],
|
||||
function(
|
||||
$,
|
||||
Templates,
|
||||
Notification,
|
||||
PubSub,
|
||||
PagedContentEvents
|
||||
PagedContentEvents,
|
||||
Pending
|
||||
) {
|
||||
|
||||
var SELECTORS = {
|
||||
@@ -74,6 +76,8 @@ define(
|
||||
var deferred = $.Deferred();
|
||||
root.attr('aria-busy', true);
|
||||
|
||||
var pendingPromise = new Pending('core/paged_content_pages:startLoading');
|
||||
|
||||
Templates.render(TEMPLATES.LOADING, {visible: true})
|
||||
.then(function(html) {
|
||||
var loadingSpinner = $(html);
|
||||
@@ -93,6 +97,8 @@ define(
|
||||
loadingSpinner.remove();
|
||||
root.css('position', '');
|
||||
root.removeAttr('aria-busy');
|
||||
|
||||
pendingPromise.resolve();
|
||||
return;
|
||||
});
|
||||
|
||||
@@ -182,6 +188,7 @@ define(
|
||||
* @param {function} renderPagesContentCallback Render pages content.
|
||||
*/
|
||||
var showPages = function(root, pagesData, id, renderPagesContentCallback) {
|
||||
var pendingPromise = new Pending('core/paged_content_pages:showPages');
|
||||
var existingPages = [];
|
||||
var newPageData = [];
|
||||
var newPagesPromise = $.Deferred();
|
||||
@@ -256,7 +263,9 @@ define(
|
||||
.fail(Notification.exception)
|
||||
.always(function() {
|
||||
loadingPromise.resolve();
|
||||
});
|
||||
pendingPromise.resolve();
|
||||
})
|
||||
.catch();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,14 +25,16 @@ define([
|
||||
'core/custom_interaction_events',
|
||||
'core/paged_content_events',
|
||||
'core/str',
|
||||
'core/pubsub'
|
||||
'core/pubsub',
|
||||
'core/pending',
|
||||
],
|
||||
function(
|
||||
$,
|
||||
CustomEvents,
|
||||
PagedContentEvents,
|
||||
Str,
|
||||
PubSub
|
||||
PubSub,
|
||||
Pending
|
||||
) {
|
||||
|
||||
var SELECTORS = {
|
||||
@@ -451,6 +453,7 @@ function(
|
||||
* @param {string} id A uniqie id for this instance.
|
||||
*/
|
||||
var showPage = function(root, pageNumber, id) {
|
||||
var pendingPromise = new Pending('core/paged_content_paging_bar:showPage');
|
||||
var lastPageNumber = getLastPageNumber(root);
|
||||
var isSamePage = pageNumber == getActivePageNumber(root);
|
||||
var limit = getLimit(root);
|
||||
@@ -492,6 +495,8 @@ function(
|
||||
limit: limit,
|
||||
offset: offset
|
||||
}]);
|
||||
|
||||
pendingPromise.resolve();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -108,7 +108,7 @@ class behat_core_generator extends behat_generator_base {
|
||||
'activities' => [
|
||||
'singular' => 'activity',
|
||||
'datagenerator' => 'activity',
|
||||
'required' => ['activity', 'idnumber', 'course'],
|
||||
'required' => ['activity', 'course'],
|
||||
'switchids' => ['course' => 'course', 'gradecategory' => 'gradecat', 'grouping' => 'groupingid'],
|
||||
],
|
||||
'blocks' => [
|
||||
@@ -377,6 +377,17 @@ class behat_core_generator extends behat_generator_base {
|
||||
}
|
||||
}
|
||||
|
||||
if (!array_key_exists('idnumber', $data)) {
|
||||
$data['idnumber'] = $data['name'];
|
||||
if (strlen($data['name']) > 100) {
|
||||
throw new Exception(
|
||||
"Activity '{$activityname}' cannot be used as the default idnumber. " .
|
||||
"The idnumber has a max length of 100 chars. " .
|
||||
"Please manually specify an idnumber."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// We split $data in the activity $record and the course module $options.
|
||||
$cmoptions = array();
|
||||
$cmcolumns = $DB->get_columns('course_modules');
|
||||
|
||||
@@ -368,6 +368,25 @@ abstract class behat_generator_base {
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the course cmid for the specified activity based on the activity's idnumber.
|
||||
*
|
||||
* Note: this does not check the module type, only the idnumber.
|
||||
*
|
||||
* @throws Exception
|
||||
* @param string $idnumber
|
||||
* @return int
|
||||
*/
|
||||
protected function get_activity_id(string $idnumber) {
|
||||
global $DB;
|
||||
|
||||
if (!$id = $DB->get_field('course_modules', 'id', ['idnumber' => $idnumber])) {
|
||||
throw new Exception('The specified activity with idnumber "' . $idnumber . '" could not be found.');
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the group id from it's idnumber.
|
||||
* @throws Exception
|
||||
@@ -512,4 +531,46 @@ abstract class behat_generator_base {
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a coursemodule from an activity name or idnumber.
|
||||
*
|
||||
* @param string $activity
|
||||
* @param string $identifier
|
||||
* @return cm_info
|
||||
*/
|
||||
protected function get_cm_by_activity_name(string $activity, string $identifier): cm_info {
|
||||
global $DB;
|
||||
|
||||
$coursetable = new \core\dml\table('course', 'c', 'c');
|
||||
$courseselect = $coursetable->get_field_select();
|
||||
$coursefrom = $coursetable->get_from_sql();
|
||||
|
||||
$cmtable = new \core\dml\table('course_modules', 'cm', 'cm');
|
||||
$cmfrom = $cmtable->get_from_sql();
|
||||
|
||||
$acttable = new \core\dml\table($activity, 'act', 'act');
|
||||
$actselect = $acttable->get_field_select();
|
||||
$actfrom = $acttable->get_from_sql();
|
||||
|
||||
$sql = <<<EOF
|
||||
SELECT cm.id as cmid, {$courseselect}, {$actselect}
|
||||
FROM {$cmfrom}
|
||||
INNER JOIN {$coursefrom} ON c.id = cm.course
|
||||
INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname
|
||||
INNER JOIN {$actfrom} ON cm.instance = act.id
|
||||
WHERE cm.idnumber = :idnumber OR act.name = :name
|
||||
EOF;
|
||||
|
||||
$result = $DB->get_record_sql($sql, [
|
||||
'modname' => $activity,
|
||||
'idnumber' => $identifier,
|
||||
'name' => $identifier,
|
||||
], MUST_EXIST);
|
||||
|
||||
$course = $coursetable->extract_from_result($result);
|
||||
$instancedata = $acttable->extract_from_result($result);
|
||||
|
||||
return get_fast_modinfo($course)->get_cm($result->cmid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1437,4 +1437,137 @@ EOF;
|
||||
$timeout = self::get_real_timeout(30) * 1000 * $factor;
|
||||
$driver->getWebDriver()->getCommandExecutor()->setRequestTimeout($timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the course category id from an identifier.
|
||||
*
|
||||
* The category idnumber, and name are checked.
|
||||
*
|
||||
* @param string $identifier
|
||||
* @return int|null
|
||||
*/
|
||||
protected function get_category_id(string $identifier): ?int {
|
||||
global $DB;
|
||||
|
||||
$sql = <<<EOF
|
||||
SELECT id
|
||||
FROM {course_categories}
|
||||
WHERE idnumber = :idnumber
|
||||
OR name = :name
|
||||
EOF;
|
||||
|
||||
$result = $DB->get_field_sql($sql, [
|
||||
'idnumber' => $identifier,
|
||||
'name' => $identifier,
|
||||
]);
|
||||
|
||||
return $result ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the course id from an identifier.
|
||||
*
|
||||
* The course idnumber, shortname, and fullname are checked.
|
||||
*
|
||||
* @param string $identifier
|
||||
* @return int|null
|
||||
*/
|
||||
protected function get_course_id(string $identifier): ?int {
|
||||
global $DB;
|
||||
|
||||
$sql = <<<EOF
|
||||
SELECT id
|
||||
FROM {course}
|
||||
WHERE idnumber = :idnumber
|
||||
OR shortname = :shortname
|
||||
OR fullname = :fullname
|
||||
EOF;
|
||||
|
||||
$result = $DB->get_field_sql($sql, [
|
||||
'idnumber' => $identifier,
|
||||
'shortname' => $identifier,
|
||||
'fullname' => $identifier,
|
||||
]);
|
||||
|
||||
return $result ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the activity course module id from its idnumber.
|
||||
*
|
||||
* Note: Only idnumber is supported here, not name at this time.
|
||||
*
|
||||
* @param string $identifier
|
||||
* @return cm_info|null
|
||||
*/
|
||||
protected function get_course_module_for_identifier(string $identifier): ?cm_info {
|
||||
global $DB;
|
||||
|
||||
$coursetable = new \core\dml\table('course', 'c', 'c');
|
||||
$courseselect = $coursetable->get_field_select();
|
||||
$coursefrom = $coursetable->get_from_sql();
|
||||
|
||||
$cmtable = new \core\dml\table('course_modules', 'cm', 'cm');
|
||||
$cmfrom = $cmtable->get_from_sql();
|
||||
|
||||
$sql = <<<EOF
|
||||
SELECT {$courseselect}, cm.id as cmid
|
||||
FROM {$cmfrom}
|
||||
INNER JOIN {$coursefrom} ON c.id = cm.course
|
||||
WHERE cm.idnumber = :idnumber
|
||||
EOF;
|
||||
|
||||
$result = $DB->get_record_sql($sql, [
|
||||
'idnumber' => $identifier,
|
||||
]);
|
||||
|
||||
if ($result) {
|
||||
$course = $coursetable->extract_from_result($result);
|
||||
return get_fast_modinfo($course)->get_cm($result->cmid);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a coursemodule from an activity name or idnumber.
|
||||
*
|
||||
* @param string $activity
|
||||
* @param string $identifier
|
||||
* @return cm_info
|
||||
*/
|
||||
protected function get_cm_by_activity_name(string $activity, string $identifier): cm_info {
|
||||
global $DB;
|
||||
|
||||
$coursetable = new \core\dml\table('course', 'c', 'c');
|
||||
$courseselect = $coursetable->get_field_select();
|
||||
$coursefrom = $coursetable->get_from_sql();
|
||||
|
||||
$cmtable = new \core\dml\table('course_modules', 'cm', 'cm');
|
||||
$cmfrom = $cmtable->get_from_sql();
|
||||
|
||||
$acttable = new \core\dml\table($activity, 'act', 'act');
|
||||
$actselect = $acttable->get_field_select();
|
||||
$actfrom = $acttable->get_from_sql();
|
||||
|
||||
$sql = <<<EOF
|
||||
SELECT cm.id as cmid, {$courseselect}, {$actselect}
|
||||
FROM {$cmfrom}
|
||||
INNER JOIN {$coursefrom} ON c.id = cm.course
|
||||
INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname
|
||||
INNER JOIN {$actfrom} ON cm.instance = act.id
|
||||
WHERE cm.idnumber = :idnumber OR act.name = :name
|
||||
EOF;
|
||||
|
||||
$result = $DB->get_record_sql($sql, [
|
||||
'modname' => $activity,
|
||||
'idnumber' => $identifier,
|
||||
'name' => $identifier,
|
||||
], MUST_EXIST);
|
||||
|
||||
$course = $coursetable->extract_from_result($result);
|
||||
$instancedata = $acttable->extract_from_result($result);
|
||||
|
||||
return get_fast_modinfo($course)->get_cm($result->cmid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,8 @@ class dataformat {
|
||||
* @param string $dataformat
|
||||
* @param array $columns
|
||||
* @param Iterable $iterator
|
||||
* @param callable|null $callback
|
||||
* @param callable|null $callback Optional callback method to apply to each record prior to writing, which accepts two
|
||||
* parameters as such: function($record, bool $supportshtml) returning formatted record
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public static function download_data(string $filename, string $dataformat, array $columns, Iterable $iterator,
|
||||
@@ -89,7 +90,7 @@ class dataformat {
|
||||
$rownum = 0;
|
||||
foreach ($iterator as $row) {
|
||||
if (is_callable($callback)) {
|
||||
$row = $callback($row);
|
||||
$row = $callback($row, $format->supports_html());
|
||||
}
|
||||
if ($row === null) {
|
||||
continue;
|
||||
@@ -131,7 +132,7 @@ class dataformat {
|
||||
$rownum = 0;
|
||||
foreach ($iterator as $row) {
|
||||
if (is_callable($callback)) {
|
||||
$row = $callback($row);
|
||||
$row = $callback($row, $format->supports_html());
|
||||
}
|
||||
if ($row === null) {
|
||||
continue;
|
||||
|
||||
@@ -55,14 +55,20 @@ class curl_security_helper extends curl_security_helper_base {
|
||||
];
|
||||
|
||||
/**
|
||||
* Checks whether the given URL is blacklisted by checking its address and port number against the black/white lists.
|
||||
* Checks whether the given URL is blocked by checking its address and port number against the block/allow lists.
|
||||
* The behaviour of this function can be classified as strict, as it returns true for URLs which are invalid or
|
||||
* could not be parsed, as well as those valid URLs which were found in the blacklist.
|
||||
* could not be parsed, as well as those valid URLs which were found in the list of blocked ones.
|
||||
*
|
||||
* @param string $urlstring the URL to check.
|
||||
* @return bool true if the URL is blacklisted or invalid and false if the URL is not blacklisted.
|
||||
* @param int $notused There used to be an optional parameter $maxredirects for a short while here, not used any more.
|
||||
* @return bool true if the URL is blocked or invalid and false if the URL is not blocked.
|
||||
*/
|
||||
public function url_is_blocked($urlstring) {
|
||||
public function url_is_blocked($urlstring, $notused = null) {
|
||||
|
||||
if ($notused !== null) {
|
||||
debugging('The $maxredirects parameter of curl_security_helper::url_is_blocked() has been dropped!', DEBUG_DEVELOPER);
|
||||
}
|
||||
|
||||
// If no config data is present, then all hosts/ports are allowed.
|
||||
if (!$this->is_enabled()) {
|
||||
return false;
|
||||
@@ -85,7 +91,7 @@ class curl_security_helper extends curl_security_helper_base {
|
||||
}
|
||||
|
||||
if ($parsed['port'] && $parsed['host']) {
|
||||
// Check the host and port against the blacklist/whitelist entries.
|
||||
// Check the host and port against the allow/block entries.
|
||||
return $this->host_is_blocked($parsed['host']) || $this->port_is_blocked($parsed['port']);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -186,10 +186,18 @@ class manager {
|
||||
$localisedeventdata->fullmessage = $eventdata->fullmessage;
|
||||
$localisedeventdata->fullmessagehtml = $eventdata->fullmessagehtml;
|
||||
if (!empty($localisedeventdata->fullmessage)) {
|
||||
// Prevent unclosed HTML elements.
|
||||
$localisedeventdata->fullmessage =
|
||||
\core_message\helper::prevent_unclosed_html_tags($localisedeventdata->fullmessage, true);
|
||||
|
||||
$localisedeventdata->fullmessage .= "\n\n---------------------------------------------------------------------\n"
|
||||
. $emailtagline;
|
||||
}
|
||||
if (!empty($localisedeventdata->fullmessagehtml)) {
|
||||
// Prevent unclosed HTML elements.
|
||||
$localisedeventdata->fullmessagehtml =
|
||||
\core_message\helper::prevent_unclosed_html_tags($localisedeventdata->fullmessagehtml, true);
|
||||
|
||||
$localisedeventdata->fullmessagehtml .=
|
||||
"<br><br>---------------------------------------------------------------------<br>" . $emailtagline;
|
||||
}
|
||||
|
||||
@@ -21,11 +21,8 @@ Feature: Add h5ps to Atto
|
||||
|
||||
@javascript @external
|
||||
Scenario: Insert an embedded h5p
|
||||
Given I log in as "admin"
|
||||
And I change window size to "large"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
Given I change window size to "large"
|
||||
And I am on the PageName1 "page activity editing" page logged in as admin
|
||||
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
|
||||
And I set the field with xpath "//input[@data-region='h5pfile']" to "https://moodle.h5p.com/content/1290772960722742119"
|
||||
And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue"
|
||||
@@ -42,9 +39,7 @@ Feature: Add h5ps to Atto
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/guess-the-answer.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the PageName1 "page activity editing" page
|
||||
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
|
||||
And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
|
||||
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
|
||||
@@ -57,11 +52,8 @@ Feature: Add h5ps to Atto
|
||||
|
||||
@javascript
|
||||
Scenario: Test an invalid url
|
||||
Given I log in as "admin"
|
||||
And I change window size to "large"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
Given I change window size to "large"
|
||||
And I am on the PageName1 "page activity editing" page logged in as admin
|
||||
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
|
||||
# This is not a real external URL, so this scenario shouldn't be labeled as external.
|
||||
And I set the field with xpath "//input[@data-region='h5pfile']" to "ftp://moodle.h5p.com/content/1290772960722742119"
|
||||
@@ -75,10 +67,7 @@ Feature: Add h5ps to Atto
|
||||
| capability | permission | role | contextlevel | reference |
|
||||
| atto/h5p:addembed | Prohibit | editingteacher | Course | C1 |
|
||||
| moodle/h5p:deploy | Prohibit | editingteacher | Course | C1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
When I navigate to "Edit settings" in current page administration
|
||||
When I am on the PageName1 "page activity editing" page logged in as teacher1
|
||||
Then "Insert H5P" "button" should not exist
|
||||
|
||||
@javascript
|
||||
@@ -86,10 +75,7 @@ Feature: Add h5ps to Atto
|
||||
Given the following "permission overrides" exist:
|
||||
| capability | permission | role | contextlevel | reference |
|
||||
| atto/h5p:addembed | Prohibit | editingteacher | Course | C1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
When I navigate to "Edit settings" in current page administration
|
||||
And I am on the PageName1 "page activity editing" page logged in as teacher1
|
||||
And I click on "Insert H5P" "button"
|
||||
Then I should not see "H5P URL" in the "Insert H5P" "dialogue"
|
||||
And I should see "H5P file upload" in the "Insert H5P" "dialogue"
|
||||
@@ -100,10 +86,7 @@ Feature: Add h5ps to Atto
|
||||
Given the following "permission overrides" exist:
|
||||
| capability | permission | role | contextlevel | reference |
|
||||
| moodle/h5p:deploy | Prohibit | editingteacher | Course | C1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
When I navigate to "Edit settings" in current page administration
|
||||
When I am on the PageName1 "page activity editing" page logged in as teacher1
|
||||
And I click on "Insert H5P" "button"
|
||||
Then I should not see "H5P file upload" in the "Insert H5P" "dialogue"
|
||||
And I should see "H5P URL" in the "Insert H5P" "dialogue"
|
||||
@@ -115,9 +98,7 @@ Feature: Add h5ps to Atto
|
||||
And I follow "Manage private files..."
|
||||
And I upload "lib/editor/atto/tests/fixtures/drag.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the PageName1 "page activity editing" page
|
||||
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
|
||||
# H5P file content
|
||||
And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
|
||||
@@ -151,9 +132,7 @@ Feature: Add h5ps to Atto
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/guess-the-answer.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the PageName1 "page activity editing" page
|
||||
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
|
||||
And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
|
||||
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
|
||||
@@ -205,22 +184,17 @@ Feature: Add h5ps to Atto
|
||||
|
||||
@javascript @external
|
||||
Scenario: H5P options are ignored for H5P URLs
|
||||
Given I log in as "admin"
|
||||
And I change window size to "large"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
Given I change window size to "large"
|
||||
And I am on the PageName1 "page activity editing" page logged in as admin
|
||||
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
|
||||
And I set the field with xpath "//input[@data-region='h5pfile']" to "https://moodle.h5p.com/content/1290752078589054689"
|
||||
And I set the field with xpath "//input[@data-region='h5pfile']" to "https://moodle.h5p.com/content/1291366510035871129"
|
||||
And I click on "H5P options" "link"
|
||||
And I click on "Embed button" "checkbox"
|
||||
And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue"
|
||||
And I wait until the page is ready
|
||||
When I click on "Save and display" "button"
|
||||
Then ".h5p-placeholder" "css_element" should exist
|
||||
And I wait until the page is ready
|
||||
And I switch to "h5pcontent" iframe
|
||||
And I should see "History of strawberries"
|
||||
And I should see "Far far away"
|
||||
And I should not see "Embed"
|
||||
And I switch to the main frame
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
@@ -241,9 +215,7 @@ Feature: Add h5ps to Atto
|
||||
And I follow "Manage private files..."
|
||||
And I upload "h5p/tests/fixtures/guess-the-answer.h5p" file to "Files" filemanager
|
||||
And I click on "Save changes" "button"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the PageName1 "page activity editing" page
|
||||
And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
|
||||
And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
|
||||
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
|
||||
@@ -253,9 +225,7 @@ Feature: Add h5ps to Atto
|
||||
And I wait until the page is ready
|
||||
And I click on "Save and display" "button"
|
||||
And I log out
|
||||
When I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "PageName1"
|
||||
When I am on the PageName1 "page activity" page logged in as student1
|
||||
Then I switch to "h5pcontent" iframe
|
||||
And I switch to "h5p-iframe" class iframe
|
||||
And I should see "reveal"
|
||||
|
||||
+52
-12
@@ -567,6 +567,11 @@ function enrol_get_my_courses($fields = null, $sort = null, $limit = 0, $coursei
|
||||
$offset = 0, $excludecourses = []) {
|
||||
global $DB, $USER, $CFG;
|
||||
|
||||
// Allowed prefixes and field names.
|
||||
$allowedprefixesandfields = ['c' => array_keys($DB->get_columns('course')),
|
||||
'ul' => array_keys($DB->get_columns('user_lastaccess')),
|
||||
'ue' => array_keys($DB->get_columns('user_enrolments'))];
|
||||
|
||||
// Re-Arrange the course sorting according to the admin settings.
|
||||
$sort = enrol_get_courses_sortingsql($sort);
|
||||
|
||||
@@ -599,28 +604,63 @@ function enrol_get_my_courses($fields = null, $sort = null, $limit = 0, $coursei
|
||||
$orderby = "";
|
||||
$sort = trim($sort);
|
||||
$sorttimeaccess = false;
|
||||
$allowedsortprefixes = array('c', 'ul', 'ue');
|
||||
if (!empty($sort)) {
|
||||
$rawsorts = explode(',', $sort);
|
||||
$sorts = array();
|
||||
foreach ($rawsorts as $rawsort) {
|
||||
$rawsort = trim($rawsort);
|
||||
if (preg_match('/^ul\.(\S*)\s(asc|desc)/i', $rawsort, $matches)) {
|
||||
if (strcasecmp($matches[2], 'asc') == 0) {
|
||||
$sorts[] = 'COALESCE(ul.' . $matches[1] . ', 0) ASC';
|
||||
} else {
|
||||
$sorts[] = 'COALESCE(ul.' . $matches[1] . ', 0) DESC';
|
||||
// Make sure that there are no more white spaces in sortparams after explode.
|
||||
$sortparams = array_values(array_filter(explode(' ', $rawsort)));
|
||||
// If more than 2 values present then throw coding_exception.
|
||||
if (isset($sortparams[2])) {
|
||||
throw new coding_exception('Invalid $sort parameter in enrol_get_my_courses()');
|
||||
}
|
||||
// Check the sort ordering if present, at the beginning.
|
||||
if (isset($sortparams[1]) && (preg_match("/^(asc|desc)$/i", $sortparams[1]) === 0)) {
|
||||
throw new coding_exception('Invalid sort direction in $sort parameter in enrol_get_my_courses()');
|
||||
}
|
||||
|
||||
$sortfield = $sortparams[0];
|
||||
$sortdirection = $sortparams[1] ?? 'asc';
|
||||
if (strpos($sortfield, '.') !== false) {
|
||||
$sortfieldparams = explode('.', $sortfield);
|
||||
// Check if more than one dots present in the prefix field.
|
||||
if (isset($sortfieldparams[2])) {
|
||||
throw new coding_exception('Invalid $sort parameter in enrol_get_my_courses()');
|
||||
}
|
||||
$sorttimeaccess = true;
|
||||
} else if (strpos($rawsort, '.') !== false) {
|
||||
$prefix = explode('.', $rawsort);
|
||||
if (in_array($prefix[0], $allowedsortprefixes)) {
|
||||
$sorts[] = trim($rawsort);
|
||||
list($prefix, $fieldname) = [$sortfieldparams[0], $sortfieldparams[1]];
|
||||
// Check if the field name matches with the allowed prefix.
|
||||
if (array_key_exists($prefix, $allowedprefixesandfields) &&
|
||||
(in_array($fieldname, $allowedprefixesandfields[$prefix]))) {
|
||||
if ($prefix === 'ul') {
|
||||
$sorts[] = "COALESCE({$prefix}.{$fieldname}, 0) {$sortdirection}";
|
||||
$sorttimeaccess = true;
|
||||
} else {
|
||||
// Check if the field name that matches with the prefix and just append to sorts.
|
||||
$sorts[] = $rawsort;
|
||||
}
|
||||
} else {
|
||||
throw new coding_exception('Invalid $sort parameter in enrol_get_my_courses()');
|
||||
}
|
||||
} else {
|
||||
$sorts[] = 'c.'.trim($rawsort);
|
||||
// Check if the field name matches with $allowedprefixesandfields.
|
||||
$found = false;
|
||||
foreach (array_keys($allowedprefixesandfields) as $prefix) {
|
||||
if (in_array($sortfield, $allowedprefixesandfields[$prefix])) {
|
||||
if ($prefix === 'ul') {
|
||||
$sorts[] = "COALESCE({$prefix}.{$sortfield}, 0) {$sortdirection}";
|
||||
$sorttimeaccess = true;
|
||||
} else {
|
||||
$sorts[] = "{$prefix}.{$sortfield} {$sortdirection}";
|
||||
}
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
// The param is not found in $allowedprefixesandfields.
|
||||
throw new coding_exception('Invalid $sort parameter in enrol_get_my_courses()');
|
||||
}
|
||||
}
|
||||
}
|
||||
$sort = implode(',', $sorts);
|
||||
|
||||
+35
-16
@@ -3063,7 +3063,7 @@ class curl {
|
||||
public $error;
|
||||
/** @var int error code */
|
||||
public $errno;
|
||||
/** @var bool use workaround for open_basedir restrictions, to be changed from unit tests only! */
|
||||
/** @var bool Perform redirects at PHP level instead of relying on native cURL functionality. Always true now. */
|
||||
public $emulateredirects = null;
|
||||
|
||||
/** @var array cURL options */
|
||||
@@ -3160,9 +3160,13 @@ class curl {
|
||||
$this->proxy = false;
|
||||
}
|
||||
|
||||
if (!isset($this->emulateredirects)) {
|
||||
$this->emulateredirects = ini_get('open_basedir');
|
||||
}
|
||||
// All redirects are performed at PHP level now and each one is checked against blocked URLs rules. We do not
|
||||
// want to let cURL naively follow the redirect chain and visit every URL for security reasons. Even when the
|
||||
// caller explicitly wants to ignore the security checks, we would need to fall back to the original
|
||||
// implementation and use emulated redirects if open_basedir is in effect to avoid the PHP warning
|
||||
// "CURLOPT_FOLLOWLOCATION cannot be activated when in safe_mode or an open_basedir". So it is better to simply
|
||||
// ignore this property and always handle redirects at this PHP wrapper level and not inside the native cURL.
|
||||
$this->emulateredirects = true;
|
||||
|
||||
// Curl security setup. Allow injection of a security helper, but if not found, default to the core helper.
|
||||
if (isset($settings['securityhelper']) && $settings['securityhelper'] instanceof \core\files\curl_security_helper_base) {
|
||||
@@ -3471,8 +3475,8 @@ class curl {
|
||||
|
||||
// Set options.
|
||||
foreach($this->options as $name => $val) {
|
||||
if ($name === 'CURLOPT_FOLLOWLOCATION' and $this->emulateredirects) {
|
||||
// The redirects are emulated elsewhere.
|
||||
if ($name === 'CURLOPT_FOLLOWLOCATION') {
|
||||
// All the redirects are emulated at PHP level.
|
||||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 0);
|
||||
continue;
|
||||
}
|
||||
@@ -3644,8 +3648,12 @@ class curl {
|
||||
}
|
||||
}
|
||||
|
||||
// If curl security is enabled, check the URL against the blacklist before calling curl_exec.
|
||||
// Note: This will only check the base url. In the case of redirects, the blacklist is also after the curl_exec.
|
||||
if (empty($this->emulateredirects)) {
|
||||
// Just in case someone had tried to explicitly disable emulated redirects in legacy code.
|
||||
debugging('Attempting to disable emulated redirects has no effect any more!', DEBUG_DEVELOPER);
|
||||
}
|
||||
|
||||
// If curl security is enabled, check the URL against the list of blocked URLs before calling the first curl_exec.
|
||||
if (!$this->ignoresecurity && $this->securityhelper->url_is_blocked($url)) {
|
||||
$this->error = $this->securityhelper->get_blocked_url_string();
|
||||
return $this->error;
|
||||
@@ -3668,16 +3676,14 @@ class curl {
|
||||
$this->errno = curl_errno($curl);
|
||||
// Note: $this->response and $this->rawresponse are filled by $hits->formatHeader callback.
|
||||
|
||||
// In the case of redirects (which curl blindly follows), check the post-redirect URL against the blacklist entries too.
|
||||
if (intval($this->info['redirect_count']) > 0 && !$this->ignoresecurity
|
||||
&& $this->securityhelper->url_is_blocked($this->info['url'])) {
|
||||
$this->reset_request_state_vars();
|
||||
$this->error = $this->securityhelper->get_blocked_url_string();
|
||||
curl_close($curl);
|
||||
return $this->error;
|
||||
if (intval($this->info['redirect_count']) > 0) {
|
||||
// For security reasons we do not allow the cURL handle to follow redirects on its own.
|
||||
// See setting CURLOPT_FOLLOWLOCATION in {@see self::apply_opt()} method.
|
||||
throw new coding_exception('Internal cURL handle should never follow redirects on its own!',
|
||||
'Reported number of redirects: ' . $this->info['redirect_count']);
|
||||
}
|
||||
|
||||
if ($this->emulateredirects and $this->options['CURLOPT_FOLLOWLOCATION'] and $this->info['http_code'] != 200) {
|
||||
if ($this->options['CURLOPT_FOLLOWLOCATION'] && $this->info['http_code'] != 200) {
|
||||
$redirects = 0;
|
||||
|
||||
while($redirects <= $this->options['CURLOPT_MAXREDIRS']) {
|
||||
@@ -3711,6 +3717,12 @@ class curl {
|
||||
if (isset($this->info['redirect_url'])) {
|
||||
if (preg_match('|^https?://|i', $this->info['redirect_url'])) {
|
||||
$redirecturl = $this->info['redirect_url'];
|
||||
} else {
|
||||
// Emulate CURLOPT_REDIR_PROTOCOLS behaviour which we have set to (CURLPROTO_HTTP | CURLPROTO_HTTPS) only.
|
||||
$this->errno = CURLE_UNSUPPORTED_PROTOCOL;
|
||||
$this->error = 'Redirect to a URL with unsuported protocol: ' . $this->info['redirect_url'];
|
||||
curl_close($curl);
|
||||
return $this->error;
|
||||
}
|
||||
}
|
||||
if (!$redirecturl) {
|
||||
@@ -3740,6 +3752,13 @@ class curl {
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->ignoresecurity && $this->securityhelper->url_is_blocked($redirecturl)) {
|
||||
$this->reset_request_state_vars();
|
||||
$this->error = $this->securityhelper->get_blocked_url_string();
|
||||
curl_close($curl);
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
curl_setopt($curl, CURLOPT_URL, $redirecturl);
|
||||
$ret = curl_exec($curl);
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class behat_core_form extends behat_question_base {
|
||||
* @throws Exception with a meaningful error message if the specified page cannot be found.
|
||||
*/
|
||||
protected function resolve_page_url(string $page): moodle_url {
|
||||
switch ($page) {
|
||||
switch (strtolower($page)) {
|
||||
default:
|
||||
throw new Exception('Unrecognised core_form page type "' . $page . '."');
|
||||
}
|
||||
@@ -70,8 +70,8 @@ class behat_core_form extends behat_question_base {
|
||||
* @throws Exception with a meaningful error message if the specified page cannot be found.
|
||||
*/
|
||||
protected function resolve_page_instance_url(string $type, string $identifier): moodle_url {
|
||||
switch ($type) {
|
||||
case 'Fixture':
|
||||
switch (strtolower($type)) {
|
||||
case 'fixture':
|
||||
return new moodle_url('/lib/form/tests/fixtures/' .
|
||||
clean_param($identifier, PARAM_ALPHAEXT) . '.php');
|
||||
|
||||
|
||||
@@ -31,18 +31,19 @@ Feature: Using the activity grade form element
|
||||
| Scale | Disappointing, Good, Very good, Excellent |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| forum | Test forum name | Test forum description | C1 | forum1 |
|
||||
And I am on the "Test forum name" "forum activity editing" page logged in as teacher1
|
||||
And I set the following fields to these values:
|
||||
| Forum type | Standard forum for general use |
|
||||
| Description | Test forum description |
|
||||
| Aggregate type | Average of ratings |
|
||||
| scale[modgrade_type] | Point |
|
||||
| scale[modgrade_point] | 100 |
|
||||
| Group mode | No groups |
|
||||
And I follow "Test forum name"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test forum name" "forum activity editing" page
|
||||
When I expand all fieldsets
|
||||
Then I should not see "Some grades have already been awarded, so the grade type"
|
||||
And I set the field "scale[modgrade_type]" to "Scale"
|
||||
@@ -89,21 +90,17 @@ Feature: Using the activity grade form element
|
||||
| scale[modgrade_scale] | ABCDEF |
|
||||
| Group mode | No groups |
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test forum name"
|
||||
And I am on the "Test forum name" "forum activity" page logged in as student1
|
||||
And I click on "Add a new discussion topic" "link"
|
||||
And I set the following fields to these values:
|
||||
| Subject | Discussion subject |
|
||||
| Message | Discussion message |
|
||||
And I press "Post to forum"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test forum name"
|
||||
And I am on the "Test forum name" "forum activity" page logged in as teacher1
|
||||
And I follow "Discussion subject"
|
||||
And I set the field "rating" to "D"
|
||||
And I follow "Test forum name"
|
||||
And I am on the "Test forum name" "forum activity" page
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
When I expand all fieldsets
|
||||
Then I should see "Some grades have already been awarded, so the grade type and scale cannot be changed"
|
||||
@@ -138,8 +135,7 @@ Feature: Using the activity grade form element
|
||||
| Description | Test assignment description |
|
||||
| grade[modgrade_type] | Scale |
|
||||
| grade[modgrade_scale] | ABCDEF |
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I am on the "Test assignment name" "assign activity" page
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
And I set the field "Grade" to "C"
|
||||
@@ -156,33 +152,30 @@ Feature: Using the activity grade form element
|
||||
And the field "grade[modgrade_scale]" matches value "ABCDEF"
|
||||
|
||||
Scenario: Attempting to change the maximum grade when ratings exist
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name |
|
||||
Given the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | section |
|
||||
| forum | Test forum name | Test forum description | C1 | forum1 | 1 |
|
||||
And I am on the "Test forum name" "forum activity editing" page logged in as teacher1
|
||||
And I set the following fields to these values:
|
||||
| Forum type | Standard forum for general use |
|
||||
| Description | Test forum description |
|
||||
| Aggregate type | Average of ratings |
|
||||
| scale[modgrade_type] | Point |
|
||||
| scale[modgrade_point] | 100 |
|
||||
| Group mode | No groups |
|
||||
And I press "Save and return to course"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test forum name"
|
||||
And I am on the "Test forum name" "forum activity" page logged in as student1
|
||||
And I click on "Add a new discussion topic" "link"
|
||||
And I set the following fields to these values:
|
||||
| Subject | Discussion subject |
|
||||
| Message | Discussion message |
|
||||
And I press "Post to forum"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test forum name"
|
||||
And I am on the "Test forum name" "forum activity" page logged in as teacher1
|
||||
And I follow "Discussion subject"
|
||||
And I set the field "rating" to "100"
|
||||
And I press "Rate"
|
||||
And I follow "Test forum name"
|
||||
And I am on the "Test forum name" "forum activity" page
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
When I expand all fieldsets
|
||||
Then I should see "You cannot change the type, as grades already exist for this item."
|
||||
@@ -192,13 +185,11 @@ Feature: Using the activity grade form element
|
||||
|
||||
@javascript
|
||||
Scenario: Attempting to change the maximum grade when no rescaling option has been chosen
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment name |
|
||||
| Description | Test assignment description |
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
Given the following "activity" exists:
|
||||
| course | C1 |
|
||||
| activity | assign |
|
||||
| name | Test assign name |
|
||||
And I am on the "Test assign name" "assign activity" page logged in as teacher1
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
And I set the field "Grade out of 100" to "50"
|
||||
|
||||
@@ -6546,7 +6546,6 @@ function send_confirmation_email($user, $confirmationurl = null) {
|
||||
$supportuser = core_user::get_support_user();
|
||||
|
||||
$data = new stdClass();
|
||||
$data->firstname = fullname($user);
|
||||
$data->sitename = format_string($site->fullname);
|
||||
$data->admin = generate_email_signoff();
|
||||
|
||||
|
||||
@@ -57,4 +57,33 @@ abstract class component_generator_base {
|
||||
*/
|
||||
public function reset() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current user during data generation.
|
||||
*
|
||||
* This should be avoided wherever possible, but in some situations underlying code will insert data as the current
|
||||
* user.
|
||||
*
|
||||
* @param stdClass $user
|
||||
*/
|
||||
protected function set_user(?stdClass $user = null): void {
|
||||
global $CFG, $DB;
|
||||
|
||||
if ($user === null) {
|
||||
$user = (object) [
|
||||
'id' => 0,
|
||||
'mnethostid' => $CFG->mnet_localhost_id,
|
||||
];
|
||||
} else {
|
||||
$user = clone($user);
|
||||
unset($user->description);
|
||||
unset($user->access);
|
||||
unset($user->preference);
|
||||
}
|
||||
|
||||
// Ensure session is empty, as it may contain caches and user-specific info.
|
||||
\core\session\manager::init_empty_session();
|
||||
|
||||
\core\session\manager::set_user($user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,9 @@ EOD;
|
||||
* @return component_generator_base or rather an instance of the appropriate subclass.
|
||||
*/
|
||||
public function get_plugin_generator($component) {
|
||||
// Note: This global is included so that generator have access to it.
|
||||
// CFG is widely used in require statements.
|
||||
global $CFG;
|
||||
list($type, $plugin) = core_component::normalize_component($component);
|
||||
$cleancomponent = $type . '_' . $plugin;
|
||||
if ($cleancomponent != $component) {
|
||||
|
||||
@@ -240,8 +240,7 @@ Feature: Initials bar
|
||||
Given the following "activities" exist:
|
||||
| activity | course | idnumber | name | intro | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled |
|
||||
| assign | C1 | assign1 | TestAssignment | Test assignment description | 0 | 0 |
|
||||
And I am on the "assign1" "Activity" page logged in as "admin"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "assign1" "assign Activity editing" page logged in as "admin"
|
||||
And I expand all fieldsets
|
||||
And I set the field "Completion tracking" to "1"
|
||||
And I click on "Save and return to course" "button"
|
||||
|
||||
@@ -543,7 +543,9 @@ class behat_navigation extends behat_base {
|
||||
*
|
||||
* For pages belonging to core, the 'core > ' bit is omitted.
|
||||
*
|
||||
* @When I am on the :page page
|
||||
* @When /^I am on the (?<page>[^ "]*) page$/
|
||||
* @When /^I am on the "(?<page>[^"]*)" page$/
|
||||
*
|
||||
* @param string $page the component and page name.
|
||||
* E.g. 'Admin notifications' or 'core_user > Preferences'.
|
||||
* @throws Exception if the specified page cannot be determined.
|
||||
@@ -561,7 +563,11 @@ class behat_navigation extends behat_base {
|
||||
* but with the advantage that you go straight to the desired page, without
|
||||
* having to wait for the Dashboard to load.
|
||||
*
|
||||
* @When I am on the :page page logged in as :username
|
||||
* @When /^I am on the (?<page>[^ "]*) page logged in as (?<username>[^ "]*)$/
|
||||
* @When /^I am on the "(?<page>[^"]*)" page logged in as (?<username>[^ "]*)$/
|
||||
* @When /^I am on the (?<page>[^ "]*) page logged in as "(?<username>[^ "]*)"$/
|
||||
* @When /^I am on the "(?<page>[^"]*)" page logged in as "(?<username>[^ "]*)"$/
|
||||
*
|
||||
* @param string $page the type of page. E.g. 'Admin notifications' or 'core_user > Preferences'.
|
||||
* @param string $username the name of the user to log in as. E.g. 'admin'.
|
||||
* @throws Exception if the specified page cannot be determined.
|
||||
@@ -622,7 +628,11 @@ class behat_navigation extends behat_base {
|
||||
*
|
||||
* For pages belonging to core, the 'core > ' bit is omitted.
|
||||
*
|
||||
* @When I am on the :identifier :type page
|
||||
* @When /^I am on the (?<identifier>[^ "]*) (?<type>[^ "]*) page$/
|
||||
* @When /^I am on the "(?<identifier>[^"]*)" "(?<type>[^"]*)" page$/
|
||||
* @When /^I am on the (?<identifier>[^ "]*) "(?<type>[^"]*)" page$/
|
||||
* @When /^I am on the "(?<identifier>[^"]*)" (?<type>[^ "]*) page$/
|
||||
*
|
||||
* @param string $identifier identifies the particular page. E.g. 'Test quiz'.
|
||||
* @param string $type the component and page type. E.g. 'mod_quiz > View'.
|
||||
* @throws Exception if the specified page cannot be determined.
|
||||
@@ -640,7 +650,15 @@ class behat_navigation extends behat_base {
|
||||
* but with the advantage that you go straight to the desired page, without
|
||||
* having to wait for the Dashboard to load.
|
||||
*
|
||||
* @When I am on the :identifier :type page logged in as :username
|
||||
* @When /^I am on the (?<identifier>[^ "]*) (?<type>[^ "]*) page logged in as (?<username>[^ "]*)$/
|
||||
* @When /^I am on the "(?<identifier>[^"]*)" "(?<type>[^"]*)" page logged in as (?<username>[^ "]*)$/
|
||||
* @When /^I am on the (?<identifier>[^ "]*) "(?<type>[^"]*)" page logged in as (?<username>[^ "]*)$/
|
||||
* @When /^I am on the "(?<identifier>[^"]*)" (?<type>[^ "]*) page logged in as (?<username>[^ "]*)$/
|
||||
* @When /^I am on the (?<identifier>[^ "]*) (?<type>[^ "]*) page logged in as "(?<username>[^"]*)"$/
|
||||
* @When /^I am on the "(?<identifier>[^"]*)" "(?<type>[^"]*)" page logged in as "(?<username>[^"]*)"$/
|
||||
* @When /^I am on the (?<identifier>[^ "]*) "(?<type>[^"]*)" page logged in as "(?<username>[^"]*)"$/
|
||||
* @When /^I am on the "(?<identifier>[^"]*)" (?<type>[^ "]*) page logged in as "(?<username>[^"]*)"$/
|
||||
*
|
||||
* @param string $identifier identifies the particular page. E.g. 'Test quiz'.
|
||||
* @param string $type the component and page type. E.g. 'mod_quiz > View'.
|
||||
* @param string $username the name of the user to log in as. E.g. 'student'.
|
||||
@@ -697,10 +715,17 @@ class behat_navigation extends behat_base {
|
||||
* Convert page names to URLs for steps like 'When I am on the "[identifier]" "[page type]" page'.
|
||||
*
|
||||
* Recognised page names are:
|
||||
* | Page type | Identifier meaning | description |
|
||||
* | Category page | category idnumber | List of courses in that category. |
|
||||
* | Course | course shortname | Main course home pag |
|
||||
* | Activity | activity idnumber | Start page for that activity |
|
||||
* | Page type | Identifier meaning | description |
|
||||
* | Category | category idnumber | List of courses in that category. |
|
||||
* | Course | course shortname | Main course home pag |
|
||||
* | Activity | activity idnumber | Start page for that activity |
|
||||
* | Activity editing | activity idnumber | Edit settings page for that activity |
|
||||
* | [modname] Activity | activity name or idnumber | Start page for that activity |
|
||||
* | [modname] Activity editing | activity name or idnumber | Edit settings page for that activity |
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* When I am on the "Welcome to ECON101" "forum activity" page logged in as student1
|
||||
*
|
||||
* @param string $type identifies which type of page this is, e.g. 'Category page'.
|
||||
* @param string $identifier identifies the particular page, e.g. 'test-cat'.
|
||||
@@ -710,33 +735,70 @@ class behat_navigation extends behat_base {
|
||||
protected function resolve_core_page_instance_url(string $type, string $identifier): moodle_url {
|
||||
global $DB;
|
||||
|
||||
$type = strtolower($type);
|
||||
|
||||
switch ($type) {
|
||||
case 'Category page':
|
||||
$categoryid = $DB->get_field('course_categories', 'id', ['idnumber' => $identifier]);
|
||||
case 'category':
|
||||
$categoryid = $this->get_category_id($identifier);
|
||||
if (!$categoryid) {
|
||||
throw new Exception('The specified category with idnumber "' . $identifier . '" does not exist');
|
||||
}
|
||||
return new moodle_url('/course/category.php', ['id' => $categoryid]);
|
||||
return new moodle_url('/course/index.php', ['categoryid' => $categoryid]);
|
||||
|
||||
case 'Course':
|
||||
$courseid = $DB->get_field_select('course', 'id', 'shortname = ?', [$identifier], IGNORE_MISSING);
|
||||
case 'course':
|
||||
$courseid = $this->get_course_id($identifier);
|
||||
if (!$courseid) {
|
||||
throw new Exception('The specified course with shortname, fullname, or idnumber "' .
|
||||
$identifier . '" does not exist');
|
||||
}
|
||||
return new moodle_url('/course/view.php', ['id' => $courseid]);
|
||||
|
||||
case 'Activity':
|
||||
$cm = $DB->get_record('course_modules', ['idnumber' => $identifier], 'id, course', IGNORE_MISSING);
|
||||
case 'activity':
|
||||
$cm = $this->get_course_module_for_identifier($identifier);
|
||||
if (!$cm) {
|
||||
throw new Exception('The specified activity with idnumber "' . $identifier . '" does not exist');
|
||||
}
|
||||
$modinfo = get_fast_modinfo($cm->course);
|
||||
return $modinfo->cms[$cm->id]->url;
|
||||
return $cm->url;
|
||||
|
||||
default:
|
||||
throw new Exception('Unrecognised core page type "' . $type . '."');
|
||||
case 'activity editing':
|
||||
$cm = $this->get_course_module_for_identifier($identifier);
|
||||
if (!$cm) {
|
||||
throw new Exception('The specified activity with idnumber "' . $identifier . '" does not exist');
|
||||
}
|
||||
return new moodle_url('/course/modedit.php', [
|
||||
'update' => $cm->id,
|
||||
]);
|
||||
}
|
||||
|
||||
$parts = explode(' ', $type);
|
||||
if (count($parts) > 1) {
|
||||
if ($parts[1] === 'activity') {
|
||||
$modname = $parts[0];
|
||||
$cm = $this->get_cm_by_activity_name($modname, $identifier);
|
||||
|
||||
if (count($parts) == 2) {
|
||||
// View page.
|
||||
return new moodle_url($cm->url);
|
||||
}
|
||||
|
||||
if ($parts[2] === 'editing') {
|
||||
// Edit settings page.
|
||||
return new moodle_url('/course/modedit.php', ['update' => $cm->id]);
|
||||
}
|
||||
|
||||
if ($parts[2] === 'roles') {
|
||||
// Locally assigned roles page.
|
||||
return new moodle_url('/admin/roles/assign.php', ['contextid' => $cm->context->id]);
|
||||
}
|
||||
|
||||
if ($parts[2] === 'permissions') {
|
||||
// Permissions page.
|
||||
return new moodle_url('/admin/roles/permissions.php', ['contextid' => $cm->context->id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception('Unrecognised core page type "' . $type . '."');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,9 +12,7 @@ Feature: Any day / month / year combination in date form elements works ok.
|
||||
And the following "activity" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| assign | Assignment 01 | Assign activity to test some dates | C1 | assign01 |
|
||||
Given I am on the "C1" "Course" page logged in as "admin"
|
||||
And I follow "Assignment 01"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Assignment 01" "assign activity editing" page logged in as admin
|
||||
And I expand all fieldsets
|
||||
And I set the field "Due date" to "<initial_date>"
|
||||
And I set the field "Due date" to "<final_date>"
|
||||
|
||||
@@ -31,12 +31,11 @@ Feature: Override permissions on a context
|
||||
Then "Add announcementsmod/forum:addnews" row "Prohibited" column of "permissions" table should contain "Student"
|
||||
|
||||
Scenario: Module capabilities overrides
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Forum 1 |
|
||||
And I follow "Forum 1"
|
||||
And I navigate to "Permissions" in current page administration
|
||||
Given the following "activity" exists:
|
||||
| course | C1 |
|
||||
| activity | forum |
|
||||
| name | Forum 1 |
|
||||
And I am on the "Forum 1" "forum activity permissions" page logged in as admin
|
||||
When I click on "Allow" "icon" in the "mod/forum:addnews" "table_row"
|
||||
And I press "Student"
|
||||
Then "Add announcementsmod/forum:addnews" row "Roles with permission" column of "permissions" table should contain "Student"
|
||||
|
||||
+45
-93
@@ -262,7 +262,6 @@ class core_filelib_testcase extends advanced_testcase {
|
||||
public function test_curl_redirects() {
|
||||
global $CFG;
|
||||
|
||||
// Test full URL redirects.
|
||||
$testurl = $this->getExternalTestFileUrl('/test_redir.php');
|
||||
|
||||
$curl = new curl();
|
||||
@@ -273,6 +272,7 @@ class core_filelib_testcase extends advanced_testcase {
|
||||
$this->assertSame(2, $curl->info['redirect_count']);
|
||||
$this->assertSame('done', $contents);
|
||||
|
||||
// All redirects are emulated now. Enabling "emulateredirects" explicitly does not have effect.
|
||||
$curl = new curl();
|
||||
$curl->emulateredirects = true;
|
||||
$contents = $curl->get("$testurl?redir=2", array(), array('CURLOPT_MAXREDIRS'=>2));
|
||||
@@ -282,6 +282,17 @@ class core_filelib_testcase extends advanced_testcase {
|
||||
$this->assertSame(2, $curl->info['redirect_count']);
|
||||
$this->assertSame('done', $contents);
|
||||
|
||||
// All redirects are emulated now. Attempting to disable "emulateredirects" explicitly causes warning.
|
||||
$curl = new curl();
|
||||
$curl->emulateredirects = false;
|
||||
$contents = $curl->get("$testurl?redir=2", array(), array('CURLOPT_MAXREDIRS' => 2));
|
||||
$response = $curl->getResponse();
|
||||
$this->assertDebuggingCalled('Attempting to disable emulated redirects has no effect any more!');
|
||||
$this->assertSame('200 OK', reset($response));
|
||||
$this->assertSame(0, $curl->get_errno());
|
||||
$this->assertSame(2, $curl->info['redirect_count']);
|
||||
$this->assertSame('done', $contents);
|
||||
|
||||
// This test was failing for people behind Squid proxies. Squid does not
|
||||
// fully support HTTP 1.1, so converts things to HTTP 1.0, where the name
|
||||
// of the status code is different.
|
||||
@@ -301,21 +312,6 @@ class core_filelib_testcase extends advanced_testcase {
|
||||
$this->assertSame('', $contents);
|
||||
|
||||
$curl = new curl();
|
||||
$curl->emulateredirects = true;
|
||||
$contents = $curl->get("$testurl?redir=3", array(), array('CURLOPT_FOLLOWLOCATION'=>0));
|
||||
$response = $curl->getResponse();
|
||||
$this->assertSame($responsecode302, reset($response));
|
||||
$this->assertSame(0, $curl->get_errno());
|
||||
$this->assertSame(302, $curl->info['http_code']);
|
||||
$this->assertSame('', $contents);
|
||||
|
||||
$curl = new curl();
|
||||
$contents = $curl->get("$testurl?redir=2", array(), array('CURLOPT_MAXREDIRS'=>1));
|
||||
$this->assertSame(CURLE_TOO_MANY_REDIRECTS, $curl->get_errno());
|
||||
$this->assertNotEmpty($contents);
|
||||
|
||||
$curl = new curl();
|
||||
$curl->emulateredirects = true;
|
||||
$contents = $curl->get("$testurl?redir=2", array(), array('CURLOPT_MAXREDIRS'=>1));
|
||||
$this->assertSame(CURLE_TOO_MANY_REDIRECTS, $curl->get_errno());
|
||||
$this->assertNotEmpty($contents);
|
||||
@@ -332,28 +328,6 @@ class core_filelib_testcase extends advanced_testcase {
|
||||
@unlink($tofile);
|
||||
|
||||
$curl = new curl();
|
||||
$curl->emulateredirects = true;
|
||||
$tofile = "$CFG->tempdir/test.html";
|
||||
@unlink($tofile);
|
||||
$fp = fopen($tofile, 'w');
|
||||
$result = $curl->get("$testurl?redir=1", array(), array('CURLOPT_FILE'=>$fp));
|
||||
$this->assertTrue($result);
|
||||
fclose($fp);
|
||||
$this->assertFileExists($tofile);
|
||||
$this->assertSame('done', file_get_contents($tofile));
|
||||
@unlink($tofile);
|
||||
|
||||
$curl = new curl();
|
||||
$tofile = "$CFG->tempdir/test.html";
|
||||
@unlink($tofile);
|
||||
$result = $curl->download_one("$testurl?redir=1", array(), array('filepath'=>$tofile));
|
||||
$this->assertTrue($result);
|
||||
$this->assertFileExists($tofile);
|
||||
$this->assertSame('done', file_get_contents($tofile));
|
||||
@unlink($tofile);
|
||||
|
||||
$curl = new curl();
|
||||
$curl->emulateredirects = true;
|
||||
$tofile = "$CFG->tempdir/test.html";
|
||||
@unlink($tofile);
|
||||
$result = $curl->download_one("$testurl?redir=1", array(), array('filepath'=>$tofile));
|
||||
@@ -363,6 +337,39 @@ class core_filelib_testcase extends advanced_testcase {
|
||||
@unlink($tofile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that redirects to blocked hosts are blocked.
|
||||
*/
|
||||
public function test_curl_blocked_redirect() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$testurl = $this->getExternalTestFileUrl('/test_redir.php');
|
||||
|
||||
// Block a host.
|
||||
// Note: moodle.com is the URL redirected to when test_redir.php has the param extdest=1 set.
|
||||
set_config('curlsecurityblockedhosts', 'moodle.com');
|
||||
|
||||
// Redirecting to a non-blocked host should resolve.
|
||||
$curl = new curl();
|
||||
$contents = $curl->get("{$testurl}?redir=2");
|
||||
$response = $curl->getResponse();
|
||||
$this->assertSame('200 OK', reset($response));
|
||||
$this->assertSame(0, $curl->get_errno());
|
||||
|
||||
// Redirecting to the blocked host should fail.
|
||||
$curl = new curl();
|
||||
$blockedstring = $curl->get_security()->get_blocked_url_string();
|
||||
$contents = $curl->get("{$testurl}?redir=1&extdest=1");
|
||||
$this->assertSame($blockedstring, $contents);
|
||||
$this->assertSame(0, $curl->get_errno());
|
||||
|
||||
// Redirecting to the blocked host after multiple successful redirects should also fail.
|
||||
$curl = new curl();
|
||||
$contents = $curl->get("{$testurl}?redir=3&extdest=1");
|
||||
$this->assertSame($blockedstring, $contents);
|
||||
$this->assertSame(0, $curl->get_errno());
|
||||
}
|
||||
|
||||
public function test_curl_relative_redirects() {
|
||||
// Test relative location redirects.
|
||||
$testurl = $this->getExternalTestFileUrl('/test_relative_redir.php');
|
||||
@@ -375,15 +382,6 @@ class core_filelib_testcase extends advanced_testcase {
|
||||
$this->assertSame(1, $curl->info['redirect_count']);
|
||||
$this->assertSame('done', $contents);
|
||||
|
||||
$curl = new curl();
|
||||
$curl->emulateredirects = true;
|
||||
$contents = $curl->get($testurl);
|
||||
$response = $curl->getResponse();
|
||||
$this->assertSame('200 OK', reset($response));
|
||||
$this->assertSame(0, $curl->get_errno());
|
||||
$this->assertSame(1, $curl->info['redirect_count']);
|
||||
$this->assertSame('done', $contents);
|
||||
|
||||
// Test different redirect types.
|
||||
$testurl = $this->getExternalTestFileUrl('/test_relative_redir.php');
|
||||
|
||||
@@ -396,24 +394,6 @@ class core_filelib_testcase extends advanced_testcase {
|
||||
$this->assertSame('done', $contents);
|
||||
|
||||
$curl = new curl();
|
||||
$curl->emulateredirects = true;
|
||||
$contents = $curl->get("$testurl?type=301");
|
||||
$response = $curl->getResponse();
|
||||
$this->assertSame('200 OK', reset($response));
|
||||
$this->assertSame(0, $curl->get_errno());
|
||||
$this->assertSame(1, $curl->info['redirect_count']);
|
||||
$this->assertSame('done', $contents);
|
||||
|
||||
$curl = new curl();
|
||||
$contents = $curl->get("$testurl?type=302");
|
||||
$response = $curl->getResponse();
|
||||
$this->assertSame('200 OK', reset($response));
|
||||
$this->assertSame(0, $curl->get_errno());
|
||||
$this->assertSame(1, $curl->info['redirect_count']);
|
||||
$this->assertSame('done', $contents);
|
||||
|
||||
$curl = new curl();
|
||||
$curl->emulateredirects = true;
|
||||
$contents = $curl->get("$testurl?type=302");
|
||||
$response = $curl->getResponse();
|
||||
$this->assertSame('200 OK', reset($response));
|
||||
@@ -430,24 +410,6 @@ class core_filelib_testcase extends advanced_testcase {
|
||||
$this->assertSame('done', $contents);
|
||||
|
||||
$curl = new curl();
|
||||
$curl->emulateredirects = true;
|
||||
$contents = $curl->get("$testurl?type=303");
|
||||
$response = $curl->getResponse();
|
||||
$this->assertSame('200 OK', reset($response));
|
||||
$this->assertSame(0, $curl->get_errno());
|
||||
$this->assertSame(1, $curl->info['redirect_count']);
|
||||
$this->assertSame('done', $contents);
|
||||
|
||||
$curl = new curl();
|
||||
$contents = $curl->get("$testurl?type=307");
|
||||
$response = $curl->getResponse();
|
||||
$this->assertSame('200 OK', reset($response));
|
||||
$this->assertSame(0, $curl->get_errno());
|
||||
$this->assertSame(1, $curl->info['redirect_count']);
|
||||
$this->assertSame('done', $contents);
|
||||
|
||||
$curl = new curl();
|
||||
$curl->emulateredirects = true;
|
||||
$contents = $curl->get("$testurl?type=307");
|
||||
$response = $curl->getResponse();
|
||||
$this->assertSame('200 OK', reset($response));
|
||||
@@ -462,16 +424,6 @@ class core_filelib_testcase extends advanced_testcase {
|
||||
$this->assertSame(0, $curl->get_errno());
|
||||
$this->assertSame(1, $curl->info['redirect_count']);
|
||||
$this->assertSame('done', $contents);
|
||||
|
||||
$curl = new curl();
|
||||
$curl->emulateredirects = true;
|
||||
$contents = $curl->get("$testurl?type=308");
|
||||
$response = $curl->getResponse();
|
||||
$this->assertSame('200 OK', reset($response));
|
||||
$this->assertSame(0, $curl->get_errno());
|
||||
$this->assertSame(1, $curl->info['redirect_count']);
|
||||
$this->assertSame('done', $contents);
|
||||
|
||||
}
|
||||
|
||||
public function test_curl_proxybypass() {
|
||||
|
||||
@@ -174,7 +174,7 @@ class core_message_testcase extends advanced_testcase {
|
||||
$this->assertSame(get_string('unreadnewmessage', 'message', fullname($user1)), $email->subject);
|
||||
$this->assertNotEmpty($email->header);
|
||||
$this->assertNotEmpty($email->body);
|
||||
$this->assertRegExp('/test message body.*test/s', $email->body);
|
||||
$this->assertRegExp('/test.*message body.*test/s', $email->body);
|
||||
$sink->clear();
|
||||
|
||||
// Test that event fired includes the courseid.
|
||||
@@ -214,7 +214,7 @@ class core_message_testcase extends advanced_testcase {
|
||||
$this->assertSame(get_string('unreadnewmessage', 'message', fullname($user1)), $email->subject);
|
||||
$this->assertNotEmpty($email->header);
|
||||
$this->assertNotEmpty($email->body);
|
||||
$this->assertNotRegExp('/test message body test/', $email->body);
|
||||
$this->assertNotRegExp('/test.*message body test/', $email->body);
|
||||
|
||||
// Test that event fired includes the courseid.
|
||||
$eventsink = $this->redirectEvents();
|
||||
|
||||
@@ -808,7 +808,7 @@ class core_messagelib_testcase extends advanced_testcase {
|
||||
// so verify the expected beginning and ends.
|
||||
$this->assertNotEmpty($email->header);
|
||||
$this->assertNotEmpty($email->body);
|
||||
$this->assertRegExp('/test message body.*test/s', $email->body);
|
||||
$this->assertRegExp('/test.*message body.*test/s', $email->body);
|
||||
$sink->clear();
|
||||
|
||||
// Now, send the message again, and verify that the event fired includes the courseid and conversationid.
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
This files describes API changes in core libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 3.9.9 ===
|
||||
* For security reasons, filelib has been updated so all requests now use emulated redirects.
|
||||
For this reason, manually disabling emulateredirects will no longer have any effect (and will generate a debugging message).
|
||||
|
||||
=== 3.9.7 ===
|
||||
* The signature of the get_context_name() function in the abstract class context and all extending classes (such as context_course)
|
||||
has been extended. The new parameter allows the to get the name without escaped characters.
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
namespace core_message;
|
||||
use DOMDocument;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@@ -828,4 +829,32 @@ class helper {
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent unclosed HTML elements in a message.
|
||||
*
|
||||
* @param string $message The html message.
|
||||
* @param bool $removebody True if we want to remove tag body.
|
||||
* @return string The html properly structured.
|
||||
*/
|
||||
public static function prevent_unclosed_html_tags(
|
||||
string $message,
|
||||
bool $removebody = false
|
||||
) : string {
|
||||
$html = '';
|
||||
if (!empty($message)) {
|
||||
$doc = new DOMDocument();
|
||||
$olderror = libxml_use_internal_errors(true);
|
||||
$doc->loadHTML('<?xml version="1.0" encoding="UTF-8" ?>' . $message);
|
||||
libxml_clear_errors();
|
||||
libxml_use_internal_errors($olderror);
|
||||
$html = $doc->getElementsByTagName('body')->item(0)->C14N(false, true);
|
||||
if ($removebody) {
|
||||
// Remove <body> element added in C14N function.
|
||||
$html = preg_replace('~<(/?(?:body))[^>]*>\s*~i', '', $html);
|
||||
}
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4858,13 +4858,13 @@ class core_message_external extends external_api {
|
||||
* Deletes a message for all users
|
||||
*
|
||||
* @param int $messageid the message id
|
||||
* @param int $userid the user id of who we want to delete the message for all users
|
||||
* @param int $userid the user id of who we want to delete the message for all users, is no longer used.
|
||||
* @return external_description
|
||||
* @throws moodle_exception
|
||||
* @since 3.7
|
||||
*/
|
||||
public static function delete_message_for_all_users(int $messageid, int $userid) {
|
||||
global $CFG;
|
||||
global $CFG, $USER;
|
||||
|
||||
// Check if private messaging between users is allowed.
|
||||
if (empty($CFG->messaging)) {
|
||||
@@ -4882,11 +4882,10 @@ class core_message_external extends external_api {
|
||||
$context = context_system::instance();
|
||||
self::validate_context($context);
|
||||
|
||||
$user = core_user::get_user($params['userid'], '*', MUST_EXIST);
|
||||
core_user::require_active_user($user);
|
||||
core_user::require_active_user($USER);
|
||||
|
||||
// Checks if a user can delete a message for all users.
|
||||
if (core_message\api::can_delete_message_for_all_users($user->id, $params['messageid'])) {
|
||||
if (core_message\api::can_delete_message_for_all_users($USER->id, $params['messageid'])) {
|
||||
\core_message\api::delete_message_for_all_users($params['messageid']);
|
||||
} else {
|
||||
throw new moodle_exception('You do not have permission to delete this message for everyone.');
|
||||
|
||||
@@ -24,23 +24,17 @@ Feature: Notification popover unread notifications
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment name |
|
||||
| Description | Submit your online text |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I press "Add submission"
|
||||
And the following "activity" exists:
|
||||
| activity | assign |
|
||||
| course | C1 |
|
||||
| name | Test assignment name |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| submissiondrafts | 0 |
|
||||
# This should generate a notification.
|
||||
And I set the following fields to these values:
|
||||
| Online text | I'm the student first submission |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And the following "mod_assign > submissions" exist:
|
||||
| assign | user | onlinetext |
|
||||
| Test assignment name | student1 | I'm the student1 submission |
|
||||
|
||||
Scenario: Notification popover shows correct unread count
|
||||
When I log in as "student1"
|
||||
|
||||
@@ -177,4 +177,46 @@ class core_message_helper_testcase extends advanced_testcase {
|
||||
$this->assertNotEmpty(\core_message\helper::search_get_user_details($user6)); // Teacher in same course.
|
||||
$this->assertNotEmpty(\core_message\helper::search_get_user_details($user7)); // Teacher (course contact) in another course.
|
||||
}
|
||||
|
||||
/**
|
||||
* Test prevent_unclosed_html_tags returns the correct html.
|
||||
*
|
||||
* @dataProvider prevent_unclosed_html_tags_data
|
||||
* @param string $text text to preview unclosed html tags.
|
||||
* @param string $goodhtml html good structured.
|
||||
* @param bool $removebody true if we want to remove tag body.
|
||||
*/
|
||||
public function test_prevent_unclosed_html_tags(string $message, string $goodhtml, bool $removebody) {
|
||||
$this->setAdminUser();
|
||||
|
||||
$html = \core_message\helper::prevent_unclosed_html_tags($message, $removebody);
|
||||
$this->assertSame($goodhtml, $html);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for the test_prevent_unclosed_html_tags_data tests.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function prevent_unclosed_html_tags_data(): array {
|
||||
return [
|
||||
'Prevent unclosed html elements' => [
|
||||
'<h1>Title</h1><p>Paragraph</p><b>Bold', '<h1>Title</h1><p>Paragraph</p><b>Bold</b>', true
|
||||
],
|
||||
'Prevent unclosed html elements including comments' => [
|
||||
'<h1>Title</h1><p>Paragraph</p><!-- Comments //--><b>Bold', '<h1>Title</h1><p>Paragraph</p><!-- Comments //--><b>Bold</b>', true
|
||||
],
|
||||
'Prevent unclosed comments' => ['<h1>Title</h1><p>Paragraph</p><!-- Comments', '<h1>Title</h1><p>Paragraph</p>', true
|
||||
],
|
||||
'Prevent unclosed html elements without removing tag body' => [
|
||||
'<body><h2>Title 2</h2><p>Paragraph</p><b>Bold</body>', '<body><h2>Title 2</h2><p>Paragraph</p><b>Bold</b></body>', false
|
||||
],
|
||||
'Empty html' => [
|
||||
'', '', false
|
||||
],
|
||||
'Check encoding UTF-8 is working' => [
|
||||
'<body><h1>Title</h1><p>السلام عليكم</p></body>', '<body><h1>Title</h1><p>السلام عليكم</p></body>', false
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,19 +20,12 @@ Feature: In an assignment, teachers can provide feedback comments on student sub
|
||||
@javascript
|
||||
Scenario: Teachers should be able to add and remove feedback comments via the quick grading interface
|
||||
Given the following "activities" exist:
|
||||
| activity | course | idnumber | name | assignsubmission_onlinetext_enabled | assignfeedback_comments_enabled |
|
||||
| assign | C1 | assign1 | Test assignment1 | 1 | 1 |
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment1"
|
||||
And I press "Add submission"
|
||||
And I set the following fields to these values:
|
||||
| Online text | I'm the student1 submission |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment1"
|
||||
| activity | course | name | assignsubmission_onlinetext_enabled | assignfeedback_comments_enabled |
|
||||
| assign | C1 | Test assignment name | 1 | 1 |
|
||||
And the following "mod_assign > submissions" exist:
|
||||
| assign | user | onlinetext |
|
||||
| Test assignment name | student1 | I'm the student1 submission |
|
||||
And I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
Then I click on "Quick grading" "checkbox"
|
||||
And I set the field "Feedback comments" to "Feedback from teacher."
|
||||
|
||||
@@ -18,42 +18,37 @@ Feature: In an assignment, teacher can annotate PDF files during grading
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And the following "activity" exists:
|
||||
| activity | assign |
|
||||
| course | C1 |
|
||||
| name | Test assignment name |
|
||||
| assignfeedback_editpdf_enabled | 1 |
|
||||
| assignfeedback_comments_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 1 |
|
||||
| assignsubmission_file_maxfiles | 2 |
|
||||
| assignsubmission_file_maxsizebytes | 102400 |
|
||||
| maxfilessubmission | 2 |
|
||||
| submissiondrafts | 0 |
|
||||
And the following "mod_assign > submission" exists:
|
||||
| assign | Test assignment name |
|
||||
| user | student1 |
|
||||
| file | mod/assign/feedback/editpdf/tests/fixtures/submission.pdf, mod/assign/feedback/editpdf/tests/fixtures/testgs.pdf |
|
||||
And I log in as "admin"
|
||||
And I am on site homepage
|
||||
And I navigate to "Plugins > Activity modules > Assignment > Feedback plugins > Annotate PDF" in site administration
|
||||
And I upload "pix/help.png" file to "" filemanager
|
||||
And I upload "pix/docs.png" file to "" filemanager
|
||||
When I press "Save changes"
|
||||
Then I should see "Changes saved"
|
||||
And I press "Save changes"
|
||||
And I should see "Changes saved"
|
||||
And I follow "Test ghostscript path"
|
||||
And I should see "The ghostscript path appears to be OK"
|
||||
And I am on site homepage
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment name |
|
||||
| Description | Submit your PDF file |
|
||||
| assignsubmission_file_enabled | 1 |
|
||||
| Maximum number of uploaded files | 2 |
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I press "Add submission"
|
||||
And I upload "mod/assign/feedback/editpdf/tests/fixtures/submission.pdf" file to "File submissions" filemanager
|
||||
And I upload "mod/assign/feedback/editpdf/tests/fixtures/testgs.pdf" file to "File submissions" filemanager
|
||||
And I press "Save changes"
|
||||
And I should see "Submitted for grading"
|
||||
And I should see "submission.pdf"
|
||||
And I should see "Not graded"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
|
||||
When I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Submitted for grading" "table_row"
|
||||
And I should see "Page 1 of 3"
|
||||
Then I should see "Page 1 of 3"
|
||||
And I click on ".navigate-next-button" "css_element"
|
||||
And I should see "Page 2 of 3"
|
||||
And I click on ".stampbutton" "css_element"
|
||||
@@ -102,29 +97,25 @@ Feature: In an assignment, teacher can annotate PDF files during grading
|
||||
| grouping | group |
|
||||
| G1 | G1 |
|
||||
| G1 | G2 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment name |
|
||||
| Description | Submit your PDF file |
|
||||
| assignsubmission_file_enabled | 1 |
|
||||
| Maximum number of uploaded files | 2 |
|
||||
| Students submit in groups | Yes |
|
||||
| Grouping for student groups | G1 |
|
||||
And I log out
|
||||
When I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I press "Add submission"
|
||||
And I upload "mod/assign/feedback/editpdf/tests/fixtures/submission.pdf" file to "File submissions" filemanager
|
||||
And I press "Save changes"
|
||||
Then I should see "Submitted for grading"
|
||||
And I should see "submission.pdf"
|
||||
And I should see "Not graded"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And the following "activity" exists:
|
||||
| activity | assign |
|
||||
| course | C1 |
|
||||
| name | Test assignment name |
|
||||
| assignfeedback_comments_enabled | 1 |
|
||||
| assignfeedback_editpdf_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 1 |
|
||||
| assignsubmission_file_maxfiles | 2 |
|
||||
| assignsubmission_file_maxsizebytes | 102400 |
|
||||
| maxfilessubmission | 2 |
|
||||
| teamsubmission | 1 |
|
||||
| grouping | G1 |
|
||||
| submissiondrafts | 0 |
|
||||
And the following "mod_assign > submission" exists:
|
||||
| assign | Test assignment name |
|
||||
| user | student1 |
|
||||
| file | mod/assign/feedback/editpdf/tests/fixtures/submission.pdf |
|
||||
|
||||
And I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I open the action menu in "Student 2" "table_row"
|
||||
And I click on "Grade" "link" in the "Student 2" "table_row"
|
||||
|
||||
@@ -26,28 +26,22 @@ Feature: In a group assignment, teacher can annotate PDF files for all users
|
||||
| user | group |
|
||||
| student1 | G1 |
|
||||
| student2 | G1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment name |
|
||||
| Description | Submit your PDF file |
|
||||
| assignsubmission_file_enabled | 1 |
|
||||
| Maximum number of uploaded files | 1 |
|
||||
| Students submit in groups | Yes |
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I press "Add submission"
|
||||
And I upload "mod/assign/feedback/editpdf/tests/fixtures/submission.pdf" file to "File submissions" filemanager
|
||||
And I press "Save changes"
|
||||
And I should see "Submitted for grading"
|
||||
And I should see "submission.pdf"
|
||||
And I should see "Not graded"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And the following "activity" exists:
|
||||
| activity | assign |
|
||||
| course | C1 |
|
||||
| name | Test assignment name |
|
||||
| assignsubmission_file_enabled | 1 |
|
||||
| assignsubmission_file_maxfiles | 1 |
|
||||
| assignsubmission_file_maxsizebytes | 102400 |
|
||||
| assignfeedback_editpdf_enabled | 1 |
|
||||
| submissiondrafts | 0 |
|
||||
| teamsubmission | 1 |
|
||||
And the following "mod_assign > submission" exists:
|
||||
| assign | Test assignment name |
|
||||
| user | student1 |
|
||||
| file | mod/assign/feedback/editpdf/tests/fixtures/submission.pdf |
|
||||
|
||||
And I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Submitted for grading" "table_row"
|
||||
And I wait for the complete PDF to load
|
||||
@@ -65,28 +59,22 @@ Feature: In a group assignment, teacher can annotate PDF files for all users
|
||||
And I press "OK"
|
||||
And I click on "Edit settings" "link"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I am on the "Test assignment name" Activity page logged in as student1
|
||||
When I follow "View annotated PDF..."
|
||||
Then I should see "Annotate PDF"
|
||||
And I wait until the page is ready
|
||||
And I click on "Close" "button"
|
||||
And I log out
|
||||
And I log in as "student2"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I am on the "Test assignment name" Activity page logged in as student2
|
||||
And I should not see "View annotated PDF..."
|
||||
|
||||
@javascript
|
||||
Scenario: Submit a PDF file as a student and annotate the PDF as a teacher and all students in the group get a copy of the annotated PDF.
|
||||
Given I press "Save changes"
|
||||
And I click on "OK" "button"
|
||||
And I am on "Course 1" course homepage
|
||||
And I should see "The changes to the grade and feedback were saved"
|
||||
And I am on the "Test assignment name" Activity page
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I am on the "Test assignment name" Activity page logged in as student1
|
||||
When I follow "View annotated PDF..."
|
||||
And I change window size to "large"
|
||||
Then I should see "Annotate PDF"
|
||||
@@ -94,7 +82,6 @@ Feature: In a group assignment, teacher can annotate PDF files for all users
|
||||
And I wait until the page is ready
|
||||
And I click on "Close" "button"
|
||||
And I log out
|
||||
And I log in as "student2"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
|
||||
And I am on the "Test assignment name" Activity page logged in as student2
|
||||
And I should see "View annotated PDF..."
|
||||
|
||||
@@ -18,33 +18,26 @@ Feature: In an assignment, teacher can view the feedback for a previous attempt.
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment name |
|
||||
| Description | Submit your PDF file |
|
||||
| assignsubmission_file_enabled | 1 |
|
||||
| Maximum number of uploaded files | 2 |
|
||||
| Additional attempts | Manually |
|
||||
| Maximum attempts | Unlimited |
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I press "Add submission"
|
||||
And I upload "mod/assign/feedback/editpdf/tests/fixtures/submission.pdf" file to "File submissions" filemanager
|
||||
And I upload "mod/assign/feedback/editpdf/tests/fixtures/testgs.pdf" file to "File submissions" filemanager
|
||||
And I press "Save changes"
|
||||
And I should see "Submitted for grading"
|
||||
And I should see "submission.pdf"
|
||||
And I should see "Not graded"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And the following "activity" exists:
|
||||
| activity | assign |
|
||||
| course | C1 |
|
||||
| name | Test assignment name |
|
||||
| maxattempts | 0 |
|
||||
| assignsubmission_file_enabled | 1 |
|
||||
| assignsubmission_file_maxfiles | 2 |
|
||||
| assignsubmission_file_maxsizebytes | 102400 |
|
||||
| assignfeedback_editpdf_enabled | 1 |
|
||||
| submissiondrafts | 0 |
|
||||
| attemptreopenmethod | manual |
|
||||
And the following "mod_assign > submission" exists:
|
||||
| assign | Test assignment name |
|
||||
| user | student1 |
|
||||
| file | mod/assign/feedback/editpdf/tests/fixtures/submission.pdf, mod/assign/feedback/editpdf/tests/fixtures/testgs.pdf |
|
||||
|
||||
When I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Submitted for grading" "table_row"
|
||||
And I should see "Page 1 of 3"
|
||||
Then I should see "Page 1 of 3"
|
||||
And I click on ".navigate-next-button" "css_element"
|
||||
And I should see "Page 2 of 3"
|
||||
And I click on ".stampbutton" "css_element"
|
||||
|
||||
@@ -25,32 +25,24 @@ Feature: In an assignment, teacher can submit feedback files during grading
|
||||
| user | group |
|
||||
| student1 | G1 |
|
||||
| student2 | G1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment name |
|
||||
| Description | Submit your PDF file |
|
||||
| Maximum number of uploaded files | 2 |
|
||||
| Students submit in groups | Yes |
|
||||
And I follow "Test assignment name"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I follow "Expand all"
|
||||
And I set the field "assignfeedback_file_enabled" to "1"
|
||||
And I press "Save and display"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I press "Add submission"
|
||||
And I upload "mod/assign/feedback/file/tests/fixtures/submission.txt" file to "File submissions" filemanager
|
||||
And I press "Save changes"
|
||||
And I should see "Submitted for grading"
|
||||
And I should see "submission.txt"
|
||||
And I should see "Not graded"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And the following "activity" exists:
|
||||
| activity | assign |
|
||||
| course | C1 |
|
||||
| name | Test assignment name |
|
||||
| assignsubmission_file_enabled | 1 |
|
||||
| assignsubmission_file_maxfiles | 1 |
|
||||
| assignsubmission_file_maxsizebytes | 1024 |
|
||||
| assignfeedback_comments_enabled | 1 |
|
||||
| assignfeedback_file_enabled | 1 |
|
||||
| maxfilessubmission | 2 |
|
||||
| teamsubmission | 1 |
|
||||
| submissiondrafts | 0 |
|
||||
And the following "mod_assign > submission" exists:
|
||||
| assign | Test assignment name |
|
||||
| user | student1 |
|
||||
| file | mod/assign/feedback/file/tests/fixtures/submission.txt |
|
||||
|
||||
And I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
And I click on "Grade" "link" in the ".submissionlinks" "css_element"
|
||||
And I upload "mod/assign/feedback/file/tests/fixtures/feedback.txt" file to "Feedback files" filemanager
|
||||
|
||||
@@ -61,14 +53,10 @@ Feature: In an assignment, teacher can submit feedback files during grading
|
||||
And I click on "OK" "button"
|
||||
And I click on "Course 1" "link" in the "[data-region=assignment-info]" "css_element"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I am on the "Test assignment name" Activity page logged in as student1
|
||||
And I should see "feedback.txt"
|
||||
And I log out
|
||||
When I log in as "student2"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I am on the "Test assignment name" Activity page logged in as student2
|
||||
Then I should not see "feedback.txt"
|
||||
|
||||
@javascript
|
||||
@@ -77,12 +65,8 @@ Feature: In an assignment, teacher can submit feedback files during grading
|
||||
And I click on "OK" "button"
|
||||
And I click on "Course 1" "link" in the "[data-region=assignment-info]" "css_element"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I am on the "Test assignment name" Activity page logged in as student1
|
||||
And I should see "feedback.txt"
|
||||
And I log out
|
||||
When I log in as "student2"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
When I am on the "Test assignment name" Activity page logged in as student2
|
||||
Then I should see "feedback.txt"
|
||||
|
||||
@@ -22,11 +22,9 @@ Feature: In an assignment, limit submittable file types
|
||||
@javascript
|
||||
Scenario: File types validation for an assignment
|
||||
Given the following "activities" exist:
|
||||
| activity | course | idnumber | name | intro | duedate | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | assignsubmission_file_maxfiles | assignsubmission_file_maxsizebytes |
|
||||
| assign | C1 | assign1 | Test assignment name | Test assignment description | 1388534400 | 0 | 1 | 1 | 0 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
| activity | course | name | duedate | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | assignsubmission_file_maxfiles | assignsubmission_file_maxsizebytes |
|
||||
| assign | C1 | Test assignment name | 1388534400 | 0 | 1 | 1 | 0 |
|
||||
And I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
When I set the field "Accepted file types" to "image/png;doesntexist;.anything;unreal/mimetype;nodot"
|
||||
And I press "Save and display"
|
||||
@@ -46,11 +44,9 @@ Feature: In an assignment, limit submittable file types
|
||||
@javascript @_file_upload
|
||||
Scenario: Uploading permitted file types for an assignment
|
||||
Given the following "activities" exist:
|
||||
| activity | course | idnumber | name | intro | duedate | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | assignsubmission_file_maxfiles | assignsubmission_file_maxsizebytes | assignsubmission_file_filetypes |
|
||||
| assign | C1 | assign1 | Test assignment name | Test assignment description | 1388534400 | 0 | 1 | 3 | 0 | image/png,spreadsheet,.xml,.txt |
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
| activity | course | name | duedate | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | assignsubmission_file_maxfiles | assignsubmission_file_maxsizebytes | assignsubmission_file_filetypes |
|
||||
| assign | C1 | Test assignment name | 1388534400 | 0 | 1 | 3 | 0 | image/png,spreadsheet,.xml,.txt |
|
||||
And I am on the "Test assignment name" Activity page logged in as student1
|
||||
When I press "Add submission"
|
||||
And I should see "Accepted file types"
|
||||
And I should see "Image (PNG)"
|
||||
@@ -67,11 +63,9 @@ Feature: In an assignment, limit submittable file types
|
||||
@javascript @_file_upload
|
||||
Scenario: No filetypes allows all
|
||||
Given the following "activities" exist:
|
||||
| activity | course | idnumber | name | intro | duedate | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | assignsubmission_file_maxfiles | assignsubmission_file_maxsizebytes | assignsubmission_file_filetypes |
|
||||
| assign | C1 | assign1 | Test assignment name | Test assignment description | 1388534400 | 0 | 1 | 2 | 0 | |
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
| activity | course | name | duedate | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | assignsubmission_file_maxfiles | assignsubmission_file_maxsizebytes | assignsubmission_file_filetypes |
|
||||
| assign | C1 | Test assignment name | 1388534400 | 0 | 1 | 2 | 0 | |
|
||||
And I am on the "Test assignment name" Activity page logged in as student1
|
||||
When I press "Add submission"
|
||||
And I should not see "Accepted file types"
|
||||
And I upload "lib/tests/fixtures/gd-logo.png" file to "File submissions" filemanager
|
||||
|
||||
@@ -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/>.
|
||||
|
||||
require_once("{$CFG->dirroot}/mod/assign/tests/generator/assignsubmission_subplugin_generator.php");
|
||||
|
||||
/**
|
||||
* Online Text assignment submission subplugin data generator.
|
||||
*
|
||||
* @package assignsubmission_file
|
||||
* @category test
|
||||
* @copyright 2021 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class assignsubmission_file_generator extends assignsubmission_subplugin_generator {
|
||||
/**
|
||||
* Add submission data in the correct format for a call to `assign::save_submission()` from a table containing
|
||||
* submission data for a single activity.
|
||||
*
|
||||
* Data should be added to the $submission object passed into the function.
|
||||
*
|
||||
* @param stdClass $submission The submission record to be modified
|
||||
* @param assign $assign The assignment being submitted to
|
||||
* @param array $data The data received
|
||||
*/
|
||||
public function add_submission_data(stdClass $submission, assign $assign, array $data): void {
|
||||
global $CFG;
|
||||
|
||||
if (array_key_exists('file', $data)) {
|
||||
$files = explode(',', $data['file']);
|
||||
$itemid = file_get_unused_draft_itemid();
|
||||
|
||||
$fs = get_file_storage();
|
||||
|
||||
foreach ($files as $filepath) {
|
||||
// All paths are relative to $CFG->dirroot.
|
||||
$filepath = trim($filepath);
|
||||
$filepath = "{$CFG->dirroot}/{$filepath}";
|
||||
$filename = basename($filepath);
|
||||
|
||||
$fs->create_file_from_pathname((object) [
|
||||
'itemid' => $itemid,
|
||||
'contextid' => context_user::instance($submission->userid)->id,
|
||||
'component' => 'user',
|
||||
'filearea' => 'draft',
|
||||
'filepath' => '/',
|
||||
'filename' => $filename,
|
||||
], $filepath);
|
||||
}
|
||||
$submission->files_filemanager = $itemid;
|
||||
|
||||
$submission->file_editor = [
|
||||
'itemid' => $itemid,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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/>.
|
||||
|
||||
require_once("{$CFG->dirroot}/mod/assign/tests/generator/assignsubmission_subplugin_generator.php");
|
||||
|
||||
/**
|
||||
* Online Text assignment submission subplugin data generator.
|
||||
*
|
||||
* @package assignsubmission_onlinetext
|
||||
* @category test
|
||||
* @copyright 2021 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class assignsubmission_onlinetext_generator extends assignsubmission_subplugin_generator {
|
||||
/**
|
||||
* Add submission data in the correct format for a call to `assign::save_submission()` from a table containing
|
||||
* submission data for a single activity.
|
||||
*
|
||||
* Data should be added to the $submission object passed into the function.
|
||||
*
|
||||
* @param stdClass $submission The submission record to be modified
|
||||
* @param assign $assign The assignment being submitted to
|
||||
* @param array $data The data received
|
||||
*/
|
||||
public function add_submission_data(stdClass $submission, assign $assign, array $data): void {
|
||||
if (array_key_exists('onlinetext', $data)) {
|
||||
$submission->onlinetext_editor = [
|
||||
'itemid' => file_get_unused_draft_itemid(),
|
||||
'text' => $data['onlinetext'],
|
||||
'format' => FORMAT_HTML,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,35 +9,29 @@ Feature: In an assignment, students start a new attempt based on their previous
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category | groupmode |
|
||||
| Course 1 | C1 | 0 | 1 |
|
||||
And the following "activity" exists:
|
||||
| activity | assign |
|
||||
| course | C1 |
|
||||
| name | Test assignment name |
|
||||
| intro | Submit your online text |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| attemptreopenmethod | manual |
|
||||
| hidegrader | 1 |
|
||||
| submissiondrafts | 0 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment name |
|
||||
| Description | Submit your online text |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Additional attempts | Manually |
|
||||
| Hide grader identity from students | Yes |
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
When I press "Add submission"
|
||||
And I set the following fields to these values:
|
||||
| Online text | I'm the student first submission |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And the following "mod_assign > submissions" exist:
|
||||
| assign | user | onlinetext |
|
||||
| Test assignment name | student1 | I'm the student first submission |
|
||||
|
||||
And I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
And I set the following fields to these values:
|
||||
@@ -46,16 +40,14 @@ Feature: In an assignment, students start a new attempt based on their previous
|
||||
And I press "OK"
|
||||
And I click on "Edit settings" "link"
|
||||
And I log out
|
||||
Then I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I should not see "Teacher 1"
|
||||
|
||||
When I am on the "Test assignment name" Activity page logged in as student1
|
||||
Then I should not see "Teacher 1"
|
||||
And I press "Add a new attempt based on previous submission"
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
|
||||
And I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
And I should see "I'm the student first submission"
|
||||
@@ -89,29 +81,24 @@ Feature: In an assignment, students start a new attempt based on their previous
|
||||
| student2 | G1 |
|
||||
| student3 | G2 |
|
||||
| student4 | G2 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment name |
|
||||
| Description | Test assignment description |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Students submit in groups | Yes |
|
||||
| Additional attempts | Manually |
|
||||
| Maximum attempts | 3 |
|
||||
| Group mode | Separate groups |
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I press "Add submission"
|
||||
And I set the following fields to these values:
|
||||
| Online text | I'm the student's first submission |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
|
||||
And the following "activity" exists:
|
||||
| activity | assign |
|
||||
| course | C1 |
|
||||
| name | Test assignment name |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| attemptreopenmethod | manual |
|
||||
| submissiondrafts | 0 |
|
||||
| groupmode | 1 |
|
||||
| teamsubmission | 1 |
|
||||
| hidegrader | 1 |
|
||||
| maxattempts | 3 |
|
||||
And the following "mod_assign > submissions" exist:
|
||||
| assign | user | onlinetext |
|
||||
| Test assignment name | student1 | I'm the student first submission |
|
||||
|
||||
And I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
When I navigate to "View all submissions" in current page administration
|
||||
Then "Student 1" row "Status" column of "generaltable" table should contain "Submitted for grading"
|
||||
And "Student 2" row "Status" column of "generaltable" table should contain "Submitted for grading"
|
||||
@@ -129,18 +116,15 @@ Feature: In an assignment, students start a new attempt based on their previous
|
||||
And I click on "Go" "button" confirming the dialogue
|
||||
And I should not see "The grades were not saved because someone has modified one or more records more recently than when you loaded the page."
|
||||
And I log out
|
||||
And I log in as "student3"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I am on the "Test assignment name" Activity page logged in as student3
|
||||
And I should see "This is attempt 1 ( 3 attempts allowed )."
|
||||
And I press "Add submission"
|
||||
And I set the following fields to these values:
|
||||
| Online text | I'm the student's 3 group 2 first attempt |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
|
||||
And I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And "Student 1" row "Status" column of "generaltable" table should contain "Reopened"
|
||||
And "Student 2" row "Status" column of "generaltable" table should contain "Reopened"
|
||||
@@ -153,18 +137,16 @@ Feature: In an assignment, students start a new attempt based on their previous
|
||||
And I press "OK"
|
||||
And I follow "Assignment: Test assignment name"
|
||||
And I log out
|
||||
And I log in as "student4"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
|
||||
And I am on the "Test assignment name" Activity page logged in as student4
|
||||
And I should see "This is attempt 2 ( 3 attempts allowed )."
|
||||
And I press "Add a new attempt"
|
||||
And I set the following fields to these values:
|
||||
| Online text | I'm the student's 4 group 2 second attempt |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
|
||||
And I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
And I select "Group 2" from the "group" singleselect
|
||||
And I click on "Grade" "link" in the ".submissionlinks" "css_element"
|
||||
And I should see "2" in the "#id_attemptsettings" "css_element"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@mod @mod_assign
|
||||
Feature: Switch role does not cause an error message in assignsubmission_comments
|
||||
|
||||
Background:
|
||||
Scenario: I switch role to student and an error doesn't occur
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
@@ -11,15 +11,14 @@ Feature: Switch role does not cause an error message in assignsubmission_comment
|
||||
And the following "course enrolments" exist:
|
||||
| course | user | role |
|
||||
| C1 | teacher1 | editingteacher |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | This is the description text |
|
||||
| Students submit in groups | Yes |
|
||||
|
||||
Scenario: I switch role to student and an error doesn't occur
|
||||
And the following "activity" exists:
|
||||
| activity | assign |
|
||||
| course | C1 |
|
||||
| name | Test assignment |
|
||||
| intro | This is the description text |
|
||||
| teamsubmission | 1 |
|
||||
| submissiondrafts | 0 |
|
||||
And I am on the "C1" Course page logged in as teacher1
|
||||
When I follow "Switch role to..." in the user menu
|
||||
And I press "Student"
|
||||
And I follow "Test assignment"
|
||||
|
||||
@@ -22,48 +22,43 @@ Feature: Assign reset
|
||||
| name | course | idnumber |
|
||||
| Group 1 | C1 | G1 |
|
||||
| Group 2 | C1 | G2 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment name |
|
||||
| Description | Submit your online text |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_onlinetext_wordlimit_enabled | 1 |
|
||||
| assignsubmission_onlinetext_wordlimit | 10 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
And the following "activity" exists:
|
||||
| activity | assign |
|
||||
| course | C1 |
|
||||
| name | Test assignment name |
|
||||
| intro | Submit your online text |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_onlinetext_wordlimit_enabled | 1 |
|
||||
| assignsubmission_onlinetext_wordlimit | 10 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| submissiondrafts | 0 |
|
||||
|
||||
Scenario: Use course reset to clear all attempt data
|
||||
When I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
When I press "Add submission"
|
||||
And I set the following fields to these values:
|
||||
| Online text | I'm the student first submission |
|
||||
And I press "Save changes"
|
||||
Then I should see "Submitted for grading"
|
||||
Given the following "mod_assign > submissions" exist:
|
||||
| assign | user | onlinetext |
|
||||
| Test assignment name | student1 | I'm the student first submission |
|
||||
And I am on the "Test assignment name" Activity page logged in as student1
|
||||
And I should see "Submitted for grading"
|
||||
And I should see "I'm the student first submission"
|
||||
And I should see "Not graded"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
|
||||
And I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I should see "Submitted for grading"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Reset" in current page administration
|
||||
When I navigate to "Reset" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Delete all submissions | 1 |
|
||||
And I press "Reset course"
|
||||
And I press "Continue"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test assignment name"
|
||||
And I am on the "Test assignment name" Activity page
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
Then I should not see "Submitted for grading"
|
||||
|
||||
@javascript
|
||||
Scenario: Use course reset to remove user overrides.
|
||||
When I follow "Test assignment name"
|
||||
And I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
And I navigate to "User overrides" in current page administration
|
||||
And I press "Add user override"
|
||||
And I set the following fields to these values:
|
||||
@@ -88,7 +83,7 @@ Feature: Assign reset
|
||||
Then I should not see "Sam1 Student1"
|
||||
|
||||
Scenario: Use course reset to remove group overrides.
|
||||
When I follow "Test assignment name"
|
||||
When I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
And I navigate to "Group overrides" in current page administration
|
||||
And I press "Add group override"
|
||||
And I set the following fields to these values:
|
||||
@@ -113,7 +108,7 @@ Feature: Assign reset
|
||||
Then I should not see "Group 1"
|
||||
|
||||
Scenario: Use course reset to reset blind marking assignment.
|
||||
Given I follow "Test assignment name"
|
||||
When I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| blindmarking | 1 |
|
||||
|
||||
@@ -30,21 +30,19 @@ Feature: Assign group override
|
||||
| student2 | G2 |
|
||||
| student3 | G1 |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | assignsubmission_onlinetext_enabled |
|
||||
| assign | Test assignment name | Submit your online text | C1 | assign1 | 1 |
|
||||
| activity | name | intro | course | assignsubmission_onlinetext_enabled |
|
||||
| assign | Test assignment name | Submit your online text | C1 | 1 |
|
||||
|
||||
Scenario: Add, modify then delete a group override
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I follow "Test assignment name"
|
||||
And I navigate to "Group overrides" in current page administration
|
||||
Given I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
When I navigate to "Group overrides" in current page administration
|
||||
And I press "Add group override"
|
||||
And I set the following fields to these values:
|
||||
| Override group | Group 1 |
|
||||
| Due date | ##1 Jan 2020 08:00## |
|
||||
And I press "Save"
|
||||
And I should see "Wednesday, 1 January 2020, 8:00"
|
||||
Then I click on "Edit" "link" in the "Group 1" "table_row"
|
||||
Then I should see "Wednesday, 1 January 2020, 8:00"
|
||||
And I click on "Edit" "link" in the "Group 1" "table_row"
|
||||
And I set the following fields to these values:
|
||||
| Due date | ##1 Jan 2030 08:00## |
|
||||
And I press "Save"
|
||||
@@ -54,17 +52,15 @@ Feature: Assign group override
|
||||
And I should not see "Group 1"
|
||||
|
||||
Scenario: Duplicate a user override
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I follow "Test assignment name"
|
||||
And I navigate to "Group overrides" in current page administration
|
||||
Given I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
When I navigate to "Group overrides" in current page administration
|
||||
And I press "Add group override"
|
||||
And I set the following fields to these values:
|
||||
| Override group | Group 1 |
|
||||
| Due date | ##1 Jan 2020 08:00## |
|
||||
And I press "Save"
|
||||
And I should see "Wednesday, 1 January 2020, 8:00"
|
||||
Then I click on "copy" "link"
|
||||
Then I should see "Wednesday, 1 January 2020, 8:00"
|
||||
And I click on "copy" "link"
|
||||
And I set the following fields to these values:
|
||||
| Override group | Group 2 |
|
||||
| Due date | ##1 Jan 2030 08:00## |
|
||||
@@ -73,10 +69,8 @@ Feature: Assign group override
|
||||
And I should see "Group 2"
|
||||
|
||||
Scenario: Allow a group to have a different due date
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I follow "Test assignment name"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
Given I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
When I navigate to "Edit settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Allow submissions from | disabled |
|
||||
| Due date | ##1 Jan 2000 08:00## |
|
||||
@@ -101,10 +95,8 @@ Feature: Assign group override
|
||||
And I should see "Wednesday, 1 January 2020, 8:00"
|
||||
|
||||
Scenario: Allow a group to have a different cut off date
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I follow "Test assignment name"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
Given I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
When I navigate to "Edit settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Due date | disabled |
|
||||
| Allow submissions from | disabled |
|
||||
@@ -129,10 +121,8 @@ Feature: Assign group override
|
||||
And I should see "You have not made a submission yet."
|
||||
|
||||
Scenario: Allow a group to have a different start date
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I follow "Test assignment name"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
Given I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
When I navigate to "Edit settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Due date | disabled |
|
||||
| Allow submissions from | ##1 January 2030 08:00## |
|
||||
@@ -159,10 +149,8 @@ Feature: Assign group override
|
||||
|
||||
@javascript
|
||||
Scenario: Add both a user and group override and verify that both are applied correctly
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I follow "Test assignment name"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
Given I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
When I navigate to "Edit settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Due date | disabled |
|
||||
| Allow submissions from | ##1 January 2040 08:00## |
|
||||
@@ -204,12 +192,10 @@ Feature: Assign group override
|
||||
| capability | permission | role | contextlevel | reference |
|
||||
| moodle/site:accessallgroups | Prevent | editingteacher | Course | C1 |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | groupmode |
|
||||
| assign | Assignment 2 | Assignment 2 description | C1 | assign2 | 1 |
|
||||
When I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Assignment 2"
|
||||
And I navigate to "Group overrides" in current page administration
|
||||
| activity | name | intro | course | groupmode |
|
||||
| assign | Assignment 2 | Assignment 2 description | C1 | 1 |
|
||||
And I am on the "Assignment 2" Activity page logged in as teacher1
|
||||
When I navigate to "Group overrides" in current page administration
|
||||
Then I should see "No groups you can access."
|
||||
And the "Add group override" "button" should be disabled
|
||||
|
||||
@@ -219,15 +205,13 @@ Feature: Assign group override
|
||||
| capability | permission | role | contextlevel | reference |
|
||||
| moodle/site:accessallgroups | Prevent | editingteacher | Course | C1 |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | groupmode |
|
||||
| assign | Assignment 2 | Assignment 2 description | C1 | assign2 | 1 |
|
||||
| activity | name | intro | course | groupmode |
|
||||
| assign | Assignment 2 | Assignment 2 description | C1 | 1 |
|
||||
And the following "group members" exist:
|
||||
| user | group |
|
||||
| teacher1 | G1 |
|
||||
When I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Assignment 2"
|
||||
And I navigate to "Group overrides" in current page administration
|
||||
And I am on the "Assignment 2" Activity page logged in as teacher1
|
||||
When I navigate to "Group overrides" in current page administration
|
||||
And I press "Add group override"
|
||||
Then the "Override group" select box should contain "Group 1"
|
||||
And the "Override group" select box should not contain "Group 2"
|
||||
@@ -238,14 +222,12 @@ Feature: Assign group override
|
||||
| capability | permission | role | contextlevel | reference |
|
||||
| moodle/site:accessallgroups | Prevent | editingteacher | Course | C1 |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | groupmode |
|
||||
| assign | Assignment 2 | Assignment 2 description | C1 | assign2 | 1 |
|
||||
| activity | name | intro | course | groupmode |
|
||||
| assign | Assignment 2 | Assignment 2 description | C1 | 1 |
|
||||
And the following "group members" exist:
|
||||
| user | group |
|
||||
| teacher1 | G1 |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Assignment 2"
|
||||
And I am on the "Assignment 2" Activity page logged in as admin
|
||||
And I navigate to "Group overrides" in current page administration
|
||||
And I press "Add group override"
|
||||
And I set the following fields to these values:
|
||||
@@ -257,9 +239,8 @@ Feature: Assign group override
|
||||
| Allow submissions from | ##1 January 2020 08:00## |
|
||||
And I press "Save"
|
||||
And I log out
|
||||
When I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Assignment 2"
|
||||
|
||||
When I am on the "Assignment 2" Activity page logged in as teacher1
|
||||
And I navigate to "Group overrides" in current page administration
|
||||
Then I should see "Group 1" in the ".generaltable" "css_element"
|
||||
And I should not see "Group 2" in the ".generaltable" "css_element"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user