Compare commits

...

132 Commits

Author SHA1 Message Date
Eloy Lafuente (stronk7) aca9cdc61f Moodle release 3.1.16 2019-01-12 13:25:46 +01:00
Sara Arjona bbaf0525f4 weekly release 3.1.15+ 2019-01-10 17:51:37 +01:00
Sara Arjona 7a37b0a5a4 Merge branch 'install_31_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_31_STABLE 2019-01-10 17:51:36 +01:00
AMOS bot 2dcd7f8a55 Automatically generated installer lang files 2019-01-10 00:09:22 +00:00
Eloy Lafuente (stronk7) 7edb20cadd Merge branch 'MDL-64285-31' of git://github.com/junpataleta/moodle into MOODLE_31_STABLE 2019-01-09 00:04:25 +01:00
Michael Hawkins 3d2783690d MDL-64395 groups: Added XSS Risk to the manage groups capability 2019-01-08 10:19:28 +01:00
Michael Hawkins 3681c247f5 MDL-64372 userpix: Escape fullname string on userpix index page 2019-01-08 10:19:28 +01:00
Sara Arjona 7013fe50b5 MDL-64222 badge: Removed backpackurl from the edit_form 2019-01-08 10:19:28 +01:00
Eloy Lafuente (stronk7) d3c2514a2c Merge branch 'MDL-64520-31' of git://github.com/andrewnicols/moodle into MOODLE_31_STABLE 2019-01-08 10:08:19 +01:00
Andrew Nicols 808954253e MDL-64520 iplookup: Remove failing unit tests
GeoIP V1 database has been deprecated and removed. We can no longer test
against it.
2019-01-08 11:56:44 +08:00
Andrew Nicols be5d94c454 Merge branch 'MDL-63276_31' of https://github.com/stronk7/moodle into MOODLE_31_STABLE 2019-01-08 06:57:07 +08:00
Mathew d75d4949ef MDL-49651 mod_forum: Respect course visibility in cron
This checks the courses' current visibility and the users permissions.
If they have the permission to view the course when it is hidden they'll get messages.

We already have checks for the users enrolled & subscription status.
2019-01-03 10:50:30 +08:00
Eloy Lafuente (stronk7) 88180f1e0c MDL-63276 environment: PHP 7.1 and Moodle 3.2 required 2019-01-03 01:20:19 +01:00
Eloy Lafuente (stronk7) b534e3ff7b MDL-63276 environment: 3.7 base information
This is a direct copy of the 3.6 branch to
have changes under control easier in next commits.
2019-01-03 01:20:18 +01:00
AMOS bot c7d887dae0 Automatically generated installer lang files 2018-12-19 00:09:58 +00:00
Jun Pataleta d2df0daf5b MDL-64285 core: Fix environment check test
* Looping the environment results and skipping some items mean that
if a test gets skipped, the rest of the environment results won't be
tested. It's better to use a data provider for this in order to
individually test each environment result.
2018-12-13 16:05:14 +08:00
AMOS bot 9c7f64b79d Automatically generated installer lang files 2018-12-07 00:10:22 +00:00
AMOS bot 2cff96a309 Automatically generated installer lang files 2018-11-30 00:08:24 +00:00
AMOS bot c01ffc64eb Automatically generated installer lang files 2018-11-29 00:09:09 +00:00
AMOS bot e3f586e627 Automatically generated installer lang files 2018-11-23 00:08:07 +00:00
David Monllao 6f41a2c318 weekly release 3.1.15+ 2018-11-20 12:55:06 +01:00
David Monllao 786fe59949 Merge branch 'install_31_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_31_STABLE 2018-11-20 12:55:04 +01:00
Jun Pataleta 53c902867f Merge branch 'MDL-63994-31-castoken' of git://github.com/mudrd8mz/moodle into MOODLE_31_STABLE 2018-11-19 15:45:03 +08:00
David Mudrák 7467757700 MDL-63994 auth_cas: Include the login token in the simulated login form
The CAS login process relies on the standard authenticate_user_login()
call to set up the user. So we need to inject the login token to pass
the validation.
2018-11-15 21:36:26 +01:00
David Mudrák ee5065676d MDL-63994 login: Improve the logintoken param input
The logintoken is supposed to arrive as a part of the login form ($frm)
together with the username and password. So it should be handled the
same way - including the opportunity for the auth plugins to provide the
form data via the loginpage_hook().

This also implies that only logintoken coming as a part of the POST
request are taken into account, which is a good thing and another thin
layer in this security mechanism.
2018-11-15 21:36:17 +01:00
David Mudrák 04919a422b MDL-63994 login: Clarify inline comments on loginpage_hook() usage
While working on the issue, I found these inline comments outdated and
confusing. The auth plugin types can implement a loginpage_hook()
method, the purpose of which is to inject the $user and/or $frm into
this login/index.php script. The new comments should make it more clear.

Note the second comment mentioned a prelogin_hook() which was an old
name of what is now called loginpage_hook(). It had nothing to do with
the existing pre_loginpage_hook() and was only confusing.
2018-11-15 21:35:53 +01:00
AMOS bot 2b459ffe02 Automatically generated installer lang files 2018-11-13 00:08:12 +00:00
Eloy Lafuente (stronk7) da70ec0cca Moodle release 3.1.15 2018-11-10 20:36:10 +01:00
Eloy Lafuente (stronk7) 6ce7c17be9 weekly release 3.1.14+ 2018-11-10 12:53:08 +01:00
Eloy Lafuente (stronk7) f058de06a3 Merge branch 'install_31_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_31_STABLE 2018-11-10 12:53:05 +01:00
AMOS bot f4f0f30630 Automatically generated installer lang files 2018-11-06 00:07:59 +00:00
Jun Pataleta 2f982389d4 MDL-63183 auth_shibboleth: Don't render page when already logged in 2018-10-24 14:00:13 +08:00
Jun Pataleta 41790d2e48 MDL-63183 login: Add hidden login token input in guest login forms
* Affected forms:
  - login/index_form.html
  - auth/shibboleth/index_form.html
2018-10-24 11:27:52 +08:00
Damyon Wiese 52b50073fc MDL-63183 auth: Login protection
CSRF protection for the login form. The authenticate_user_login function was
extended to validate the token (in \core\session\manager) but by default it
does not perform the extra validation. Existing uses of this function from
auth plugins and features like "change password" will continue to work without
changes. New config value $CFG->disablelogintoken can bypass this check.
2018-10-23 12:29:30 +08:00
AMOS bot 3598b0e3bd Automatically generated installer lang files 2018-10-22 00:07:52 +00:00
AMOS bot f2391ae1c1 Automatically generated installer lang files 2018-10-19 00:08:45 +00:00
AMOS bot f2eeb4ede6 Automatically generated installer lang files 2018-10-18 00:08:02 +00:00
Eloy Lafuente (stronk7) e3602a5a0a weekly release 3.1.14+ 2018-10-16 16:05:21 +02:00
Eloy Lafuente (stronk7) 513e8044c3 Merge branch 'install_31_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_31_STABLE 2018-10-16 16:05:19 +02:00
Andrew Nicols 6776687817 Merge branch 'MDL-63421_31' of git://github.com/stronk7/moodle into MOODLE_31_STABLE 2018-10-16 08:57:36 +08:00
AMOS bot f558157719 Automatically generated installer lang files 2018-10-15 00:07:51 +00:00
AMOS bot e07f6c0528 Automatically generated installer lang files 2018-10-11 00:07:50 +00:00
AMOS bot ba532b0010 Automatically generated installer lang files 2018-10-10 00:07:46 +00:00
Eloy Lafuente (stronk7) 9dfe3e0be1 MDL-63421 env: Moodle 3.4.x and 3.5.x do not support PHP 7.3 2018-10-05 13:39:12 +02:00
AMOS bot f27e3d0bde Automatically generated installer lang files 2018-10-04 00:07:53 +00:00
Eloy Lafuente (stronk7) f1ad334f3a weekly release 3.1.14+ 2018-09-27 15:17:44 +02:00
Andrew Nicols 8ee12efa22 Merge branch 'MDL-63346_31' of https://github.com/stronk7/moodle into MOODLE_31_STABLE 2018-09-25 09:18:27 +08:00
Eloy Lafuente (stronk7) 1fe370973c MDL-63346 js: Changed min.js with uglify-js bump (2.6.1 => 2.6.4) 2018-09-20 12:07:27 +02:00
Eloy Lafuente (stronk7) d871d35b90 MDL-63346 nodejs: Bump to created from scratch shrinkwrap file
Steps:

- remove node_modules & npm-shrinkwrap.json
- npm cache clear --force
- npm install
- npm shrinkwrap
2018-09-20 10:57:48 +02:00
Eloy Lafuente (stronk7) 066b56539e MDL-63346 travis: GRUNT job immune to npm-shrinkwrap.json changes
When upgrading nodejs/npm versions, there are modifications to
different packages or to the format of the npm-shrinkwrap.json
file. Usually that leads to failed jobs untill the bundled file
is updated.

To avoid that, we just ignore the npm-shrinkwrap.json file, so
just the REAL modifications in css/js/ignore stuff are considered.
2018-09-20 10:57:07 +02:00
Eloy Lafuente (stronk7) bdc0d9f924 weekly release 3.1.14+ 2018-09-14 11:06:38 +02:00
Eloy Lafuente (stronk7) 785c9e3f70 MDL-61169 iplookup: Change to another block still remaining to SF 2018-09-13 19:09:10 +02:00
Eloy Lafuente (stronk7) b45c238223 Moodle release 3.1.14 2018-09-08 16:49:31 +02:00
AMOS bot a5f11a79a2 Automatically generated installer lang files 2018-09-08 00:08:15 +00:00
Jun Pataleta 22b39b4c8c weekly release 3.1.13+ 2018-09-07 11:10:51 +08:00
Jun Pataleta de284c4cd4 Merge branch 'install_31_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_31_STABLE 2018-09-07 11:10:23 +08:00
Jake Dallimore fc5853c205 MDL-62947 mod_feedback: fix feedback so it correctly uses forms API
Feedback code was doing the following, which is incompatible with the
sec-patched quickforms lib:
- appending '[0]' to non-group element names, meaning type checks in
getCleanType() were falling back to PARAM_RAW instead of PARAM_INT,
and meaning _findValue() was comparing elements it thought to be arrays
with scalar submit values (worked with eval() implementation as the 0th
element of a string was the character, but not working when patched).
- external unit tests incorrectly testing multichoice questions in the
process_page tests - patched lib highlighted failures.

It was also doing the following:
- actively setting null as default element values instead of 0 for
radio buttons and dropdowns (for 'not selected'). This is incompatible
with more recent quickforms lib (see MDL-63070).
- creating groups using addElement instead of addGroup - not recommended

This patch addresses the above.
2018-09-05 12:23:13 +08:00
Jake Dallimore 110828ee5c MDL-62947 core_form: fix remote code execution exploit in QuickForms
Applies the patch found upstream:
https://github.com/pear/HTML_QuickForm/commit/
d3a6d5c44dedf3c164c6c79198e4ef479bcedcd2 and make util methods static
for php7 compatibility.
2018-09-05 12:23:13 +08:00
AMOS bot 97a9e8c3c4 Automatically generated installer lang files 2018-09-05 00:08:07 +00:00
Tim Hunt da1eeea0ff MDL-62880 qtype_ddwtos: drop support for legacy import format
It was more than 8 years since we wrote in that format.
2018-09-04 13:57:45 +02:00
David Monllao 1b87b66946 Merge branch 'MDL-63275-31' of git://github.com/junpataleta/moodle into MOODLE_31_STABLE 2018-09-04 13:46:50 +02:00
Jun Pataleta 7db66a5fe2 MDL-63275 calendar: Fix rrule_manager unit test
* The calculation of the expected date should depend on the comparison
with the start date's date and not it's exact timestamp.
2018-09-04 13:46:41 +02:00
Jun Pataleta 8c04f87af5 MDL-63275 calendar: Properly calculate expected until date 2018-09-04 13:46:34 +02:00
Jun Pataleta 6a4d4f2ba4 MDL-63275 calendar: Use a fixed start day for forever BYMONTH test 2018-09-04 13:46:28 +02:00
Jun Pataleta 845266a33d MDL-63275 calendar: Better testing of forever recurring events
* Change the start date of the parent event to the current date
  for tests that with events that recur forever.
* Limit query results to 100 for events that recur forever that can
  generate more than 100 event records.
2018-09-04 13:46:12 +02:00
Jun Pataleta a9ec123f52 Merge branch 'MDL-60901_31' of git://github.com/stronk7/moodle into MOODLE_31_STABLE 2018-09-04 10:18:08 +08:00
Eloy Lafuente (stronk7) 1cef9981fb MDL-60901 environment: 3.6 requirements
Changes include:
- MySQL 5.6 is required.
- PostgreSQL 8.4 is required.
- Oracle 11.2 is required.
- 64bits architecture is recommended.
2018-09-03 10:12:46 +02:00
AMOS bot 81cbe8e8a4 Automatically generated installer lang files 2018-09-02 00:08:09 +00:00
AMOS bot c428bb3c0b Automatically generated installer lang files 2018-09-01 00:08:05 +00:00
Eloy Lafuente (stronk7) 75b395ee62 weekly release 3.1.13+ 2018-08-30 19:04:07 +02:00
Eloy Lafuente (stronk7) 9637705b0c Merge branch 'install_31_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_31_STABLE 2018-08-30 19:04:05 +02:00
AMOS bot bae234d9ff Automatically generated installer lang files 2018-08-30 00:08:43 +00:00
Jake Dallimore a27fbd640d Merge branch 'MDL-63101-31' of git://github.com/andrewnicols/moodle into MOODLE_31_STABLE 2018-08-28 16:56:51 +08:00
Andrew Nicols 83cf77b622 MDL-63101 cache: Improve accuracy of cache event invalidation 2018-08-27 13:13:01 +08:00
Eloy Lafuente (stronk7) 88b95638fb weekly release 3.1.13+ 2018-08-17 17:37:26 +02:00
Eloy Lafuente (stronk7) dc855f283b Merge branch 'install_31_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_31_STABLE 2018-08-17 17:37:24 +02:00
Eloy Lafuente (stronk7) a0c850628c Merge branch 'MDL-63050-31' of git://github.com/andrewnicols/moodle into MOODLE_31_STABLE 2018-08-16 02:18:41 +02:00
Andrew Nicols 0edc5fe898 MDL-63050 redis: Correct empty test for PHP54 2018-08-16 08:16:39 +08:00
AMOS bot ef65abdcbd Automatically generated installer lang files 2018-08-16 00:08:57 +00:00
Eloy Lafuente (stronk7) 931f732a8c Merge branch 'MDL-63050-31' of git://github.com/andrewnicols/moodle into MOODLE_31_STABLE 2018-08-16 01:58:28 +02:00
Andrew Nicols 318ab14384 MDL-63050 redis: Make session check compatible with Redis 4.0 2018-08-16 07:55:00 +08:00
AMOS bot c5691ceee3 Automatically generated installer lang files 2018-08-15 00:08:18 +00:00
AMOS bot 910ceebd70 Automatically generated installer lang files 2018-07-29 00:07:52 +00:00
AMOS bot 38317c9050 Automatically generated installer lang files 2018-07-18 00:08:08 +00:00
AMOS bot bd956b6ce2 Automatically generated installer lang files 2018-07-17 00:08:58 +00:00
Eloy Lafuente (stronk7) b19d180a86 Moodle release 3.1.13 2018-07-07 06:48:58 +02:00
Eloy Lafuente (stronk7) 93b943b322 Merge branch 'install_31_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_31_STABLE 2018-07-07 06:48:44 +02:00
AMOS bot 8e3b262bb7 Automatically generated installer lang files 2018-07-07 00:09:05 +00:00
AMOS bot f0b9026133 Automatically generated installer lang files 2018-07-05 00:08:59 +00:00
Tim Hunt b779dc805e MDL-62820 question import: properly escape output 2018-07-04 15:42:36 +08:00
Marina Glancy e74867d06c MDL-62790 course: cap check in core_course_get_categories 2018-07-03 12:05:51 +08:00
AMOS bot 41feb40e7e Automatically generated installer lang files 2018-06-13 00:08:54 +00:00
David Monllao 7696a8d9e3 weekly release 3.1.12+ 2018-05-24 10:45:51 +02:00
David Monllao c44b6e79fa Merge branch 'm31_MDL-61893_Accept_Any_Node_Carbon_Version-minimal' of https://github.com/scara/moodle into MOODLE_31_STABLE 2018-05-22 09:24:23 +02:00
Matteo Scaramuccia 81d5b794d0 MDL-61893 JavaScript: Accept any node version but Carbon (LTS)
Bumped the npm-shrinkwrap.json file version too by simply running
'npm install' after having removed the 'node_modules' directory.
2018-05-21 23:00:53 +02:00
Eloy Lafuente (stronk7) 8137f98b1c Merge branch 'MDL-62500-31' of git://github.com/andrewnicols/moodle into MOODLE_31_STABLE 2018-05-21 13:40:28 +02:00
Andrew Nicols 9103f6ca8a MDL-62500 tag: Update checkbox label when updating tag 2018-05-21 15:48:51 +08:00
Eloy Lafuente (stronk7) e6973df683 Moodle release 3.1.12 2018-05-16 18:42:02 +02:00
Marina Glancy 7d7ca07870 MDL-62469 qtype_calculated: check remaining placeholders, see MDL-62275
Amended for phpunit 4.x exception expectations.
2018-05-16 18:04:59 +02:00
David Monllao 8398fbe8b6 weekly release 3.1.11+ 2018-05-15 09:42:19 +02:00
David Monllao 7c362df750 Merge branch 'install_31_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_31_STABLE 2018-05-15 09:42:18 +02:00
AMOS bot 550b956e23 Automatically generated installer lang files 2018-05-15 00:07:06 +00:00
AMOS bot 59dbf60906 Automatically generated installer lang files 2018-05-13 00:07:23 +00:00
Eloy Lafuente (stronk7) f6f7a788ac MDL-62416 question_calculated: fix const to work under php54 2018-05-12 18:55:31 +02:00
Eloy Lafuente (stronk7) b6c0d8fc2a MDL-62275 qtype_calculatedmulti: Fix typo 2018-05-11 21:18:49 +02:00
Tim Hunt b7bbe9fd94 MDL-62275 qtype_calc*: improve validation of formulae
Many thanks to Marina Glancy for helping with this.
2018-05-11 01:44:17 +02:00
Marina Glancy f6da281a83 MDL-62206 blocks: do not add fixed form elements as hidden 2018-05-10 12:09:27 +08:00
Adam Olley f72830b4f0 MDL-62210 mod_assign: limit file lookup to the target assign 2018-05-10 11:22:39 +08:00
Brendan Cox ecd1bce400 MDL-62210 mod_assign: improved validation in portfolio caller class 2018-05-10 11:22:39 +08:00
Jun Pataleta 6c0e979eda MDL-62232 mod_forum: Use setExpectedException() 2018-05-10 09:21:06 +08:00
Brendan Cox 3ff27109ec MDL-62232 mod_forum: Additional tests for portfolio file export 2018-05-10 09:21:06 +08:00
Adam Olley f06f4603b8 MDL-62232 mod_forum: Limit portfolio to files belonging to the post 2018-05-10 09:21:06 +08:00
Marina Glancy 7bed262b8f MDL-62233 portfolio: check caller parent class 2018-05-10 09:21:05 +08:00
Marina Glancy e9ba7022fc MDL-61996 core: when loggedin always check user is complete 2018-05-09 12:10:02 +08:00
Jun Pataleta 60aab30175 weekly release 3.1.11+ 2018-05-09 12:00:59 +08:00
Jun Pataleta 85e9ee2175 Merge branch 'install_31_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_31_STABLE 2018-05-09 12:00:57 +08:00
Jake Dallimore 10426ccf9d Merge branch 'MDL-62280-31' of git://github.com/andrewnicols/moodle into MOODLE_31_STABLE 2018-05-03 10:55:04 +08:00
AMOS bot babe95c9dc Automatically generated installer lang files 2018-05-03 00:07:08 +00:00
Andrew Nicols 9a15bdc97f MDL-62280 xhprof: Support tideways_xhprof 2018-05-01 11:03:49 +08:00
AMOS bot 86f0bb4591 Automatically generated installer lang files 2018-05-01 00:07:45 +00:00
AMOS bot b0d7351cff Automatically generated installer lang files 2018-04-30 00:07:08 +00:00
AMOS bot ad5761237a Automatically generated installer lang files 2018-04-16 00:07:54 +00:00
AMOS bot d98544a729 Automatically generated installer lang files 2018-04-11 00:07:57 +00:00
AMOS bot 1dd71c502a Automatically generated installer lang files 2018-03-31 00:07:48 +00:00
Jun Pataleta fae9236939 weekly release 3.1.11+ 2018-03-29 12:55:45 +08:00
Jun Pataleta 36a7b9f234 Merge branch 'install_31_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_31_STABLE 2018-03-29 12:55:43 +08:00
Jake Dallimore 878d69b794 Merge branch 'MDL-61770-31' of git://github.com/andrewnicols/moodle into MOODLE_31_STABLE 2018-03-28 13:32:54 +08:00
Andrew Nicols 2032491730 MDL-61770 iplookup: Check types rather than values 2018-03-28 11:38:45 +08:00
AMOS bot 7b2fc2b81e Automatically generated installer lang files 2018-03-25 00:06:59 +00:00
AMOS bot c8fe4d8b88 Automatically generated installer lang files 2018-03-21 00:06:46 +00:00
AMOS bot 567c0bb51d Automatically generated installer lang files 2018-03-20 00:06:46 +00:00
AMOS bot fe8a827cb0 Automatically generated installer lang files 2018-03-20 00:06:45 +00:00
138 changed files with 5678 additions and 2766 deletions
+3 -4
View File
@@ -45,12 +45,9 @@ matrix:
fast_finish: true
include:
# Run grunt/npm install on lowest supported npm version
- php: 7
env: DB=none TASK=GRUNT NVM_VERSION='0.10'
# Run grunt/npm install on highest version ('node' is an alias for the latest node.js version.)
- php: 7
env: DB=none TASK=GRUNT NVM_VERSION='node'
env: DB=none TASK=GRUNT NVM_VERSION='lts/carbon'
exclude:
# MySQL - it's just too slow.
@@ -242,7 +239,9 @@ script:
grunt ;
# Add all files to the git index and then run diff --cached to see all changes.
# This ensures that we get the status of all files, including new files.
# We ignore npm-shrinkwrap.json to make the tasks immune to npm changes.
git add . ;
git reset -- npm-shrinkwrap.json ;
git diff --cached --exit-code ;
fi
+364
View File
@@ -2097,6 +2097,7 @@
<VENDOR name="oracle" version="10.2" />
</DATABASE>
<PHP version="7.0.0" level="required">
<RESTRICT function="restrict_php_version_73" message="unsupportedphpversion73" />
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
@@ -2273,6 +2274,7 @@
<VENDOR name="oracle" version="10.2" />
</DATABASE>
<PHP version="7.0.0" level="required">
<RESTRICT function="restrict_php_version_73" message="unsupportedphpversion73" />
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
@@ -2435,4 +2437,366 @@
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="3.6" requires="3.1">
<UNICODE level="required">
<FEEDBACK>
<ON_ERROR message="unicoderequired" />
</FEEDBACK>
</UNICODE>
<DATABASE level="required">
<VENDOR name="mariadb" version="5.5.31" />
<VENDOR name="mysql" version="5.6" />
<VENDOR name="postgres" version="9.4" />
<VENDOR name="mssql" version="10.0" />
<VENDOR name="oracle" version="11.2" />
</DATABASE>
<PHP version="7.0.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="optional">
<FEEDBACK>
<ON_CHECK message="mbstringrecommended" />
</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_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_CHECKS>
</MOODLE>
<MOODLE version="3.7" requires="3.2">
<UNICODE level="required">
<FEEDBACK>
<ON_ERROR message="unicoderequired" />
</FEEDBACK>
</UNICODE>
<DATABASE level="required">
<VENDOR name="mariadb" version="5.5.31" />
<VENDOR name="mysql" version="5.6" />
<VENDOR name="postgres" version="9.4" />
<VENDOR name="mssql" version="10.0" />
<VENDOR name="oracle" version="11.2" />
</DATABASE>
<PHP version="7.1.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="optional">
<FEEDBACK>
<ON_CHECK message="mbstringrecommended" />
</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_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_CHECKS>
</MOODLE>
</COMPATIBILITY_MATRIX>
+3 -1
View File
@@ -32,7 +32,9 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
$ADMIN->add('development', $temp);
// "Profiling" settingpage (conditionally if the 'xhprof' extension is available only).
$xhprofenabled = extension_loaded('xhprof') || extension_loaded('tideways');
$xhprofenabled = extension_loaded('tideways_xhprof');
$xhprofenabled = $xhprofenabled || extension_loaded('tideways');
$xhprofenabled = $xhprofenabled || extension_loaded('xhprof');
$temp = new admin_settingpage('profiling', new lang_string('profiling', 'admin'), 'moodle/site:config', !$xhprofenabled);
// Main profiling switch.
$temp->add(new admin_setting_configcheckbox('profilingenabled', new lang_string('profilingenabled', 'admin'), new lang_string('profilingenabled_help', 'admin'), false));
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/str","core/templates","tool_lp/competency_rule"],function(a,b,c,d){var e=function(){d.apply(this,arguments)};return e.prototype=Object.create(d.prototype),e.prototype._container=null,e.prototype._templateLoaded=!1,e.prototype.getConfig=function(){return JSON.stringify({base:{points:this._getRequiredPoints()},competencies:this._getCompetenciesConfig()})},e.prototype._getCompetenciesConfig=function(){var b=[];return this._container.find("[data-competency]").each(function(){var c=a(this),d=c.data("competency"),e=parseInt(c.find('[name="points"]').val(),10),f=c.find('[name="required"]').prop("checked");b.push({id:d,points:e,required:f?1:0})}),b},e.prototype._getRequiredPoints=function(){return parseInt(this._container.find('[name="requiredpoints"]').val()||1,10)},e.prototype.getType=function(){return"core_competency\\competency_rule_points"},e.prototype.injectTemplate=function(b){var d,e=this,f=this._tree.getChildren(this._competency.id),g={base:{points:2},competencies:[]};if(this._templateLoaded=!1,e._competency.ruletype==e.getType())try{g=JSON.parse(e._competency.ruleconfig)}catch(h){}return d={requiredpoints:g&&g.base?g.base.points:2,competency:e._competency,children:[]},a.each(f,function(b,c){var e={id:c.id,shortname:c.shortname,required:!1,points:0};g&&a.each(g.competencies,function(a,b){b.id==e.id&&(e.required=b.required?!0:!1,e.points=b.points)}),d.children.push(e)}),c.render("tool_lp/competency_rule_points",d).then(function(a){e._container=b,b.html(a),b.find("input").change(function(){e._triggerChange()}),e._templateLoaded=!0,e._triggerChange()})},e.prototype.isValid=function(){if(!this._templateLoaded)return!1;var b=this._getRequiredPoints(),c=0,d=!0;return a.each(this._getCompetenciesConfig(),function(a,b){b.points<0&&(d=!1),c+=b.points}),d=d&&c>=b},e});
define(["jquery","core/str","core/templates","tool_lp/competency_rule"],function(a,b,c,d){var e=function(){d.apply(this,arguments)};return e.prototype=Object.create(d.prototype),e.prototype._container=null,e.prototype._templateLoaded=!1,e.prototype.getConfig=function(){return JSON.stringify({base:{points:this._getRequiredPoints()},competencies:this._getCompetenciesConfig()})},e.prototype._getCompetenciesConfig=function(){var b=[];return this._container.find("[data-competency]").each(function(){var c=a(this),d=c.data("competency"),e=parseInt(c.find('[name="points"]').val(),10),f=c.find('[name="required"]').prop("checked");b.push({id:d,points:e,required:f?1:0})}),b},e.prototype._getRequiredPoints=function(){return parseInt(this._container.find('[name="requiredpoints"]').val()||1,10)},e.prototype.getType=function(){return"core_competency\\competency_rule_points"},e.prototype.injectTemplate=function(b){var d,e=this,f=this._tree.getChildren(this._competency.id),g={base:{points:2},competencies:[]};if(this._templateLoaded=!1,e._competency.ruletype==e.getType())try{g=JSON.parse(e._competency.ruleconfig)}catch(h){}return d={requiredpoints:g&&g.base?g.base.points:2,competency:e._competency,children:[]},a.each(f,function(b,c){var e={id:c.id,shortname:c.shortname,required:!1,points:0};g&&a.each(g.competencies,function(a,b){b.id==e.id&&(e.required=!!b.required,e.points=b.points)}),d.children.push(e)}),c.render("tool_lp/competency_rule_points",d).then(function(a){e._container=b,b.html(a),b.find("input").change(function(){e._triggerChange()}),e._templateLoaded=!0,e._triggerChange()})},e.prototype.isValid=function(){if(!this._templateLoaded)return!1;var b=this._getRequiredPoints(),c=0,d=!0;return a.each(this._getCompetenciesConfig(),function(a,b){b.points<0&&(d=!1),c+=b.points}),d=d&&c>=b},e});
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/notification","core/ajax","core/templates","core/str","tool_lp/tree","tool_lp/competencypicker"],function(a,b,c,d,e,f,g){var h=function(a,b,c){g.prototype.constructor.apply(this,[1,!1,"self",c]),this._userId=a,this._plans=[],b&&(this._planId=b,this._singlePlan=!0)};return h.prototype=Object.create(g.prototype),h.prototype._plans=null,h.prototype._planId=null,h.prototype._singlePlan=!1,h.prototype._userId=null,h.prototype._afterRender=function(){var b=this;g.prototype._afterRender.apply(b,arguments),b._singlePlan||b._find('[data-action="chooseplan"]').change(function(c){b._planId=a(c.target).val(),b._loadCompetencies().then(b._refresh.bind(b))}.bind(b))},h.prototype._fetchCompetencies=function(a,d){var e=this;return c.call([{methodname:"core_competency_list_plan_competencies",args:{id:a}}])[0].done(function(a){var b,c,f=[];for(b=0;b<a.length;b++)c=a[b].competency,c.shortname.toLowerCase().indexOf(d.toLowerCase())<0||(c.children=[],c.haschildren=0,f.push(c));e._competencies=f}).fail(b.exception)},h.prototype._getPlan=function(b){var c;return a.each(this._plans,function(a,d){return d.id==b?(c=d,!1):void 0}),c},h.prototype._loadCompetencies=function(){return this._fetchCompetencies(this._planId,this._searchText)},h.prototype._loadPlans=function(){var d,e=this;return e._plans.length>0?a.when():(d=e._singlePlan?c.call([{methodname:"core_competency_read_plan",args:{id:this._planId}}])[0].then(function(a){return[a]}):c.call([{methodname:"core_competency_list_user_plans",args:{userid:e._userId}}])[0],d.done(function(a){e._plans=a}).fail(b.exception))},h.prototype._preRender=function(){var b=this;return b._loadPlans().then(function(){return!b._planId&&b._plans.length>0&&(b._planId=b._plans[0].id),b._planId?b._loadCompetencies():(b._plans=[],a.when())}.bind(b))},h.prototype._render=function(){var b=this;return b._preRender().then(function(){b._singlePlan||a.each(b._plans,function(a,c){c.id==b._planId?c.selected=!0:c.selected=!1});var c={competencies:b._competencies,plan:b._getPlan(b._planId),plans:b._plans,search:b._searchText,singlePlan:b._singlePlan};return d.render("tool_lp/competency_picker_user_plans",c)}.bind(b))},h});
define(["jquery","core/notification","core/ajax","core/templates","core/str","tool_lp/tree","tool_lp/competencypicker"],function(a,b,c,d,e,f,g){var h=function(a,b,c){g.prototype.constructor.apply(this,[1,!1,"self",c]),this._userId=a,this._plans=[],b&&(this._planId=b,this._singlePlan=!0)};return h.prototype=Object.create(g.prototype),h.prototype._plans=null,h.prototype._planId=null,h.prototype._singlePlan=!1,h.prototype._userId=null,h.prototype._afterRender=function(){var b=this;g.prototype._afterRender.apply(b,arguments),b._singlePlan||b._find('[data-action="chooseplan"]').change(function(c){b._planId=a(c.target).val(),b._loadCompetencies().then(b._refresh.bind(b))}.bind(b))},h.prototype._fetchCompetencies=function(a,d){var e=this;return c.call([{methodname:"core_competency_list_plan_competencies",args:{id:a}}])[0].done(function(a){var b,c,f=[];for(b=0;b<a.length;b++)c=a[b].competency,c.shortname.toLowerCase().indexOf(d.toLowerCase())<0||(c.children=[],c.haschildren=0,f.push(c));e._competencies=f}).fail(b.exception)},h.prototype._getPlan=function(b){var c;return a.each(this._plans,function(a,d){if(d.id==b)return c=d,!1}),c},h.prototype._loadCompetencies=function(){return this._fetchCompetencies(this._planId,this._searchText)},h.prototype._loadPlans=function(){var d,e=this;return e._plans.length>0?a.when():(d=e._singlePlan?c.call([{methodname:"core_competency_read_plan",args:{id:this._planId}}])[0].then(function(a){return[a]}):c.call([{methodname:"core_competency_list_user_plans",args:{userid:e._userId}}])[0],d.done(function(a){e._plans=a}).fail(b.exception))},h.prototype._preRender=function(){var b=this;return b._loadPlans().then(function(){return!b._planId&&b._plans.length>0&&(b._planId=b._plans[0].id),b._planId?b._loadCompetencies():(b._plans=[],a.when())}.bind(b))},h.prototype._render=function(){var b=this;return b._preRender().then(function(){b._singlePlan||a.each(b._plans,function(a,c){c.id==b._planId?c.selected=!0:c.selected=!1});var c={competencies:b._competencies,plan:b._getPlan(b._planId),plans:b._plans,search:b._searchText,singlePlan:b._singlePlan};return d.render("tool_lp/competency_picker_user_plans",c)}.bind(b))},h});
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/notification","core/templates","tool_lp/dialogue","tool_lp/competency_outcomes","core/str"],function(a,b,c,d,e,f){var g=function(b,c){this._eventNode=a("<div></div>"),this._tree=b,this._rulesModules=c,this._setUp()};return g.prototype._competency=null,g.prototype._eventNode=null,g.prototype._outcomesOption=null,g.prototype._popup=null,g.prototype._ready=null,g.prototype._rules=null,g.prototype._rulesModules=null,g.prototype._tree=null,g.prototype._afterChange=function(){this._isValid()?this._find('[data-action="save"]').prop("disabled",!1):this._find('[data-action="save"]').prop("disabled",!0)},g.prototype._afterRuleConfigChange=function(a,b){b==this._getRule()&&this._afterChange()},g.prototype._afterRender=function(){var a=this;a._find('[name="outcome"]').on("change",function(){a._switchedOutcome()}).trigger("change"),a._find('[name="rule"]').on("change",function(){a._switchedRule()}).trigger("change"),a._find('[data-action="save"]').on("click",function(){a._trigger("save",a._getConfig()),a.close()}),a._find('[data-action="cancel"]').on("click",function(){a.close()})},g.prototype.canBeConfigured=function(){var b=!1;return a.each(this._rules,function(a,c){return c.canConfig()?(b=!0,!1):void 0}),b},g.prototype.close=function(){this._popup.close(),this._popup=null},g.prototype.display=function(){var a=this;if(a._competency)return a._render().then(function(b){return f.get_string("competencyrule","tool_lp").then(function(c){a._popup=new d(c,b,a._afterRender.bind(a))})}).fail(b.exception)},g.prototype._find=function(b){return a(this._popup.getContent()).find(b)},g.prototype._getApplicableOutcomesOptions=function(){var b=this,c=[];return a.each(b._outcomesOption,function(a,d){c.push({code:d.code,name:d.name,selected:d.code==b._competency.ruleoutcome?!0:!1})}),c},g.prototype._getApplicableRulesOptions=function(){var b=this,c=[];return a.each(b._rules,function(a,d){d.canConfig()&&c.push({name:b._getRuleName(d.getType()),type:d.getType(),selected:d.getType()==b._competency.ruletype?!0:!1})}),c},g.prototype._getConfig=function(){var a=this._getRule();return{ruletype:a?a.getType():null,ruleconfig:a?a.getConfig():null,ruleoutcome:this._getOutcome()}},g.prototype._getOutcome=function(){return this._find('[name="outcome"]').val()},g.prototype._getRule=function(){var b,c=this._find('[name="rule"]').val();return a.each(this._rules,function(a,d){return d.getType()==c?(b=d,!1):void 0}),b},g.prototype._getRuleName=function(b){var c,d=this;return a.each(d._rulesModules,function(a,d){return d.type==b?(c=d.name,!1):void 0}),c},g.prototype._initOutcomes=function(){var a=this;return e.getAll().then(function(b){a._outcomesOption=b})},g.prototype._initRules=function(){var b=this,c=[];return a.each(b._rules,function(d,e){var f=e.init().then(function(){e.setTargetCompetency(b._competency),e.on("change",b._afterRuleConfigChange.bind(b))},function(){return b._rules.splice(d,1),a.when()});c.push(f)}),a.when.apply(a.when,c)},g.prototype._isValid=function(){var a=this._getOutcome(),b=this._getRule();return a==e.NONE?!0:b?b.isValid():!1},g.prototype.on=function(a,b){this._eventNode.on(a,b)},g.prototype._preRender=function(){return this.ready()},g.prototype.ready=function(){return this._ready.promise()},g.prototype._render=function(){var a=this;return this._preRender().then(function(){var b;a.canBeConfigured()?(b={},b.outcomes=a._getApplicableOutcomesOptions(),b.rules=a._getApplicableRulesOptions()):b=!1;var d={competencyshortname:a._competency.shortname,config:b};return c.render("tool_lp/competency_rule_config",d)})},g.prototype.setTargetCompetencyId=function(b){var c=this;c._competency=c._tree.getCompetency(b),a.each(c._rules,function(a,b){b.setTargetCompetency(c._competency)})},g.prototype._setUp=function(){var b=this,c=[],d=[];b._ready=a.Deferred(),b._rules=[],a.each(b._rulesModules,function(a,b){d.push(b.amd)}),require(d,function(){a.each(arguments,function(a,c){var d=new c(b._tree);b._rules.push(d)}),c.push(b._initRules()),c.push(b._initOutcomes()),a.when.apply(a.when,c).always(function(){b._ready.resolve()})})},g.prototype._switchedOutcome=function(){var a=this,b=a._getOutcome();return b==e.NONE?(a._find('[data-region="rule-type"]').hide().find('[name="rule"]').val(-1),a._find('[data-region="rule-config"]').empty().hide(),void a._afterChange()):(a._find('[data-region="rule-type"]').show(),a._find('[data-region="rule-config"]').show(),void a._afterChange())},g.prototype._switchedRule=function(){var a=this,b=a._find('[data-region="rule-config"]'),c=a._getRule();return c?void c.injectTemplate(b).then(function(){b.show()},function(){b.empty().hide()}).always(function(){a._afterChange()}):(b.empty().hide(),void a._afterChange())},g.prototype._trigger=function(a,b){this._eventNode.trigger(a,[b])},g});
define(["jquery","core/notification","core/templates","tool_lp/dialogue","tool_lp/competency_outcomes","core/str"],function(a,b,c,d,e,f){var g=function(b,c){this._eventNode=a("<div></div>"),this._tree=b,this._rulesModules=c,this._setUp()};return g.prototype._competency=null,g.prototype._eventNode=null,g.prototype._outcomesOption=null,g.prototype._popup=null,g.prototype._ready=null,g.prototype._rules=null,g.prototype._rulesModules=null,g.prototype._tree=null,g.prototype._afterChange=function(){this._isValid()?this._find('[data-action="save"]').prop("disabled",!1):this._find('[data-action="save"]').prop("disabled",!0)},g.prototype._afterRuleConfigChange=function(a,b){b==this._getRule()&&this._afterChange()},g.prototype._afterRender=function(){var a=this;a._find('[name="outcome"]').on("change",function(){a._switchedOutcome()}).trigger("change"),a._find('[name="rule"]').on("change",function(){a._switchedRule()}).trigger("change"),a._find('[data-action="save"]').on("click",function(){a._trigger("save",a._getConfig()),a.close()}),a._find('[data-action="cancel"]').on("click",function(){a.close()})},g.prototype.canBeConfigured=function(){var b=!1;return a.each(this._rules,function(a,c){if(c.canConfig())return b=!0,!1}),b},g.prototype.close=function(){this._popup.close(),this._popup=null},g.prototype.display=function(){var a=this;if(a._competency)return a._render().then(function(b){return f.get_string("competencyrule","tool_lp").then(function(c){a._popup=new d(c,b,a._afterRender.bind(a))})}).fail(b.exception)},g.prototype._find=function(b){return a(this._popup.getContent()).find(b)},g.prototype._getApplicableOutcomesOptions=function(){var b=this,c=[];return a.each(b._outcomesOption,function(a,d){c.push({code:d.code,name:d.name,selected:d.code==b._competency.ruleoutcome})}),c},g.prototype._getApplicableRulesOptions=function(){var b=this,c=[];return a.each(b._rules,function(a,d){d.canConfig()&&c.push({name:b._getRuleName(d.getType()),type:d.getType(),selected:d.getType()==b._competency.ruletype})}),c},g.prototype._getConfig=function(){var a=this._getRule();return{ruletype:a?a.getType():null,ruleconfig:a?a.getConfig():null,ruleoutcome:this._getOutcome()}},g.prototype._getOutcome=function(){return this._find('[name="outcome"]').val()},g.prototype._getRule=function(){var b,c=this._find('[name="rule"]').val();return a.each(this._rules,function(a,d){if(d.getType()==c)return b=d,!1}),b},g.prototype._getRuleName=function(b){var c,d=this;return a.each(d._rulesModules,function(a,d){if(d.type==b)return c=d.name,!1}),c},g.prototype._initOutcomes=function(){var a=this;return e.getAll().then(function(b){a._outcomesOption=b})},g.prototype._initRules=function(){var b=this,c=[];return a.each(b._rules,function(d,e){var f=e.init().then(function(){e.setTargetCompetency(b._competency),e.on("change",b._afterRuleConfigChange.bind(b))},function(){return b._rules.splice(d,1),a.when()});c.push(f)}),a.when.apply(a.when,c)},g.prototype._isValid=function(){var a=this._getOutcome(),b=this._getRule();return a==e.NONE||!!b&&b.isValid()},g.prototype.on=function(a,b){this._eventNode.on(a,b)},g.prototype._preRender=function(){return this.ready()},g.prototype.ready=function(){return this._ready.promise()},g.prototype._render=function(){var a=this;return this._preRender().then(function(){var b;a.canBeConfigured()?(b={},b.outcomes=a._getApplicableOutcomesOptions(),b.rules=a._getApplicableRulesOptions()):b=!1;var d={competencyshortname:a._competency.shortname,config:b};return c.render("tool_lp/competency_rule_config",d)})},g.prototype.setTargetCompetencyId=function(b){var c=this;c._competency=c._tree.getCompetency(b),a.each(c._rules,function(a,b){b.setTargetCompetency(c._competency)})},g.prototype._setUp=function(){var b=this,c=[],d=[];b._ready=a.Deferred(),b._rules=[],a.each(b._rulesModules,function(a,b){d.push(b.amd)}),require(d,function(){a.each(arguments,function(a,c){var d=new c(b._tree);b._rules.push(d)}),c.push(b._initRules()),c.push(b._initOutcomes()),a.when.apply(a.when,c).always(function(){b._ready.resolve()})})},g.prototype._switchedOutcome=function(){var a=this,b=a._getOutcome();return b==e.NONE?(a._find('[data-region="rule-type"]').hide().find('[name="rule"]').val(-1),a._find('[data-region="rule-config"]').empty().hide(),void a._afterChange()):(a._find('[data-region="rule-type"]').show(),a._find('[data-region="rule-config"]').show(),void a._afterChange())},g.prototype._switchedRule=function(){var a=this,b=a._find('[data-region="rule-config"]'),c=a._getRule();return c?void c.injectTemplate(b).then(function(){b.show()},function(){b.empty().hide()}).always(function(){a._afterChange()}):(b.empty().hide(),void a._afterChange())},g.prototype._trigger=function(a,b){this._eventNode.trigger(a,[b])},g});
+1 -1
View File
@@ -1 +1 @@
define(["core/ajax","core/notification","core/templates","tool_lp/tree","tool_lp/competency_outcomes","jquery"],function(a,b,c,d,e,f){var g={},h=0,i="",j="",k="",l=!1,m=function(a,b){var c=0,d=!1;for(a.haschildren=!1,a.children=[],c=0;c<b.length;c++)d=b[c],d.parentid==a.id&&(a.haschildren=!0,a.children.push(d),m(d,b))},n=function(b){var e=f.Deferred();return c.render("tool_lp/loading",{}).done(function(n,o){c.replaceNodeContents(f(j),n,o);var p=a.call([{methodname:"core_competency_search_competencies",args:{searchtext:b,competencyframeworkid:h}}]);p[0].done(function(a){g={};var b=0;for(b=0;b<a.length;b++)g[a[b].id]=a[b];var h=[],n=!1;for(b=0;b<a.length;b++)n=a[b],0===parseInt(n.parentid,10)&&(h.push(n),m(n,a));var o={shortname:i,canmanage:l,competencies:h};c.render("tool_lp/competencies_tree_root",o).done(function(a,b){c.replaceNodeContents(f(j),f(a).html(),b);var h=new d(j,!1);if(k){var i=f(j).find("[data-id="+k+"]");i.length&&(h.selectItem(i),h.updateFocus(i))}e.resolve(g)}).fail(e.reject)}).fail(e.reject)}),e.promise()},o=function(a,b){var c=b.selected;k=c.attr("data-id")};return{init:function(a,c,d,e,f){h=a,i=c,l=f,j=e,n(d).fail(b.exception),this.on("selectionchanged",o)},on:function(a,b){f(j).on(a,b)},getChildren:function(a){var b=[];return f.each(g,function(c,d){d.parentid==a&&b.push(d)}),b},getCompetencyFrameworkId:function(){return h},getCompetency:function(a){return g[a]},getCompetencyLevel:function(a){var b=this.getCompetency(a),c=b.path.replace(/^\/|\/$/g,"").split("/").length;return c},hasChildren:function(a){return this.getChildren(a).length>0},hasRule:function(a){var b=this.getCompetency(a);return b?b.ruleoutcome!=e.OUTCOME_NONE&&b.ruletype:!1},reloadCompetencies:function(){return n("").fail(b.exception)},listCompetencies:function(){return g}}});
define(["core/ajax","core/notification","core/templates","tool_lp/tree","tool_lp/competency_outcomes","jquery"],function(a,b,c,d,e,f){var g={},h=0,i="",j="",k="",l=!1,m=function(a,b){var c=0,d=!1;for(a.haschildren=!1,a.children=[],c=0;c<b.length;c++)d=b[c],d.parentid==a.id&&(a.haschildren=!0,a.children.push(d),m(d,b))},n=function(b){var e=f.Deferred();return c.render("tool_lp/loading",{}).done(function(n,o){c.replaceNodeContents(f(j),n,o);var p=a.call([{methodname:"core_competency_search_competencies",args:{searchtext:b,competencyframeworkid:h}}]);p[0].done(function(a){g={};var b=0;for(b=0;b<a.length;b++)g[a[b].id]=a[b];var h=[],n=!1;for(b=0;b<a.length;b++)n=a[b],0===parseInt(n.parentid,10)&&(h.push(n),m(n,a));var o={shortname:i,canmanage:l,competencies:h};c.render("tool_lp/competencies_tree_root",o).done(function(a,b){c.replaceNodeContents(f(j),f(a).html(),b);var h=new d(j,(!1));if(k){var i=f(j).find("[data-id="+k+"]");i.length&&(h.selectItem(i),h.updateFocus(i))}e.resolve(g)}).fail(e.reject)}).fail(e.reject)}),e.promise()},o=function(a,b){var c=b.selected;k=c.attr("data-id")};return{init:function(a,c,d,e,f){h=a,i=c,l=f,j=e,n(d).fail(b.exception),this.on("selectionchanged",o)},on:function(a,b){f(j).on(a,b)},getChildren:function(a){var b=[];return f.each(g,function(c,d){d.parentid==a&&b.push(d)}),b},getCompetencyFrameworkId:function(){return h},getCompetency:function(a){return g[a]},getCompetencyLevel:function(a){var b=this.getCompetency(a),c=b.path.replace(/^\/|\/$/g,"").split("/").length;return c},hasChildren:function(a){return this.getChildren(a).length>0},hasRule:function(a){var b=this.getCompetency(a);return!!b&&(b.ruleoutcome!=e.OUTCOME_NONE&&b.ruletype)},reloadCompetencies:function(){return n("").fail(b.exception)},listCompetencies:function(){return g}}});
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/ajax","core/str","tool_lp/competencypicker","core/templates","core/notification"],function(a,b,c,d,e,f){var g=function(a,b,c,d,e){this.buttonSelector=a,this.inputHiddenSelector=b,this.staticElementSelector=c,this.frameworkId=d,this.pageContextId=e,this.registerEvents()};return g.prototype.buttonSelector=null,g.prototype.inputHiddenSelector=null,g.prototype.staticElementSelector=null,g.prototype.frameworkId=null,g.prototype.pageContextId=null,g.prototype.setParent=function(d){var e=this;0!==d.competencyId?b.call([{methodname:"core_competency_read_competency",args:{id:d.competencyId}}])[0].done(function(b){a(e.staticElementSelector).html(b.shortname),a(e.inputHiddenSelector).val(b.id)}).fail(f.exception):c.get_string("competencyframeworkroot","tool_lp").then(function(b){a(e.staticElementSelector).html(b),a(e.inputHiddenSelector).val(d.competencyId)}).fail(f.exception)},g.prototype.registerEvents=function(){var b=this;a(b.buttonSelector).on("click",function(a){a.preventDefault();var c=new d(b.pageContextId,b.frameworkId,"self",!1);c._render=function(){var a=this;return a._preRender().then(function(){var b={competencies:a._competencies,framework:a._getFramework(a._frameworkId),frameworks:a._frameworks,search:a._searchText,singleFramework:a._singleFramework};return e.render("tool_lp/competency_picker_competencyform",b)}.bind(a))},c.on("save",function(a,c){b.setParent(c)}.bind(b)),c.display()})},{init:function(a,b,c,d,e){new g(a,b,c,d,e)}}});
define(["jquery","core/ajax","core/str","tool_lp/competencypicker","core/templates","core/notification"],function(a,b,c,d,e,f){var g=function(a,b,c,d,e){this.buttonSelector=a,this.inputHiddenSelector=b,this.staticElementSelector=c,this.frameworkId=d,this.pageContextId=e,this.registerEvents()};return g.prototype.buttonSelector=null,g.prototype.inputHiddenSelector=null,g.prototype.staticElementSelector=null,g.prototype.frameworkId=null,g.prototype.pageContextId=null,g.prototype.setParent=function(d){var e=this;0!==d.competencyId?b.call([{methodname:"core_competency_read_competency",args:{id:d.competencyId}}])[0].done(function(b){a(e.staticElementSelector).html(b.shortname),a(e.inputHiddenSelector).val(b.id)}).fail(f.exception):c.get_string("competencyframeworkroot","tool_lp").then(function(b){a(e.staticElementSelector).html(b),a(e.inputHiddenSelector).val(d.competencyId)}).fail(f.exception)},g.prototype.registerEvents=function(){var b=this;a(b.buttonSelector).on("click",function(a){a.preventDefault();var c=new d(b.pageContextId,b.frameworkId,"self",(!1));c._render=function(){var a=this;return a._preRender().then(function(){var b={competencies:a._competencies,framework:a._getFramework(a._frameworkId),frameworks:a._frameworks,search:a._searchText,singleFramework:a._singleFramework};return e.render("tool_lp/competency_picker_competencyform",b)}.bind(a))},c.on("save",function(a,c){b.setParent(c)}.bind(b)),c.display()})},{init:function(a,b,c,d,e){new g(a,b,c,d,e)}}});
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/notification","core/ajax","core/templates"],function(a,b,c,d){var e=function(a,b,c,d,e,f){this._rootElement=a,this._competencyId=b,this._userId=c,this._planId=d,this._courseId=e,this._valid=!0,this._displayuser="undefined"!=typeof f?f:!1,this._planId?(this._methodName="tool_lp_data_for_user_competency_summary_in_plan",this._args={competencyid:this._competencyId,planid:this._planId},this._templateName="tool_lp/user_competency_summary_in_plan"):this._courseId?(this._methodName="tool_lp_data_for_user_competency_summary_in_course",this._args={userid:this._userId,competencyid:this._competencyId,courseid:this._courseId},this._templateName="tool_lp/user_competency_summary_in_course"):(this._methodName="tool_lp_data_for_user_competency_summary",this._args={userid:this._userId,competencyid:this._competencyId},this._templateName="tool_lp/user_competency_summary")};return e.prototype.reload=function(){var a=this,e=[];this._valid&&(e=c.call([{methodname:this._methodName,args:this._args}]),e[0].done(function(c){a._displayuser&&(c.displayuser=!0),d.render(a._templateName,c).done(function(b,c){d.replaceNode(a._rootElement,b,c)}).fail(b.exception)}).fail(b.exception))},e.prototype._rootElement=null,e.prototype._courseId=null,e.prototype._valid=null,e.prototype._planId=null,e.prototype._competencyId=null,e.prototype._userId=null,e.prototype._methodName=null,e.prototype._args=null,e.prototype._templateName=null,e.prototype._displayuser=!1,e});
define(["jquery","core/notification","core/ajax","core/templates"],function(a,b,c,d){var e=function(a,b,c,d,e,f){this._rootElement=a,this._competencyId=b,this._userId=c,this._planId=d,this._courseId=e,this._valid=!0,this._displayuser="undefined"!=typeof f&&f,this._planId?(this._methodName="tool_lp_data_for_user_competency_summary_in_plan",this._args={competencyid:this._competencyId,planid:this._planId},this._templateName="tool_lp/user_competency_summary_in_plan"):this._courseId?(this._methodName="tool_lp_data_for_user_competency_summary_in_course",this._args={userid:this._userId,competencyid:this._competencyId,courseid:this._courseId},this._templateName="tool_lp/user_competency_summary_in_course"):(this._methodName="tool_lp_data_for_user_competency_summary",this._args={userid:this._userId,competencyid:this._competencyId},this._templateName="tool_lp/user_competency_summary")};return e.prototype.reload=function(){var a=this,e=[];this._valid&&(e=c.call([{methodname:this._methodName,args:this._args}]),e[0].done(function(c){a._displayuser&&(c.displayuser=!0),d.render(a._templateName,c).done(function(b,c){d.replaceNode(a._rootElement,b,c)}).fail(b.exception)}).fail(b.exception))},e.prototype._rootElement=null,e.prototype._courseId=null,e.prototype._valid=null,e.prototype._planId=null,e.prototype._competencyId=null,e.prototype._userId=null,e.prototype._methodName=null,e.prototype._args=null,e.prototype._templateName=null,e.prototype._displayuser=!1,e});
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/notification","core/str","core/ajax","core/templates","tool_lp/dialogue"],function(a,b,c,d,e,f){var g=function(b,c,d){this._regionSelector=b,this._userCompetencySelector=c,this._planId=d,a(this._regionSelector).on("click",this._userCompetencySelector,this._handleClick.bind(this))};return g.prototype._handleClick=function(c){c.preventDefault();var e=a(c.target).closest("tr"),f=a(e).data("competencyid"),g=a(e).data("userid"),h=this._planId,i=d.call([{methodname:"tool_lp_data_for_user_competency_summary_in_plan",args:{competencyid:f,planid:h},done:this._contextLoaded.bind(this),fail:b.exception}]);i[0].then(function(a){var c="core_competency_user_competency_viewed_in_plan";a.plan.iscompleted&&(c="core_competency_user_competency_plan_viewed"),d.call([{methodname:c,args:{competencyid:f,userid:g,planid:h},fail:b.exception}])})},g.prototype._contextLoaded=function(a){var d=this;e.render("tool_lp/user_competency_summary_in_plan",a).done(function(a,g){c.get_string("usercompetencysummary","report_competency").done(function(b){new f(b,a,e.runTemplateJS.bind(e,g),d._refresh.bind(d),!0)}).fail(b.exception)}).fail(b.exception)},g.prototype._refresh=function(){var a=this._planId;d.call([{methodname:"tool_lp_data_for_plan_page",args:{planid:a},done:this._pageContextLoaded.bind(this),fail:b.exception}])},g.prototype._pageContextLoaded=function(a){var c=this;e.render("tool_lp/plan_page",a).done(function(a,b){e.replaceNode(c._regionSelector,a,b)}).fail(b.exception)},g.prototype._regionSelector=null,g.prototype._userCompetencySelector=null,g.prototype._planId=null,g});
define(["jquery","core/notification","core/str","core/ajax","core/templates","tool_lp/dialogue"],function(a,b,c,d,e,f){var g=function(b,c,d){this._regionSelector=b,this._userCompetencySelector=c,this._planId=d,a(this._regionSelector).on("click",this._userCompetencySelector,this._handleClick.bind(this))};return g.prototype._handleClick=function(c){c.preventDefault();var e=a(c.target).closest("tr"),f=a(e).data("competencyid"),g=a(e).data("userid"),h=this._planId,i=d.call([{methodname:"tool_lp_data_for_user_competency_summary_in_plan",args:{competencyid:f,planid:h},done:this._contextLoaded.bind(this),fail:b.exception}]);i[0].then(function(a){var c="core_competency_user_competency_viewed_in_plan";a.plan.iscompleted&&(c="core_competency_user_competency_plan_viewed"),d.call([{methodname:c,args:{competencyid:f,userid:g,planid:h},fail:b.exception}])})},g.prototype._contextLoaded=function(a){var d=this;e.render("tool_lp/user_competency_summary_in_plan",a).done(function(a,g){c.get_string("usercompetencysummary","report_competency").done(function(b){new f(b,a,e.runTemplateJS.bind(e,g),d._refresh.bind(d),(!0))}).fail(b.exception)}).fail(b.exception)},g.prototype._refresh=function(){var a=this._planId;d.call([{methodname:"tool_lp_data_for_plan_page",args:{planid:a},done:this._pageContextLoaded.bind(this),fail:b.exception}])},g.prototype._pageContextLoaded=function(a){var c=this;e.render("tool_lp/plan_page",a).done(function(a,b){e.replaceNode(c._regionSelector,a,b)}).fail(b.exception)},g.prototype._regionSelector=null,g.prototype._userCompetencySelector=null,g.prototype._planId=null,g});
+6 -2
View File
@@ -25,8 +25,12 @@
defined('MOODLE_INTERNAL') || die;
// profiling tool, added to development
if ((extension_loaded('xhprof') || extension_loaded('tideways')) && (!empty($CFG->profilingenabled) || !empty($CFG->earlyprofilingenabled))) {
// Profiling tool, added to development.
$hasextension = extension_loaded('tideways_xhprof');
$hasextension = $hasextension || extension_loaded('tideways');
$hasextension = $hasextension || extension_loaded('xhprof');
$isenabled = !empty($CFG->profilingenabled) || !empty($CFG->earlyprofilingenabled);
if ($hasextension && $isenabled) {
$ADMIN->add('development', new admin_externalpage('toolprofiling', get_string('pluginname', 'tool_profiling'),
"$CFG->wwwroot/$CFG->admin/tool/profiling/index.php", 'moodle/site:config'));
}
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/ajax","core/log","core/notification","core/templates","core/config","core/str"],function(a,b,c,d,e,f,g){var h=function(a,b){if(!a)return!1;var c="@template "+b,d=0,e=[];if(e=a.match(/{{!([\s\S]*?)}}/g),null!==e)for(d=0;d<e.length;d++){var f=e[d],g=f.indexOf(c);if(-1!==g){var h=g+c.length+1;return f=f.substr(h,f.length-2-h)}}return!1},i=function(b,f,i){g.get_string("templateselected","tool_templatelibrary",b).done(function(b){a('[data-region="displaytemplateheader"]').text(b)}).fail(d.exception);var j=h(f,b);j===!1&&(j=h(i,b)),j&&(f=j),a('[data-region="displaytemplatesource"]').text(f);var k=f.match(/Example context \(json\):([\s\S]*)/),l=!1;if(k){var m=k[1].trim();try{l=a.parseJSON(m)}catch(n){c.debug("Could not parse json example context for template."),c.debug(n)}}l?e.render(b,l).done(function(b,c){e.replaceNodeContents(a('[data-region="displaytemplateexample"]'),b,c)}).fail(d.exception):g.get_string("templatehasnoexample","tool_templatelibrary").done(function(b){a('[data-region="displaytemplateexample"]').text(b)}).fail(d.exception)},j=function(c){var e=c.split("/"),g=e.shift(),h=e.shift(),j=b.call([{methodname:"core_output_load_template",args:{component:g,template:h,themename:f.theme}},{methodname:"tool_templatelibrary_load_canonical_template",args:{component:g,template:h}}],!0,!1);a.when.apply(a,j).done(function(a,b){i(c,a,b)}).fail(d.exception)};return a('[data-region="list-templates"]').on("click","[data-templatename]",function(b){var c=a(this).data("templatename");b.preventDefault(),j(c)}),{}});
define(["jquery","core/ajax","core/log","core/notification","core/templates","core/config","core/str"],function(a,b,c,d,e,f,g){var h=function(a,b){if(!a)return!1;var c="@template "+b,d=0,e=[];if(e=a.match(/{{!([\s\S]*?)}}/g),null!==e)for(d=0;d<e.length;d++){var f=e[d],g=f.indexOf(c);if(g!==-1){var h=g+c.length+1;return f=f.substr(h,f.length-2-h)}}return!1},i=function(b,f,i){g.get_string("templateselected","tool_templatelibrary",b).done(function(b){a('[data-region="displaytemplateheader"]').text(b)}).fail(d.exception);var j=h(f,b);j===!1&&(j=h(i,b)),j&&(f=j),a('[data-region="displaytemplatesource"]').text(f);var k=f.match(/Example context \(json\):([\s\S]*)/),l=!1;if(k){var m=k[1].trim();try{l=a.parseJSON(m)}catch(n){c.debug("Could not parse json example context for template."),c.debug(n)}}l?e.render(b,l).done(function(b,c){e.replaceNodeContents(a('[data-region="displaytemplateexample"]'),b,c)}).fail(d.exception):g.get_string("templatehasnoexample","tool_templatelibrary").done(function(b){a('[data-region="displaytemplateexample"]').text(b)}).fail(d.exception)},j=function(c){var e=c.split("/"),g=e.shift(),h=e.shift(),j=b.call([{methodname:"core_output_load_template",args:{component:g,template:h,themename:f.theme}},{methodname:"tool_templatelibrary_load_canonical_template",args:{component:g,template:h}}],!0,!1);a.when.apply(a,j).done(function(a,b){i(c,a,b)}).fail(d.exception)};return a('[data-region="list-templates"]').on("click","[data-templatename]",function(b){var c=a(this).data("templatename");b.preventDefault(),j(c)}),{}});
+2
View File
@@ -154,6 +154,7 @@ class auth_plugin_cas extends auth_plugin_ldap {
$frm = new stdClass();
$frm->username = phpCAS::getUser();
$frm->password = 'passwdCas';
$frm->logintoken = \core\session\manager::get_login_token();
// Redirect to a course if multi-auth is activated, authCAS is set to CAS and the courseid is specified.
if ($this->config->multiauth && !empty($courseid)) {
@@ -167,6 +168,7 @@ class auth_plugin_cas extends auth_plugin_ldap {
$frm = new stdClass();
$frm->username = 'guest';
$frm->password = 'guest';
$frm->logintoken = \core\session\manager::get_login_token();
return;
}
+2 -1
View File
@@ -1762,7 +1762,8 @@ class auth_plugin_ldap extends auth_plugin_base {
// Here we want to trigger the whole authentication machinery
// to make sure no step is bypassed...
$user = authenticate_user_login($username, $key);
$reason = null;
$user = authenticate_user_login($username, $key, false, $reason, false);
if ($user) {
complete_user_login($user);
+2 -1
View File
@@ -49,9 +49,10 @@
$frm->password = generate_password(8);
/// Check if the user has actually submitted login data to us
$reason = null;
if ($shibbolethauth->user_login($frm->username, $frm->password)
&& $user = authenticate_user_login($frm->username, $frm->password)) {
&& $user = authenticate_user_login($frm->username, $frm->password, false, $reason, false)) {
complete_user_login($user);
if (user_not_fully_set_up($USER, true)) {
+1
View File
@@ -54,6 +54,7 @@ if ($show_instructions) {
</div>
<form action="../../login/index.php" method="post" id="guestlogin">
<div class="guestform">
<input type="hidden" name="logintoken" value="<?php echo s(\core\session\manager::get_login_token()); ?>" />
<input type="hidden" name="username" value="guest" />
<input type="hidden" name="password" value="guest" />
<input type="submit" value="<?php print_string("loginguest") ?>" />
+13 -1
View File
@@ -69,7 +69,19 @@ $PAGE->https_required();
$PAGE->set_heading($site->fullname);
echo $OUTPUT->header();
include("index_form.html");
if (isloggedin() and !isguestuser()) {
// Prevent logging when already logged in, we do not want them to relogin by accident because sesskey would be changed.
echo $OUTPUT->box_start();
$params = array('sesskey' => sesskey(), 'loginpage' => 1);
$logout = new single_button(new moodle_url('/login/logout.php', $params), get_string('logout'), 'post');
$continue = new single_button(new moodle_url('/'), get_string('cancel'), 'get');
echo $OUTPUT->confirm(get_string('alreadyloggedin', 'error', fullname($USER)), $logout, $continue);
echo $OUTPUT->box_end();
} else {
include("index_form.html");
}
echo $OUTPUT->footer();
+4
View File
@@ -1,6 +1,10 @@
This files describes API changes in /auth/* - plugins,
information provided here is intended especially for developers.
=== 3.1.15 ===
* Login forms generated from Moodle must include a login token to protect automated logins. See \core\session\manager::get_login_token().
=== 3.0 ===
* login_signup_form::signup_captcha_enabled() now calls is_captcha_enabled() from the current auth plugin instead of from auth_email
+1 -4
View File
@@ -50,9 +50,6 @@ class edit_backpack_form extends moodleform {
$mform->addElement('hidden', 'userid', $USER->id);
$mform->setType('userid', PARAM_INT);
$mform->addElement('hidden', 'backpackurl', BADGE_BACKPACKURL);
$mform->setType('backpackurl', PARAM_URL);
if (isset($this->_customdata['email'])) {
// Email will be passed in when we're in the process of verifying the user's email address,
// so set the connection status, lock the email field, and provide options to resend the verification
@@ -94,7 +91,7 @@ class edit_backpack_form extends moodleform {
// We don't need to verify the email address if we're clearing a pending email verification attempt.
if (!isset($data['revertbutton'])) {
$check = new stdClass();
$check->backpackurl = $data['backpackurl'];
$check->backpackurl = BADGE_BACKPACKURL;
$check->email = $data['email'];
$bp = new OpenBadgesBackpackHandler($check);
+45 -26
View File
@@ -50,6 +50,12 @@ class block_edit_form extends moodleform {
*/
public $page;
/**
* Defaults set in set_data() that need to be returned in get_data() if form elements were not created
* @var array
*/
protected $defaults = [];
function __construct($actionurl, $block, $page) {
global $CFG;
$this->block = $block;
@@ -92,9 +98,6 @@ class block_edit_form extends moodleform {
}
$parentcontext = context::instance_by_id($this->block->instance->parentcontextid);
$mform->addElement('hidden', 'bui_parentcontextid', $parentcontext->id);
$mform->setType('bui_parentcontextid', PARAM_INT);
$mform->addElement('static', 'bui_homecontext', get_string('createdat', 'block'), $parentcontext->get_context_name());
$mform->addHelpButton('bui_homecontext', 'createdat', 'block');
@@ -109,21 +112,9 @@ class block_edit_form extends moodleform {
// implies one (and only one) harcoded page-type that will be set later
// when processing the form data at {@link block_manager::process_url_edit()}
// There are some conditions to check related to contexts
$ctxconditions = $this->page->context->contextlevel == CONTEXT_COURSE &&
$this->page->context->instanceid == get_site()->id;
// And also some pagetype conditions
$pageconditions = isset($bits[0]) && isset($bits[1]) && $bits[0] == 'site' && $bits[1] == 'index';
// So now we can be 100% sure if edition is happening at frontpage
$editingatfrontpage = $ctxconditions && $pageconditions;
// Let the form to know about that, can be useful later
$mform->addElement('hidden', 'bui_editingatfrontpage', (int)$editingatfrontpage);
$mform->setType('bui_editingatfrontpage', PARAM_INT);
// Front page, show the page-contexts element and set $pagetypelist to 'any page' (*)
// as unique option. Processign the form will do any change if needed
if ($editingatfrontpage) {
if ($this->is_editing_the_frontpage()) {
$contextoptions = array();
$contextoptions[BUI_CONTEXTS_FRONTPAGE_ONLY] = get_string('showonfrontpageonly', 'block');
$contextoptions[BUI_CONTEXTS_FRONTPAGE_SUBS] = get_string('showonfrontpageandsubs', 'block');
@@ -135,16 +126,13 @@ class block_edit_form extends moodleform {
// Any other system context block, hide the page-contexts element,
// it's always system-wide BUI_CONTEXTS_ENTIRE_SITE
} else if ($parentcontext->contextlevel == CONTEXT_SYSTEM) {
$mform->addElement('hidden', 'bui_contexts', BUI_CONTEXTS_ENTIRE_SITE);
} else if ($parentcontext->contextlevel == CONTEXT_COURSE) {
// 0 means display on current context only, not child contexts
// but if course managers select mod-* as pagetype patterns, block system will overwrite this option
// to 1 (display on current context and child contexts)
$mform->addElement('hidden', 'bui_contexts', BUI_CONTEXTS_CURRENT);
} else if ($parentcontext->contextlevel == CONTEXT_MODULE or $parentcontext->contextlevel == CONTEXT_USER) {
// module context doesn't have child contexts, so display in current context only
$mform->addElement('hidden', 'bui_contexts', BUI_CONTEXTS_CURRENT);
} else {
$parentcontextname = $parentcontext->get_context_name();
$contextoptions[BUI_CONTEXTS_CURRENT] = get_string('showoncontextonly', 'block', $parentcontextname);
@@ -181,8 +169,6 @@ class block_edit_form extends moodleform {
} else {
$values = array_keys($pagetypelist);
$value = array_pop($values);
$mform->addElement('hidden', 'bui_pagetypepattern', $value);
$mform->setType('bui_pagetypepattern', PARAM_RAW);
// Now we are really hiding a lot (both page-contexts and page-type-patterns),
// specially in some systemcontext pages having only one option (my/user...)
// so, until it's decided if we are going to add the 'bring-back' pattern to
@@ -191,7 +177,7 @@ class block_edit_form extends moodleform {
// TODO: Revisit this once MDL-30574 has been decided and implemented, although
// perhaps it's not bad to always show this statically when only one pattern is
// available.
if (!$editingatfrontpage) {
if (!$this->is_editing_the_frontpage()) {
// Try to beautify it
$strvalue = $value;
$strkey = 'page-'.str_replace('*', 'x', $strvalue);
@@ -205,10 +191,7 @@ class block_edit_form extends moodleform {
}
if ($this->page->subpage) {
if ($parentcontext->contextlevel == CONTEXT_USER) {
$mform->addElement('hidden', 'bui_subpagepattern', '%@NULL@%');
$mform->setType('bui_subpagepattern', PARAM_RAW);
} else {
if ($parentcontext->contextlevel != CONTEXT_USER) {
$subpageoptions = array(
'%@NULL@%' => get_string('anypagematchingtheabove', 'block'),
$this->page->subpage => get_string('thisspecificpage', 'block', $this->page->subpage),
@@ -252,6 +235,19 @@ class block_edit_form extends moodleform {
$this->add_action_buttons();
}
/**
* Returns true if the user is editing a frontpage.
* @return bool
*/
public function is_editing_the_frontpage() {
// There are some conditions to check related to contexts.
$ctxconditions = $this->page->context->contextlevel == CONTEXT_COURSE &&
$this->page->context->instanceid == get_site()->id;
$issiteindex = (strpos($this->page->pagetype, 'site-index') === 0);
// So now we can be 100% sure if edition is happening at frontpage.
return ($ctxconditions && $issiteindex);
}
function set_data($defaults) {
// Prefix bui_ on all the core field names.
$blockfields = array('showinsubcontexts', 'pagetypepattern', 'subpagepattern', 'parentcontextid',
@@ -281,6 +277,13 @@ class block_edit_form extends moodleform {
$defaults->bui_contexts = $defaults->bui_showinsubcontexts;
}
// Some fields may not be editable, remember the values here so we can return them in get_data().
$this->defaults = [
'bui_parentcontextid' => $defaults->bui_parentcontextid,
'bui_contexts' => $defaults->bui_contexts,
'bui_pagetypepattern' => $defaults->bui_pagetypepattern,
'bui_subpagepattern' => $defaults->bui_subpagepattern,
];
parent::set_data($defaults);
}
@@ -291,4 +294,20 @@ class block_edit_form extends moodleform {
protected function specific_definition($mform) {
// By default, do nothing.
}
/**
* Return submitted data if properly submitted or returns NULL if validation fails or
* if there is no submitted data.
*
* @return object submitted data; NULL if not valid or not submitted or cancelled
*/
public function get_data() {
if ($data = parent::get_data()) {
// Blocklib expects 'bui_editingatfrontpage' property to be returned from this form.
$data->bui_editingatfrontpage = $this->is_editing_the_frontpage();
// Some fields are non-editable and we need to populate them with the values from set_data().
return (object)((array)$data + $this->defaults);
}
return $data;
}
}
+1
View File
@@ -92,6 +92,7 @@ class block_login extends block_base {
}
$this->content->text .= '<div class="c1 btn"><input type="submit" value="'.get_string('login').'" /></div>';
$this->content->text .= '<input type="hidden" name="logintoken" value="'.s(\core\session\manager::get_login_token()).'" />';
$this->content->text .= "</form>\n";
+1 -1
View File
@@ -1 +1 @@
define(["jquery"],function(a){function b(d,e){var f=a("<ul></ul>");f.attr("role","group"),f.attr("aria-hidden",!0),a.each(e,function(d,e){if("object"==typeof e){var g=a("<li></li>"),h=a("<p></p>"),i=e.id||e.key+"_tree_item",j=null,k=e.expandable||e.haschildren?!0:!1;if(h.addClass("tree_item"),h.attr("id",i),h.attr("role","treeitem"),h.attr("tabindex","-1"),e.requiresajaxloading&&(h.attr("data-requires-ajax",!0),h.attr("data-node-id",e.id),h.attr("data-node-key",e.key),h.attr("data-node-type",e.type)),k&&(g.addClass("collapsed contains_branch"),h.attr("aria-expanded",!1),h.addClass("branch")),!e.icon||k&&e.type!==c.ACTIVITY&&e.type!==c.RESOURCE||(g.addClass("item_with_icon"),h.addClass("hasicon"),j=a("<img/>"),j.attr("alt",e.icon.alt),j.attr("title",e.icon.title),j.attr("src",M.util.image_url(e.icon.pix,e.icon.component)),a.each(e.icon.classes,function(a,b){j.addClass(b)})),e.link){var l=a('<a title="'+e.title+'" href="'+e.link+'"></a>');j?(l.append(j),l.append('<span class="item-content-wrap">'+e.name+"</span>")):l.append(e.name),e.hidden&&l.addClass("dimmed"),h.append(l)}else{var m=a("<span></span>");j?(m.append(j),m.append('<span class="item-content-wrap">'+e.name+"</span>")):m.append(e.name),e.hidden&&m.addClass("dimmed"),h.append(m)}g.append(h),f.append(g),e.children&&e.children.length?b(h,e.children):k&&!e.requiresajaxloading&&(g.removeClass("contains_branch"),h.addClass("emptybranch"))}}),d.parent().append(f);var g=d.attr("id")+"_group";f.attr("id",g),d.attr("aria-owns",g),d.attr("role","treeitem")}var c={ACTIVITY:40,RESOURCE:50};return{render:function(a,c){if(c.children&&c.children.length){b(a,c.children);var d=a.children("[role='treeitem']").first(),e=a.find("#"+d.attr("aria-owns"));d.attr("aria-expanded",!0),e.attr("aria-hidden",!1)}else a.parent().hasClass("contains_branch")&&(a.parent().removeClass("contains_branch"),a.addClass("emptybranch"))}}});
define(["jquery"],function(a){function b(d,e){var f=a("<ul></ul>");f.attr("role","group"),f.attr("aria-hidden",!0),a.each(e,function(d,e){if("object"==typeof e){var g=a("<li></li>"),h=a("<p></p>"),i=e.id||e.key+"_tree_item",j=null,k=!(!e.expandable&&!e.haschildren);if(h.addClass("tree_item"),h.attr("id",i),h.attr("role","treeitem"),h.attr("tabindex","-1"),e.requiresajaxloading&&(h.attr("data-requires-ajax",!0),h.attr("data-node-id",e.id),h.attr("data-node-key",e.key),h.attr("data-node-type",e.type)),k&&(g.addClass("collapsed contains_branch"),h.attr("aria-expanded",!1),h.addClass("branch")),!e.icon||k&&e.type!==c.ACTIVITY&&e.type!==c.RESOURCE||(g.addClass("item_with_icon"),h.addClass("hasicon"),j=a("<img/>"),j.attr("alt",e.icon.alt),j.attr("title",e.icon.title),j.attr("src",M.util.image_url(e.icon.pix,e.icon.component)),a.each(e.icon.classes,function(a,b){j.addClass(b)})),e.link){var l=a('<a title="'+e.title+'" href="'+e.link+'"></a>');j?(l.append(j),l.append('<span class="item-content-wrap">'+e.name+"</span>")):l.append(e.name),e.hidden&&l.addClass("dimmed"),h.append(l)}else{var m=a("<span></span>");j?(m.append(j),m.append('<span class="item-content-wrap">'+e.name+"</span>")):m.append(e.name),e.hidden&&m.addClass("dimmed"),h.append(m)}g.append(h),f.append(g),e.children&&e.children.length?b(h,e.children):k&&!e.requiresajaxloading&&(g.removeClass("contains_branch"),h.addClass("emptybranch"))}}),d.parent().append(f);var g=d.attr("id")+"_group";f.attr("id",g),d.attr("aria-owns",g),d.attr("role","treeitem")}var c={ACTIVITY:40,RESOURCE:50};return{render:function(a,c){if(c.children&&c.children.length){b(a,c.children);var d=a.children("[role='treeitem']").first(),e=a.find("#"+d.attr("aria-owns"));d.attr("aria-expanded",!0),e.attr("aria-hidden",!1)}else a.parent().hasClass("contains_branch")&&(a.parent().removeClass("contains_branch"),a.addClass("emptybranch"))}}});
+10 -2
View File
@@ -239,6 +239,7 @@ class cache_helper {
$invalidationeventset = false;
$factory = cache_factory::instance();
$inuse = $factory->get_caches_in_use();
$purgetoken = null;
foreach ($instance->get_definitions() as $name => $definitionarr) {
$definition = cache_definition::load($name, $definitionarr);
if ($definition->invalidates_on_event($event)) {
@@ -265,8 +266,11 @@ class cache_helper {
$data = array();
}
// Add our keys to them with the current cache timestamp.
if (null === $purgetoken) {
$purgetoken = cache::get_purge_token(true);
}
foreach ($keys as $key) {
$data[$key] = cache::now();
$data[$key] = $purgetoken;
}
// Set that data back to the cache.
$cache->set($event, $data);
@@ -310,6 +314,7 @@ class cache_helper {
$invalidationeventset = false;
$factory = cache_factory::instance();
$inuse = $factory->get_caches_in_use();
$purgetoken = null;
foreach ($instance->get_definitions() as $name => $definitionarr) {
$definition = cache_definition::load($name, $definitionarr);
if ($definition->invalidates_on_event($event)) {
@@ -333,8 +338,11 @@ class cache_helper {
// Get the event invalidation cache.
$cache = cache::make('core', 'eventinvalidation');
// Create a key to invalidate all.
if (null === $purgetoken) {
$purgetoken = cache::get_purge_token(true);
}
$data = array(
'purged' => cache::now()
'purged' => $purgetoken,
);
// Set that data back to the cache.
$cache->set($event, $data);
+126 -17
View File
@@ -50,6 +50,14 @@ class cache implements cache_loader {
*/
protected static $now;
/**
* A purge token used to distinguish between multiple cache purges in the same second.
* This is in the format <microtime>-<random string>.
*
* @var string
*/
protected static $purgetoken;
/**
* The definition used when loading this cache if there was one.
* @var cache_definition
@@ -1144,13 +1152,70 @@ class cache implements cache_loader {
* This stamp needs to be used for all ttl and time based operations to ensure that we don't end up with
* timing issues.
*
* @return int
* @param bool $float Whether to use floating precision accuracy.
* @return int|float
*/
public static function now() {
public static function now($float = false) {
if (self::$now === null) {
self::$now = time();
self::$now = microtime(true);
}
if ($float) {
return self::$now;
} else {
return (int) self::$now;
}
}
/**
* Get a 'purge' token used for cache invalidation handling.
*
* Note: This function is intended for use from within the Cache API only and not by plugins, or cache stores.
*
* @param bool $reset Whether to reset the token and generate a new one.
* @return string
*/
public static function get_purge_token($reset = false) {
if (self::$purgetoken === null || $reset) {
self::$now = null;
self::$purgetoken = self::now(true) . '-' . uniqid('', true);
}
return self::$purgetoken;
}
/**
* Compare a pair of purge tokens.
*
* If the two tokens are identical, then the return value is 0.
* If the time component of token A is newer than token B, then a positive value is returned.
* If the time component of token B is newer than token A, then a negative value is returned.
*
* Note: This function is intended for use from within the Cache API only and not by plugins, or cache stores.
*
* @param string $tokena
* @param string $tokenb
* @return int
*/
public static function compare_purge_tokens($tokena, $tokenb) {
if ($tokena === $tokenb) {
// There is an exact match.
return 0;
}
// The token for when the cache was last invalidated.
list($atime) = explode('-', "{$tokena}-", 2);
// The token for this cache.
list($btime) = explode('-', "{$tokenb}-", 2);
if ($atime >= $btime) {
// Token A is newer.
return 1;
} else {
// Token A is older.
return -1;
}
return self::$now;
}
}
@@ -1236,18 +1301,40 @@ class cache_application extends cache implements cache_loader_with_locking {
if ($lastinvalidation === false) {
// This is a new session, there won't be anything to invalidate. Set the time of the last invalidation and
// move on.
$this->set('lastinvalidation', cache::now());
$this->set('lastinvalidation', self::get_purge_token());
return;
} else if ($lastinvalidation == cache::now()) {
// We've already invalidated during this request.
return;
}
// Get the event invalidation cache.
/*
* Now that the whole cache check is complete, we check the meaning of any specific cache invalidation events.
* These are stored in the core/eventinvalidation cache as an multi-dimensinoal array in the form:
* [
* eventname => [
* keyname => purgetoken,
* ]
* ]
*
* The 'keyname' value is used to delete a specific key in the cache.
* If the keyname is set to the special value 'purged', then the whole cache is purged instead.
*
* The 'purgetoken' is the token that this key was last purged.
* a) If the purgetoken matches the last invalidation, then the key/cache is not purged.
* b) If the purgetoken is newer than the last invalidation, then the key/cache is not purged.
* c) If the purge token is older than the last invalidation, or it has a different token component, then
* the cache is purged.
*
* Option b should not happen under normal operation, but may happen in race condition whereby a long-running
* request's cache is cleared in another process during that request, and prior to that long-running request
* creating the cache. In such a condition, it would be incorrect to clear that cache.
*/
$cache = cache::make('core', 'eventinvalidation');
$events = $cache->get_many($definition->get_invalidation_events());
$todelete = array();
$purgeall = false;
// Iterate the returned data for the events.
foreach ($events as $event => $keys) {
if ($keys === false) {
@@ -1255,10 +1342,10 @@ class cache_application extends cache implements cache_loader_with_locking {
continue;
}
// Look at each key and check the timestamp.
foreach ($keys as $key => $timestamp) {
foreach ($keys as $key => $purgetoken) {
// If the timestamp of the event is more than or equal to the last invalidation (happened between the last
// invalidation and now)then we need to invaliate the key.
if ($timestamp >= $lastinvalidation) {
if (self::compare_purge_tokens($purgetoken, $lastinvalidation) > 0) {
if ($key === 'purged') {
$purgeall = true;
break;
@@ -1276,7 +1363,7 @@ class cache_application extends cache implements cache_loader_with_locking {
}
// Set the time of the last invalidation.
if ($purgeall || !empty($todelete)) {
$this->set('lastinvalidation', cache::now());
$this->set('lastinvalidation', self::get_purge_token(true));
}
}
}
@@ -1637,18 +1724,40 @@ class cache_session extends cache {
if ($lastinvalidation === false) {
// This is a new session, there won't be anything to invalidate. Set the time of the last invalidation and
// move on.
$this->set('lastsessioninvalidation', cache::now());
$this->set('lastsessioninvalidation', self::get_purge_token());
return;
} else if ($lastinvalidation == cache::now()) {
} else if ($lastinvalidation == self::get_purge_token()) {
// We've already invalidated during this request.
return;
}
// Get the event invalidation cache.
/*
* Now that the whole cache check is complete, we check the meaning of any specific cache invalidation events.
* These are stored in the core/eventinvalidation cache as an multi-dimensinoal array in the form:
* [
* eventname => [
* keyname => purgetoken,
* ]
* ]
*
* The 'keyname' value is used to delete a specific key in the cache.
* If the keyname is set to the special value 'purged', then the whole cache is purged instead.
*
* The 'purgetoken' is the token that this key was last purged.
* a) If the purgetoken matches the last invalidation, then the key/cache is not purged.
* b) If the purgetoken is newer than the last invalidation, then the key/cache is not purged.
* c) If the purge token is older than the last invalidation, or it has a different token component, then
* the cache is purged.
*
* Option b should not happen under normal operation, but may happen in race condition whereby a long-running
* request's cache is cleared in another process during that request, and prior to that long-running request
* creating the cache. In such a condition, it would be incorrect to clear that cache.
*/
$cache = cache::make('core', 'eventinvalidation');
$events = $cache->get_many($definition->get_invalidation_events());
$todelete = array();
$purgeall = false;
// Iterate the returned data for the events.
foreach ($events as $event => $keys) {
if ($keys === false) {
@@ -1656,10 +1765,10 @@ class cache_session extends cache {
continue;
}
// Look at each key and check the timestamp.
foreach ($keys as $key => $timestamp) {
foreach ($keys as $key => $purgetoken) {
// If the timestamp of the event is more than or equal to the last invalidation (happened between the last
// invalidation and now)then we need to invaliate the key.
if ($timestamp >= $lastinvalidation) {
// invalidation and now), then we need to invaliate the key.
if (self::compare_purge_tokens($purgetoken, $lastinvalidation) > 0) {
if ($key === 'purged') {
$purgeall = true;
break;
@@ -1677,7 +1786,7 @@ class cache_session extends cache {
}
// Set the time of the last invalidation.
if ($purgeall || !empty($todelete)) {
$this->set('lastsessioninvalidation', cache::now());
$this->set('lastsessioninvalidation', self::get_purge_token(true));
}
}
}
@@ -2214,4 +2323,4 @@ class cache_session extends cache {
*/
class cache_request extends cache {
// This comment appeases code pre-checker ;) !
}
}
+64 -10
View File
@@ -1009,7 +1009,7 @@ class core_cache_testcase extends advanced_testcase {
$timefile = $CFG->dataroot."/cache/cachestore_file/default_application/phpunit_eventinvalidationtest/las-cache/lastinvalidation-$hash.cache";
// Make sure the file is correct.
$this->assertTrue(file_exists($timefile));
$timecont = serialize(cache::now() - 60); // Back 60sec in the past to force it to re-invalidate.
$timecont = serialize(cache::now(true) - 60); // Back 60sec in the past to force it to re-invalidate.
make_writable_directory(dirname($timefile));
file_put_contents($timefile, $timecont);
$this->assertTrue(file_exists($timefile));
@@ -1035,6 +1035,7 @@ class core_cache_testcase extends advanced_testcase {
// Test 2: Rebuild and test the invalidation of the event via the invalidation cache.
cache_factory::reset();
$instance = cache_config_testing::instance();
$instance->phpunit_add_definition('phpunit/eventinvalidationtest', array(
'mode' => cache_store::MODE_APPLICATION,
@@ -1046,6 +1047,7 @@ class core_cache_testcase extends advanced_testcase {
'crazyevent'
)
));
$cache = cache::make('phpunit', 'eventinvalidationtest');
$this->assertFalse($cache->get('testkey1'));
@@ -1053,23 +1055,29 @@ class core_cache_testcase extends advanced_testcase {
// Make a new cache class. This should should invalidate testkey2.
$cache = cache::make('phpunit', 'eventinvalidationtest');
// Timestamp should have updated to cache::now().
$this->assertEquals(cache::now(), $cache->get('lastinvalidation'));
// Invalidation token should have been reset.
$this->assertEquals(cache::get_purge_token(), $cache->get('lastinvalidation'));
// Set testkey2 data.
$cache->set('testkey2', 'test data 2');
// Backdate the event invalidation time by 30 seconds.
$invalidationcache = cache::make('core', 'eventinvalidation');
$invalidationcache->set('crazyevent', array('testkey2' => cache::now() - 30));
// Lastinvalidation should already be cache::now().
$this->assertEquals(cache::now(), $cache->get('lastinvalidation'));
$this->assertEquals(cache::get_purge_token(), $cache->get('lastinvalidation'));
// Set it to 15 seconds ago so that we know if it changes.
$cache->set('lastinvalidation', cache::now() - 15);
$cache->set('lastinvalidation', cache::now(true) - 15);
// Make a new cache class. This should not invalidate anything.
cache_factory::instance()->reset_cache_instances();
$cache = cache::make('phpunit', 'eventinvalidationtest');
// Lastinvalidation shouldn't change since it was already newer than invalidation event.
$this->assertEquals(cache::now() - 15, $cache->get('lastinvalidation'));
$this->assertEquals(cache::now(true) - 15, $cache->get('lastinvalidation'));
// Now set the event invalidation to newer than the lastinvalidation time.
$invalidationcache->set('crazyevent', array('testkey2' => cache::now() - 5));
@@ -1077,18 +1085,18 @@ class core_cache_testcase extends advanced_testcase {
cache_factory::instance()->reset_cache_instances();
$cache = cache::make('phpunit', 'eventinvalidationtest');
// Lastinvalidation timestamp should have updated to cache::now().
$this->assertEquals(cache::now(), $cache->get('lastinvalidation'));
$this->assertEquals(cache::get_purge_token(), $cache->get('lastinvalidation'));
// Now simulate a purge_by_event 5 seconds ago.
$invalidationcache = cache::make('core', 'eventinvalidation');
$invalidationcache->set('crazyevent', array('purged' => cache::now() - 5));
$invalidationcache->set('crazyevent', array('purged' => cache::now(true) - 5));
// Set our lastinvalidation timestamp to 15 seconds ago.
$cache->set('lastinvalidation', cache::now() - 15);
$cache->set('lastinvalidation', cache::now(true) - 15);
// Make a new cache class. This should invalidate the cache.
cache_factory::instance()->reset_cache_instances();
$cache = cache::make('phpunit', 'eventinvalidationtest');
// Lastinvalidation timestamp should have updated to cache::now().
$this->assertEquals(cache::now(), $cache->get('lastinvalidation'));
$this->assertEquals(cache::get_purge_token(), $cache->get('lastinvalidation'));
}
@@ -2223,4 +2231,50 @@ class core_cache_testcase extends advanced_testcase {
$this->assertArrayNotHasKey($sessionid, $endstats);
$this->assertArrayNotHasKey($requestid, $endstats);
}
/**
* Tests session cache event purge and subsequent visit in the same request.
*
* This test simulates a cache being created, a value being set, then the value being purged.
* A subsequent use of the same cache is started in the same request which fills the cache.
* A new request is started a short time later.
* The cache should be filled.
*/
public function test_session_event_purge_same_second() {
$instance = cache_config_testing::instance();
$instance->phpunit_add_definition('phpunit/eventpurgetest', array(
'mode' => cache_store::MODE_SESSION,
'component' => 'phpunit',
'area' => 'eventpurgetest',
'invalidationevents' => array(
'crazyevent',
)
));
// Create the cache, set a value, and immediately purge it by event.
$cache = cache::make('phpunit', 'eventpurgetest');
$cache->set('testkey1', 'test data 1');
$this->assertEquals('test data 1', $cache->get('testkey1'));
cache_helper::purge_by_event('crazyevent');
$this->assertFalse($cache->get('testkey1'));
// Set up the cache again in the same request and add a new value back in.
$factory = \cache_factory::instance();
$factory->reset_cache_instances();
$cache = cache::make('phpunit', 'eventpurgetest');
$cache->set('testkey1', 'test data 2');
$this->assertEquals('test data 2', $cache->get('testkey1'));
// Trick the cache into thinking that this is a new request.
cache_phpunit_cache::simulate_new_request();
$factory = \cache_factory::instance();
$factory->reset_cache_instances();
// Set up the cache again.
// This is a subsequent request at a new time, so we instead the invalidation time will be checked.
// The invalidation time should match the last purged time and the cache will not be re-purged.
$cache = cache::make('phpunit', 'eventpurgetest');
$this->assertEquals('test data 2', $cache->get('testkey1'));
}
}
+14 -40
View File
@@ -534,47 +534,21 @@ class cache_phpunit_factory extends cache_factory {
public static function phpunit_disable() {
parent::disable();
}
}
/**
* Cache PHPUnit specific Cache helper.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class cache_phpunit_cache extends cache {
/**
* @var bool Whether the warning notice about alternative cache store used has been displayed.
* Make the changes which simulate a new request within the cache.
* This essentially resets currently held static values in the class, and increments the current timestamp.
*/
protected $altcachestorenotice = false;
/**
* Creates a store instance given its name and configuration.
*
* If the store has already been instantiated then the original object will be returned. (reused)
*
* @param string $name The name of the store (must be unique remember)
* @param array $details
* @param cache_definition $definition The definition to instantiate it for.
* @return boolean|cache_store
*/
public function create_store_from_config($name, array $details, cache_definition $definition) {
if (isset($details['use_test_store'])) {
// name, plugin, alt
$class = 'cachestore_'.$details['plugin'];
$method = 'initialise_unit_test_instance';
if (class_exists($class) && method_exists($class, $method)) {
$instance = $class::$method($definition);
if ($instance) {
return $instance;
}
}
// Notify user that alternative store is being used, so action can be taken.
if (!$this->altcachestorenotice) {
echo PHP_EOL . "++ WARNING: " . 'Failed to use "' . $details['plugin'] . '" cache store, alt "' .
$details['alt']['plugin'] . '" cache store is used.' . PHP_EOL . PHP_EOL;
$this->altcachestorenotice = true;
}
$details = $details['alt'];
$details['class'] = 'cachestore_'.$details['plugin'];
$name = $details['name'];
}
return parent::create_store_from_config($name, $details, $definition);
public static function simulate_new_request() {
self::$now += 0.1;
self::$purgetoken = null;
}
}
}
+4
View File
@@ -1,6 +1,10 @@
This files describes API changes in /cache/stores/* - cache store plugins.
Information provided here is intended especially for developers.
=== 3.1.14 ===
* The `cache::now()` function now takes an optional boolean parameter to indicate that the cache should return a more
accurate time, generated by the PHP `microtime` function.
=== 3.1 ===
* Cache stores has a new feature DEREFERENCES_OBJECTS.
This allows the cache loader to decide if it needs to handle dereferencing or whether the data
+239 -115
View File
@@ -451,6 +451,9 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
*/
public function test_every_300_days_forever() {
global $DB;
// Change the start date for forever events to 9am of the current date.
$this->change_event_startdate(date('Ymd\T090000'));
$startdatetime = new DateTime(date('Y-m-d H:i:s', $this->event->timestart));
$interval = new DateInterval('P300D');
@@ -463,7 +466,8 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$mang = new rrule_manager($rrule);
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', array('repeatid' => $this->event->id), 'timestart ASC');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', array('repeatid' => $this->event->id), 'timestart ASC', 0, 100);
$expecteddate = clone($startdatetime);
foreach ($records as $record) {
@@ -542,8 +546,20 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$expecteddate->add($interval);
}
}
}
// Forever event. This should generate events over time() + 10 year period, every 50th Monday.
/**
* Test recurrence rules for weekly frequency for RRULE with BYDAY rule set, recurring forever.
*/
public function test_weekly_byday_forever() {
global $DB;
// Set the next Monday as the starting date of this event.
$startdate = new DateTime('next Monday');
// Change the start date of the parent event.
$startdate = $this->change_event_startdate($startdate->format('Ymd\T090000'));
// Forever event. This should generate events over time() + 10 year period, every 50 weeks.
$rrule = 'FREQ=WEEKLY;BYDAY=MO;INTERVAL=50';
$mang = new rrule_manager($rrule);
@@ -554,13 +570,14 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$untildate->add(new DateInterval('P10Y'));
$until = $untildate->getTimestamp();
$interval = new DateInterval('P50W');
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// First instance of this set of recurring events: Monday, 17-08-1998.
$interval = new DateInterval('P50W');
// First instance of this set of recurring events.
$expecteddate = clone($startdate);
$expecteddate->modify('1998-08-17');
$expecteddate->add($offsetinterval);
// Iterate over each record and increment the expected date accordingly.
foreach ($records as $record) {
$eventdateexpected = $expecteddate->format('Y-m-d H:i:s');
$eventdateactual = date('Y-m-d H:i:s', $record->timestart);
@@ -666,17 +683,21 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
public function test_monthly_events_with_bymonthday_forever() {
global $DB;
// Change the start date for forever events to 9am of the 2nd day of the current month and year.
$this->change_event_startdate(date('Ym02\T090000'));
$startdatetime = new DateTime(date('Y-m-d H:i:s', $this->event->timestart));
$startdate = new DateTime(date('Y-m-d', $this->event->timestart));
$offsetinterval = $startdatetime->diff($startdate, true);
$interval = new DateInterval('P12M');
// Forever event. This should generate events over 10 year period, on 2nd day of every 12th month.
// Forever event. This should generate events over a 10-year period, on 2nd day of the month, every 12 months.
$rrule = "FREQ=MONTHLY;INTERVAL=12;BYMONTHDAY=2";
$mang = new rrule_manager($rrule);
$until = time() + (YEARSECS * $mang::TIME_UNLIMITED_YEARS);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
$until = $untildate->getTimestamp();
$mang->parse_rrule();
$mang->create_events($this->event);
@@ -818,24 +839,33 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
public function test_monthly_events_with_byday_forever() {
global $DB;
// Change the start date for forever events to 9am of the 2nd day of the current month and year.
$this->change_event_startdate(date('Ym02\T090000'));
$startdatetime = new DateTime(date('Y-m-d H:i:s', $this->event->timestart));
$startdate = new DateTime(date('Y-m-d', $this->event->timestart));
$offsetinterval = $startdatetime->diff($startdate, true);
$interval = new DateInterval('P12M');
// Forever event. This should generate events over 10 year period, on 2nd day of every 12th month.
// Forever event. This should generate events over a 10 year period, on 1st Monday of the month every 12 months.
$rrule = "FREQ=MONTHLY;INTERVAL=12;BYDAY=1MO";
$mang = new rrule_manager($rrule);
$until = time() + (YEARSECS * $mang::TIME_UNLIMITED_YEARS);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
$until = $untildate->getTimestamp();
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
$expecteddate = new DateTime('first Monday of September 1998');
$expecteddate = new DateTime('first Monday of this month');
// Move to the next interval's first Monday if the calculated start date is after this month's first Monday.
if ($expecteddate->getTimestamp() < $startdate->getTimestamp()) {
$expecteddate->add($interval);
$expecteddate->modify('first Monday of this month');
}
foreach ($records as $record) {
$expecteddate->add($offsetinterval);
$this->assertLessThanOrEqual($until, $record->timestart);
@@ -880,7 +910,7 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
// Create a yearly event, until the time limit is hit.
$until = strtotime('+20 day +10 years', $this->event->timestart);
$until = date('Ymd\THis\Z', $until);
$rrule = "FREQ=YEARLY;BYMONTH=9;UNTIL=$until"; // Forever event.
$rrule = "FREQ=YEARLY;BYMONTH=9;UNTIL=$until";
$mang = new rrule_manager($rrule);
$mang->parse_rrule();
$mang->create_events($this->event);
@@ -907,18 +937,6 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$this->assertTrue($result);
}
$rrule = "FREQ=YEARLY;BYMONTH=9;INTERVAL=2"; // Forever event.
$mang = new rrule_manager($rrule);
$until = time() + (YEARSECS * $mang::TIME_UNLIMITED_YEARS);
$mang->parse_rrule();
$mang->create_events($this->event);
for ($i = 0, $time = $this->event->timestart; $time < $until; $i++, $yoffset = $i * 2,
$time = strtotime("+$yoffset years", $this->event->timestart)) {
$result = $DB->record_exists('event', array('repeatid' => $this->event->id,
'timestart' => ($time)));
$this->assertTrue($result);
}
$rrule = "FREQ=YEARLY;COUNT=3;BYMONTH=9;BYDAY=1MO"; // This should generate 3 events in total.
$mang = new rrule_manager($rrule);
$mang->parse_rrule();
@@ -994,12 +1012,45 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
}
}
/**
* Test for rrule with FREQ=YEARLY and INTERVAL=2 with BYMONTH rule set, recurring forever.
*/
public function test_yearly_september_every_two_years_forever() {
global $DB;
// Change the start date for forever events to 9am on the 2nd day of September of the current year.
$this->change_event_startdate(date('Y0902\T090000'));
$rrule = "FREQ=YEARLY;BYMONTH=9;INTERVAL=2"; // Forever event.
$mang = new rrule_manager($rrule);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
$untiltimestamp = $untildate->getTimestamp();
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
$interval = new DateInterval('P2Y');
$expecteddate = new DateTime(date('Y0902\T090000'));
foreach ($records as $record) {
$this->assertLessThanOrEqual($untiltimestamp, $record->timestart);
$this->assertEquals($expecteddate->format('Y-m-d H:i:s'), date('Y-m-d H:i:s', $record->timestart));
// Go to the next expected date.
$expecteddate->add($interval);
}
}
/**
* Test for rrule with FREQ=YEARLY with BYMONTH and BYDAY rules set, recurring forever.
*/
public function test_yearly_bymonth_byday_forever() {
global $DB;
// Change the start date for forever events to the first day of September of the current year at 9am.
$this->change_event_startdate(date('Y0901\T090000'));
// Every 2 years on the first Monday of September.
$rrule = "FREQ=YEARLY;BYMONTH=9;INTERVAL=2;BYDAY=1MO";
$mang = new rrule_manager($rrule);
@@ -1018,9 +1069,9 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$offsetinterval = $startdatetime->diff($startdate, true);
$interval = new DateInterval('P2Y');
// First occurrence of this set of events is on the first Monday of September 1999.
// First occurrence of this set of events is on the first Monday of September.
$expecteddate = clone($startdatetime);
$expecteddate->modify('first Monday of September 1999');
$expecteddate->modify('first Monday of September');
$expecteddate->add($offsetinterval);
foreach ($records as $record) {
$this->assertLessThanOrEqual($untiltimestamp, $record->timestart);
@@ -1040,6 +1091,9 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
public function test_yearly_forever() {
global $DB;
// Change the start date for forever events to 9am of the current date.
$this->change_event_startdate(date('Ymd\T090000'));
$startdatetime = new DateTime(date('Y-m-d H:i:s', $this->event->timestart));
$interval = new DateInterval('P2Y');
@@ -1137,14 +1191,19 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Every other day - forever:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* DTSTART;TZID=US-Eastern:[Current date]T090000
* RRULE:FREQ=DAILY;INTERVAL=2
* ==> (1997 9:00 AM EDT)September2,4,6,8...24,26,28,30;October 2,4,6...20,22,24
* (1997 9:00 AM EST)October 26,28,30;November 1,3,5,7...25,27,29;Dec 1,3,...
*
* Sample results (e.g. in the year 1997):
* (1997 9:00 AM EDT)September2,4,6,8...24,26,28,30;October 2,4,6...20,22,24
* (1997 9:00 AM EST)October 26,28,30;November 1,3,5,7...25,27,29;Dec 1,3,...
*/
public function test_every_other_day_forever() {
global $DB;
// Change the start date for forever events to 9am of the current date in US/Eastern time.
$this->change_event_startdate(date('Ymd\T090000'), 'US/Eastern');
$startdatetime = new DateTime(date('Y-m-d H:i:s', $this->event->timestart));
$interval = new DateInterval('P2D');
@@ -1153,7 +1212,8 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
@@ -1331,16 +1391,21 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Every other week - forever:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* DTSTART;TZID=US-Eastern:[Current date]T090000
* RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=SU
* ==> (1997 9:00 AM EDT)September 2,16,30;October 14
* (1997 9:00 AM EST)October 28;November 11,25;December 9,23
* (1998 9:00 AM EST)January 6,20;February
* ...
*
* Sample results (e.g. in the year 1997):
* (1997 9:00 AM EDT)September 2,16,30;October 14
* (1997 9:00 AM EST)October 28;November 11,25;December 9,23
* (1998 9:00 AM EST)January 6,20;February
* ...
*/
public function test_every_other_week_forever() {
global $DB;
// Change the start date for forever events to 9am of the current date in US/Eastern time.
$this->change_event_startdate(date('Ymd\T090000'), 'US/Eastern');
$interval = new DateInterval('P2W');
$rrule = 'FREQ=WEEKLY;INTERVAL=2;WKST=SU';
@@ -1348,7 +1413,8 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
@@ -1694,25 +1760,28 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Monthly on the third to the last day of the month, forever:
*
* DTSTART;TZID=US-Eastern:19970928T090000
* DTSTART;TZID=US-Eastern:[Current year]0928T090000
* RRULE:FREQ=MONTHLY;BYMONTHDAY=-3
* ==> (1997 9:00 AM EDT)September 28
* (1997 9:00 AM EST)October 29;November 28;December 29
* (1998 9:00 AM EST)January 29;February 26
* ...
*
* Sample results (e.g. in the year 1997):
* (1997 9:00 AM EDT)September 28
* (1997 9:00 AM EST)October 29;November 28;December 29
* (1998 9:00 AM EST)January 29;February 26
* ...
*/
public function test_third_to_the_last_day_of_the_month_forever() {
global $DB;
// Change our event's date to 05-09-1997, based on the example from the RFC.
$this->change_event_startdate('19970928T090000', 'US/Eastern');
// Change our event's date to 28 September of the current year, based on the example from the RFC.
$this->change_event_startdate(date('Y0928\T090000'), 'US/Eastern');
$rrule = 'FREQ=MONTHLY;BYMONTHDAY=-3';
$mang = new rrule_manager($rrule);
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
@@ -1868,22 +1937,29 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Every Tuesday, every other month:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* DTSTART;TZID=US-Eastern:[Next Tuesday]T090000
* RRULE:FREQ=MONTHLY;INTERVAL=2;BYDAY=TU
* ==> (1997 9:00 AM EDT)September 2,9,16,23,30
* (1997 9:00 AM EST)November 4,11,18,25
* (1998 9:00 AM EST)January 6,13,20,27;March 3,10,17,24,31
* ...
*
* Sample results (e.g. in the year 1997):
* (1997 9:00 AM EDT)September 2,9,16,23,30
* (1997 9:00 AM EST)November 4,11,18,25
* (1998 9:00 AM EST)January 6,13,20,27;March 3,10,17,24,31
* ...
*/
public function test_every_tuesday_every_other_month_forever() {
global $DB;
// Change the start date for forever events to 9am of the Tuesday on or before of the current date in US/Eastern time.
$nexttuesday = new DateTime('next Tuesday');
$this->change_event_startdate($nexttuesday->format('Ymd\T090000'), 'US/Eastern');
$rrule = 'FREQ=MONTHLY;INTERVAL=2;BYDAY=TU';
$mang = new rrule_manager($rrule);
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
@@ -2053,18 +2129,22 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Every 20th Monday of the year, forever:
*
* DTSTART;TZID=US-Eastern:19970519T090000
* DTSTART;TZID=US-Eastern:[20th Monday of the current year]T090000
* RRULE:FREQ=YEARLY;BYDAY=20MO
* ==> (1997 9:00 AM EDT)May 19
* (1998 9:00 AM EDT)May 18
* (1999 9:00 AM EDT)May 17
* ...
*
* Sample results (e.g. in the year 1997):
* (1997 9:00 AM EDT)May 19
* (1998 9:00 AM EDT)May 18
* (1999 9:00 AM EDT)May 17
* ...
*/
public function test_yearly_every_20th_monday_forever() {
global $DB;
// Change our event's date to 19-05-1997, based on the example from the RFC.
$startdatetime = $this->change_event_startdate('19970519T090000', 'US/Eastern');
// Change our event's date to the 20th Monday of the current year.
$twentiethmonday = new DateTime(date('Y-01-01'));
$twentiethmonday->modify('+20 Monday');
$startdatetime = $this->change_event_startdate($twentiethmonday->format('Ymd\T090000'), 'US/Eastern');
$startdate = new DateTime($startdatetime->format('Y-m-d'));
@@ -2100,18 +2180,22 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Monday of week number 20 (where the default start of the week is Monday), forever:
*
* DTSTART;TZID=US-Eastern:19970512T090000
* DTSTART;TZID=US-Eastern:[1st day of the 20th week this year]T090000
* RRULE:FREQ=YEARLY;BYWEEKNO=20;BYDAY=MO
* ==> (1997 9:00 AM EDT)May 12
* (1998 9:00 AM EDT)May 11
* (1999 9:00 AM EDT)May 17
* ...
*
* Sample results (e.g. in the year 1997):
* (1997 9:00 AM EDT)May 12
* (1998 9:00 AM EDT)May 11
* (1999 9:00 AM EDT)May 17
* ...
*/
public function test_yearly_byweekno_forever() {
global $DB;
// Change our event's date to 12-05-1997, based on the example from the RFC.
$startdatetime = $this->change_event_startdate('19970512T090000', 'US/Eastern');
// Change our event's date to the start of the 20th week of the current year.
$twentiethweek = new DateTime(date('Y-01-01'));
$twentiethweek->setISODate($twentiethweek->format('Y'), 20);
$startdatetime = $this->change_event_startdate($twentiethweek->format('Ymd\T090000'), 'US/Eastern');
$startdate = clone($startdatetime);
$startdate->modify($startdate->format('Y-m-d'));
@@ -2146,18 +2230,21 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Every Thursday in March, forever:
*
* DTSTART;TZID=US-Eastern:19970313T090000
* DTSTART;TZID=US-Eastern:[First thursday of March of the current year]T090000
* RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=TH
* ==> (1997 9:00 AM EST)March 13,20,27
* (1998 9:00 AM EST)March 5,12,19,26
* (1999 9:00 AM EST)March 4,11,18,25
* ...
*
* Sample results (e.g. in the year 1997):
* (1997 9:00 AM EST)March 13,20,27
* (1998 9:00 AM EST)March 5,12,19,26
* (1999 9:00 AM EST)March 4,11,18,25
* ...
*/
public function test_every_thursday_in_march_forever() {
global $DB;
// Change our event's date to 12-05-1997, based on the example from the RFC.
$startdatetime = $this->change_event_startdate('19970313T090000', 'US/Eastern');
// Change our event's date to the first Thursday of March of the current year at 9am US/Eastern time.
$firstthursdayofmarch = new DateTime('first Thursday of March');
$startdatetime = $this->change_event_startdate($firstthursdayofmarch->format('Ymd\T090000'), 'US/Eastern');
$interval = new DateInterval('P1Y');
@@ -2166,7 +2253,8 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
@@ -2176,7 +2264,7 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$startdate = new DateTime($startdatetime->format('Y-m-d'));
$offsetinterval = $startdatetime->diff($startdate, true);
$expecteddate->setTimezone(new DateTimeZone(get_user_timezone()));
$april1st = new DateTime('1997-04-01');
$april1st = new DateTime('April 1');
foreach ($records as $record) {
$this->assertLessThanOrEqual($untiltimestamp, $record->timestart);
$this->assertEquals($expecteddate->format('Y-m-d H:i:s'), date('Y-m-d H:i:s', $record->timestart));
@@ -2201,18 +2289,21 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Every Thursday, but only during June, July, and August, forever:
*
* DTSTART;TZID=US-Eastern:19970605T090000
* DTSTART;TZID=US-Eastern:[First Thursday of June of the current year]T090000
* RRULE:FREQ=YEARLY;BYDAY=TH;BYMONTH=6,7,8
* ==> (1997 9:00 AM EDT)June 5,12,19,26;July 3,10,17,24,31;August 7,14,21,28
* (1998 9:00 AM EDT)June 4,11,18,25;July 2,9,16,23,30;August 6,13,20,27
* (1999 9:00 AM EDT)June 3,10,17,24;July 1,8,15,22,29;August 5,12,19,26
* ...
*
* Sample results (e.g. in the year 1997):
* (1997 9:00 AM EDT)June 5,12,19,26;July 3,10,17,24,31;August 7,14,21,28
* (1998 9:00 AM EDT)June 4,11,18,25;July 2,9,16,23,30;August 6,13,20,27
* (1999 9:00 AM EDT)June 3,10,17,24;July 1,8,15,22,29;August 5,12,19,26
* ...
*/
public function test_every_thursday_june_july_august_forever() {
global $DB;
// Change our event's date to 05-06-1997, based on the example from the RFC.
$startdatetime = $this->change_event_startdate('19970605T090000', 'US/Eastern');
// Change our event's date to the first Thursday of June in the current year at 9am US/Eastern time.
$firstthursdayofjune = new DateTime('first Thursday of June');
$startdatetime = $this->change_event_startdate($firstthursdayofjune->format('Ymd\T090000'), 'US/Eastern');
$startdate = new DateTime($startdatetime->format('Y-m-d'));
@@ -2225,14 +2316,15 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
$untiltimestamp = $untildate->getTimestamp();
$expecteddate = new DateTime(date('Y-m-d H:i:s', $startdatetime->getTimestamp()));
$september1st = new DateTime('1997-09-01');
$september1st = new DateTime('September 1');
foreach ($records as $record) {
$this->assertLessThanOrEqual($untiltimestamp, $record->timestart);
$this->assertEquals($expecteddate->format('Y-m-d H:i:s'), date('Y-m-d H:i:s', $record->timestart));
@@ -2254,22 +2346,28 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Every Friday the 13th, forever:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* EXDATE;TZID=US-Eastern:19970902T090000
* DTSTART;TZID=US-Eastern:[Current date]T090000
* RRULE:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13
* ==> (1998 9:00 AM EST)February 13;March 13;November 13
* (1999 9:00 AM EDT)August 13
* (2000 9:00 AM EDT)October 13
*
* Sample results (e.g. in the year 1997):
* (1998 9:00 AM EST)February 13;March 13;November 13
* (1999 9:00 AM EDT)August 13
* (2000 9:00 AM EDT)October 13
* ...
*/
public function test_friday_the_thirteenth_forever() {
global $DB;
// Change our event's date to the first Thursday of June in the current year at 9am US/Eastern time.
$this->change_event_startdate(date('Ymd\T090000'), 'US/Eastern');
$rrule = 'FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13';
$mang = new rrule_manager($rrule);
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
@@ -2285,17 +2383,22 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* The first Saturday that follows the first Sunday of the month, forever:
*
* DTSTART;TZID=US-Eastern:19970913T090000
* DTSTART;TZID=US-Eastern:[The Saturday after the month's first Sunday]T090000
* RRULE:FREQ=MONTHLY;BYDAY=SA;BYMONTHDAY=7,8,9,10,11,12,13
* ==> (1997 9:00 AM EDT)September 13;October 11
* (1997 9:00 AM EST)November 8;December 13
* (1998 9:00 AM EST)January 10;February 7;March 7
* (1998 9:00 AM EDT)April 11;May 9;June 13...
*
* Sample results (e.g. from 13 September 1997):
* (1997 9:00 AM EDT)September 13;October 11
* (1997 9:00 AM EST)November 8;December 13
* (1998 9:00 AM EST)January 10;February 7;March 7
* (1998 9:00 AM EDT)April 11;May 9;June 13...
*/
public function test_first_saturday_following_first_sunday_forever() {
global $DB;
$startdatetime = $this->change_event_startdate('19970913T090000', 'US/Eastern');
// Change our event's date to the next Saturday after the first Sunday of the the current month at 9am US/Eastern time.
$firstsaturdayafterfirstsunday = new DateTime('first Sunday of this month');
$firstsaturdayafterfirstsunday->modify('next Saturday');
$startdatetime = $this->change_event_startdate($firstsaturdayafterfirstsunday->format('Ymd\T090000'), 'US/Eastern');
$startdate = new DateTime($startdatetime->format('Y-m-d'));
$offset = $startdatetime->diff($startdate, true);
@@ -2304,7 +2407,8 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
@@ -2330,17 +2434,29 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Every four years, the first Tuesday after a Monday in November, forever (U.S. Presidential Election day):
*
* DTSTART;TZID=US-Eastern:19961105T090000
* DTSTART;TZID=US-Eastern:[Most recent election date]T090000
* RRULE:FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,5,6,7,8
* ==> (1996 9:00 AM EST)November 5
* (2000 9:00 AM EST)November 7
* (2004 9:00 AM EST)November 2
* ...
*
* Sample results (e.g. from 05 November 1996):
* (1996 9:00 AM EST)November 5
* (2000 9:00 AM EST)November 7
* (2004 9:00 AM EST)November 2
* ...
*/
public function test_every_us_presidential_election_forever() {
global $DB;
$startdatetime = $this->change_event_startdate('19961105T090000', 'US/Eastern');
// Calculate the most recent election date, starting from 1996 (e.g. today's 2017 so the most recent election was in 2016).
$currentyear = (int) date('Y');
$electionyear = 1996;
while ($electionyear + 4 < $currentyear) {
$electionyear += 4;
}
$electiondate = new DateTime('first Monday of November ' . $electionyear);
$electiondate->modify('+1 Tuesday');
// Use the most recent election date as the starting date of our recurring events.
$startdatetime = $this->change_event_startdate($electiondate->format('Ymd\T090000'), 'US/Eastern');
$startdate = new DateTime($startdatetime->format('Y-m-d'));
$offset = $startdatetime->diff($startdate, true);
@@ -2407,23 +2523,27 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
* The 2nd to last weekday of the month:
*
* DTSTART;TZID=US-Eastern:19970929T090000
* RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2
* RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2;COUNT=7
* ==> (1997 9:00 AM EDT)September 29
* (1997 9:00 AM EST)October 30;November 27;December 30
* (1998 9:00 AM EST)January 29;February 26;March 30
* ...
*
* (Original RFC example is set to recur forever. But we just want to verify that the results match the dates listed from
* the RFC example. So just limit the count to 7.)
*/
public function test_second_to_the_last_weekday_of_the_month_forever() {
public function test_second_to_the_last_weekday_of_the_month() {
global $DB;
$this->change_event_startdate('19970929T090000', 'US/Eastern');
$rrule = 'FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2';
$rrule = 'FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2;COUNT=7';
$mang = new rrule_manager($rrule);
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 7 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 7);
$expecteddates = [
(new DateTime('1997-09-29 09:00:00 EDT'))->getTimestamp(),
@@ -2444,10 +2564,8 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$this->assertLessThanOrEqual($untiltimestamp, $record->timestart);
// Confirm that the first 7 records correspond to the expected dates listed above.
if ($i < 7) {
$this->assertEquals($expecteddates[$i], $record->timestart);
$i++;
}
$this->assertEquals($expecteddates[$i], $record->timestart);
$i++;
}
}
@@ -2747,13 +2865,19 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Change the event's timestart (DTSTART) based on the test's needs.
*
* @param string $datestr The date string. In YYYYmmddThhiiss format. e.g. 19990902T090000.
* @param string $timezonestr A valid timezone string. e.g. 'US/Eastern'.
* @param string $datestr The date string. In 'Ymd\This' format. e.g. 19990902T090000.
* @param null|string $timezonestr A valid timezone string. e.g. 'US/Eastern'.
* If not provided, the default timezone will be used.
* @return bool|DateTime
*/
protected function change_event_startdate($datestr, $timezonestr) {
$timezone = new DateTimeZone($timezonestr);
$newdatetime = DateTime::createFromFormat('Ymd\THis', $datestr, $timezone);
protected function change_event_startdate($datestr, $timezonestr = null) {
// Use default timezone if not provided.
if ($timezonestr === null) {
$newdatetime = DateTime::createFromFormat('Ymd\THis', $datestr);
} else {
$timezone = new DateTimeZone($timezonestr);
$newdatetime = DateTime::createFromFormat('Ymd\THis', $datestr, $timezone);
}
// Update the start date of the parent event.
$calevent = calendar_event::load($this->event->id);
+5
View File
@@ -561,6 +561,11 @@ $CFG->admin = 'admin';
//
// $CFG->upgradekey = 'put_some_password-like_value_here';
//
// Disable login token validation for login pages. Login token validation is enabled
// by default unless $CFG->alternateloginurl is set.
//
// $CFG->disablelogintoken = true;
//
//=========================================================================
// 7. SETTINGS FOR DEVELOPMENT SERVERS - not intended for production use!!!
//=========================================================================
+2 -6
View File
@@ -1524,9 +1524,7 @@ class core_course_external extends external_api {
break;
case 'visible':
if (has_capability('moodle/category:manage', $context)
or has_capability('moodle/category:viewhiddencategories',
context_system::instance())) {
if (has_capability('moodle/category:viewhiddencategories', $context)) {
$value = clean_param($crit['value'], PARAM_INT);
} else {
throw new moodle_exception('criteriaerror',
@@ -1637,9 +1635,7 @@ class core_course_external extends external_api {
if (!isset($excludedcats[$category->id])) {
// Final check to see if the category is visible to the user.
if ($category->visible
or has_capability('moodle/category:viewhiddencategories', context_system::instance())
or has_capability('moodle/category:manage', $context)) {
if ($category->visible or has_capability('moodle/category:viewhiddencategories', $context)) {
$categoryinfo = array();
$categoryinfo['id'] = $category->id;
+4 -3
View File
@@ -201,6 +201,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
// Set the required capabilities by the external function.
$context = context_system::instance();
$roleid = $this->assignUserCapability('moodle/category:manage', $context->id);
$this->assignUserCapability('moodle/category:viewhiddencategories', $context->id, $roleid);
// Retrieve category1 + sub-categories except not visible ones
$categories = core_course_external::get_categories(array(
@@ -259,10 +260,10 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
$this->assertEquals($DB->count_records('course_categories'), count($categories));
$this->unassignUserCapability('moodle/category:manage', $context->id, $roleid);
$this->unassignUserCapability('moodle/category:viewhiddencategories', $context->id, $roleid);
// Ensure maxdepthcategory is 2 and retrieve all categories without category:manage capability. It should retrieve all
// visible categories as well.
// Ensure maxdepthcategory is 2 and retrieve all categories without category:viewhiddencategories capability.
// It should retrieve all visible categories as well.
set_config('maxcategorydepth', 2);
$categories = core_course_external::get_categories();
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/templates","core/notification","core/yui"],function(a,b,c){return{initialise:function(d,e,f,g){function h(b,c){var e="<label>"+M.util.get_string("insertcomment","gradingform_guide")+"</label>",g="comment-chooser-"+d+"-cancel",h='<button id="'+g+'">'+M.util.get_string("cancel","moodle")+"</button>",i=new M.core.dialogue({modal:!0,headerContent:e,bodyContent:b,footerContent:h,focusAfterHide:"#"+f,id:"comments-chooser-dialog-"+d});a("#"+g).click(function(){i.hide()}),a.each(c,function(b,c){var e="#comment-option-"+d+"-"+c.id;a(e).click(function(){var b=a("#"+f),d=b.val();""!==a.trim(d)&&(d+="\n"),d+=c.description,b.val(d),i.hide()}),a(document).off("keypress",e).on("keypress",e,function(){var b=event.which||event.keyCode;(13==b||32==b)&&a(e).click()})}),i.after("visibleChange",function(a){a.prevVal&&!a.newVal&&this.destroy()},i),i.show()}function i(){var a={criterionId:d,comments:g};b.render("gradingform_guide/comment_chooser",a).done(function(a){h(a,g)}).fail(c.exception)}a("#"+e).click(function(a){a.preventDefault(),i()})}}});
define(["jquery","core/templates","core/notification","core/yui"],function(a,b,c){return{initialise:function(d,e,f,g){function h(b,c){var e="<label>"+M.util.get_string("insertcomment","gradingform_guide")+"</label>",g="comment-chooser-"+d+"-cancel",h='<button id="'+g+'">'+M.util.get_string("cancel","moodle")+"</button>",i=new M.core.dialogue({modal:!0,headerContent:e,bodyContent:b,footerContent:h,focusAfterHide:"#"+f,id:"comments-chooser-dialog-"+d});a("#"+g).click(function(){i.hide()}),a.each(c,function(b,c){var e="#comment-option-"+d+"-"+c.id;a(e).click(function(){var b=a("#"+f),d=b.val();""!==a.trim(d)&&(d+="\n"),d+=c.description,b.val(d),i.hide()}),a(document).off("keypress",e).on("keypress",e,function(){var b=event.which||event.keyCode;13!=b&&32!=b||a(e).click()})}),i.after("visibleChange",function(a){a.prevVal&&!a.newVal&&this.destroy()},i),i.show()}function i(){var a={criterionId:d,comments:g};b.render("gradingform_guide/comment_chooser",a).done(function(a){h(a,g)}).fail(c.exception)}a("#"+e).click(function(a){a.preventDefault(),i()})}}});
+1 -6
View File
@@ -38,7 +38,6 @@ if (!empty($CFG->defaulthomepage) && ($CFG->defaulthomepage == HOMEPAGE_MY) && o
$urlparams['redirect'] = 0;
}
$PAGE->set_url('/', $urlparams);
$PAGE->set_course($SITE);
$PAGE->set_pagelayout('frontpage');
$PAGE->set_other_editing_capability('moodle/course:update');
$PAGE->set_other_editing_capability('moodle/course:manageactivities');
@@ -47,11 +46,7 @@ $PAGE->set_other_editing_capability('moodle/course:activityvisibility');
// Prevent caching of this page to stop confusion when changing page after making AJAX changes.
$PAGE->set_cacheable(false);
if ($CFG->forcelogin) {
require_login();
} else {
user_accesstime_log();
}
require_course_login($SITE);
$hassiteconfig = has_capability('moodle/site:config', context_system::instance());
+3
View File
@@ -38,3 +38,6 @@ $string['clitypevalue'] = 'Tiepe waarde';
$string['clitypevaluedefault'] = 'Tiepe waarde, druk Enter om die standaard waarde te gebruik ({$a})';
$string['cliunknowoption'] = 'Ontkende opsies: {$ a} Gebruik asseblief - help opsie.';
$string['cliyesnoprompt'] = 'Tik y (beteken ja) of n (beteken nee)';
$string['environmentrequireinstall'] = 'moet geïnstalleer en geaktiveer wees';
$string['environmentrequireversion'] = 'weergawe {$a->needed} word benodig en jy het tans {$a->current}';
$string['upgradekeyset'] = 'Opgradering sleutel (los skoon om nie te stel nie)';
+1
View File
@@ -31,6 +31,7 @@
defined('MOODLE_INTERNAL') || die();
$string['language'] = 'Taal';
$string['moodlelogo'] = 'Moodle logo';
$string['next'] = 'Volgende';
$string['previous'] = 'Vorige';
$string['reload'] = 'Herlaai';
+2 -2
View File
@@ -33,10 +33,10 @@ defined('MOODLE_INTERNAL') || die();
$string['clianswerno'] = 'No';
$string['cliansweryes'] = 'Sí';
$string['cliincorrectvalueerror'] = 'Error, valor incorrecte "{$a->value}" per a "{$a->option}"';
$string['cliincorrectvalueretry'] = 'Valor incorrecte, si us plau, torneu-ho a provar.';
$string['cliincorrectvalueretry'] = 'Valor incorrecte; torneu-ho a provar.';
$string['clitypevalue'] = 'Valor de tipus';
$string['clitypevaluedefault'] = 'valor de tipus, premeu la tecla de retorn (<em>Enter</em>) per fer servir un valor per defecte ({$a})';
$string['cliunknowoption'] = 'Opcions invàlides:
$string['cliunknowoption'] = 'Opcions no reconegudes:
{$a}
L\'opció --help us orientarà.';
$string['cliyesnoprompt'] = 'Escriu y (significa Sí) o n (significa No)';
+1 -1
View File
@@ -43,7 +43,7 @@ $string['cannotunzipfile'] = 'No s\'ha pogut descomprimir el fitxer';
$string['componentisuptodate'] = 'El component està actualitzat';
$string['dmlexceptiononinstall'] = '<p>S\'ha produït un error de la base de dades [{$a->errorcode}].<br />{$a->debuginfo}</p>';
$string['downloadedfilecheckfailed'] = 'Ha fallat la comprovació del fitxer baixat';
$string['invalidmd5'] = 'L\'md5 no és vàlid. Torneu-ho a provar';
$string['invalidmd5'] = 'L\'md5 no és vàlid. Torneu a provar-ho';
$string['missingrequiredfield'] = 'Falta algun camp necessari';
$string['remotedownloaderror'] = '<p>No s\'ha pogut baixar el component al vostre servidor. Verifiqueu els paràmetres del servidor intermediari. Es recomana vivament l\'extensió cURL de PHP.</p>
<p>Haureu de baixar manualment el fitxer <a href="{$a->url}">{$a->url}</a>, copiar-lo a la ubicació «{$a->dest}» del vostre servidor i descomprimir-lo allí.</p>';
+7 -7
View File
@@ -34,7 +34,7 @@ $string['admindirname'] = 'Directori d\'administració';
$string['availablelangs'] = 'Llista d\'idiomes disponibles';
$string['chooselanguagehead'] = 'Trieu un idioma';
$string['chooselanguagesub'] = 'Trieu un idioma per a la instal·lació. S\'utilitzarà també com a idioma per defecte del lloc, tot i que després podeu canviar-lo.';
$string['clialreadyconfigured'] = 'El fitxer config.php ja existeix, feu servir admin/cli/install_database.php si voleu instal·lar el Moodle en aquest lloc web.';
$string['clialreadyconfigured'] = 'El fitxer config.php ja existeix; feu servir admin/cli/install_database.php si voleu instal·lar Moodle en aquest lloc web.';
$string['clialreadyinstalled'] = 'El fitxer de configuració config.php ja existeix. Feu servir admin/cli/upgrade.php si voleu actualitzar Moodle per a aquest lloc web.';
$string['cliinstallheader'] = 'Programa d\'instal·lació de línia d\'ordres de Moodle {$a}';
$string['databasehost'] = 'Servidor de base de dades:';
@@ -52,15 +52,15 @@ $string['installation'] = 'Instal·lació';
$string['langdownloaderror'] = 'Dissortadament l\'idioma "{$a}" no es pot baixar. La instal·lació prosseguirà en anglès.';
$string['memorylimithelp'] = '<p>El límit de memòria del PHP del vostre servidor actualment està definit en {$a}.</p>
<p>Això pot causar que Moodle tingui problemes de memòria més endavant, especialment si teniu molts mòduls habilitats i/o molts usuaris.</p>
<p>Això pot causar que Moodle tingui problemes de memòria més endavant, especialment, si teniu molts mòduls habilitats i/o molts usuaris.</p>
<p>És recomanable que configureu el PHP amb un límit superior, com ara 40 MB, sempre que sigui possible. Hi ha diverses maneres de fer això:</p>
<ol>
<li>Si podeu, recompileu el PHP amb <i>--enable-memory-limit</i>. Això permetrà que Moodle defineixi el límit de memòria per si mateix.</li>
<li>Si teniu accés al fitxer php.ini, podeu canviar el paràmetre <b>memory_limit</b> a 40 MB. Si no hi teniu accés podeu demanar al vostre administrador que ho faci ell.</li>
<li>En alguns servidors PHP podeu crear un fitxer .htaccess dins del directori de Moodle amb aquesta línia:
<li>Si teniu accés al fitxer php.ini, podeu canviar el paràmetre <b>memory_limit</b> a 40 MB. Si no hi teniu accés, podeu demanar al vostre administrador que us ho faci.</li>
<li>En alguns servidors PHP podeu crear un fitxer .htaccess dins el directori de Moodle amb aquesta línia:
<p><blockquote>php_value memory_limit 40M</blockquote></p>
<p>Tanmateix, en alguns servidors això farà que no funcioni <b>cap</b> pàgina PHP (es visualitzaran errors) en el qual cas hauríeu de suprimir el fitxer .htaccess.</p></li>
<p>Tanmateix, en alguns servidors això farà que no funcioni <b>cap</b> pàgina PHP (es visualitzaran errors); en aquest cas, hauríeu de suprimir el fitxer .htaccess.</p></li>
</ol>';
$string['paths'] = 'Camins';
$string['pathserrcreatedataroot'] = 'L\'instal·lador no pot crear el directori de dades ({$a->dataroot}).';
@@ -68,8 +68,8 @@ $string['pathshead'] = 'Confirmeu els camins';
$string['pathsrodataroot'] = 'No es pot escriure en el directori dataroot.';
$string['pathsroparentdataroot'] = 'No es pot escriure en el directori pare ({$a->parent}). L\'instal·lador no pot crear el directori ({$a->dataroot}).';
$string['pathssubadmindir'] = 'Alguns serveis d\'allotjament web (pocs) utilitzen /admin com a URL especial perquè accediu a un tauler de control o quelcom semblant. Malauradament, això entra en conflicte amb la ubicació estàndard de les pàgines d\'administració de Moodle. Podeu arreglar aquest problema canviant el nom del directori d\'administració de Moodle en la vostra instal·lació i posant el nou nom aquí. Per exemple: <em>moodleadmin</em>. Això arreglarà els enllaços d\'administració de Moodle.';
$string['pathssubdataroot'] = '<p>Directori on el Moodle emmagatzemarà els materials pujats pels usuaris.</p>
<p>Aquest directori hauria de tenir permisos de lectura i escriptura per a l\'usuari del servidor web (normalment \'www-data\', \'nobody\', or \'apache\').</p>
$string['pathssubdataroot'] = '<p>Directori on Moodle emmagatzemarà els materials pujats pels usuaris.</p>
<p>Aquest directori hauria de tenir permisos de lectura i escriptura per a l\'usuari del servidor web (normalment «www-data», «nobody», or «apache»).</p>
<p>No ha de ser accessible directament via web.</p>
<p>L\'instal·lador provarà de crear-lo si no existeix.</p>';
$string['pathssubdirroot'] = 'Camí complet del directori d\'instal·lació de Moodle.';
+35
View File
@@ -0,0 +1,35 @@
<?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/>.
/**
* 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['parentlanguage'] = 'de';
$string['thisdirection'] = 'ltr';
$string['thislanguage'] = 'Deutsch - Schweiz';
+7 -7
View File
@@ -33,12 +33,12 @@ defined('MOODLE_INTERNAL') || die();
$string['clianswerno'] = 'ο';
$string['cliansweryes'] = 'ν';
$string['cliincorrectvalueerror'] = 'Σφάλμα, λανθασμένη τιμή "{$a->value}" για το "{$a->option}"';
$string['cliincorrectvalueretry'] = 'Λανθασμένη τιμή, παρακαλώ προσπαθήστε ξανά';
$string['clitypevalue'] = 'δώσε μία τιμή';
$string['clitypevaluedefault'] = 'δώσε μία τιμή, πάτησε Enter για να χρησιμοποιήσεις τη προκαθορισμένη τιμή ({$a})';
$string['cliunknowoption'] = 'Μη αναγνωρίσιμες επιλογές:
{$a}
Παρακαλώ χρησιμοποιείστε την επιλογή --βοήθεια';
$string['cliyesnoprompt'] = 'πατώντας ν (σημαίνει ναι) αλλιώς πατώντας ο (σημαίνει όχι)';
$string['cliincorrectvalueretry'] = 'Λανθασμένη τιμή. Παρακαλούμε προσπαθήστε ξανά.';
$string['clitypevalue'] = 'πληκτρολογήστε μια τιμή';
$string['clitypevaluedefault'] = 'πληκτρολογήστε μια τιμή· πατήστε Enter για να χρησιμοποιήσετε τηνπροεπιλεγμένη τιμή ({$a})';
$string['cliunknowoption'] = 'Μη αναγνωρίσιμες επιλογές: {$a}<br />
Παρακαλούμε χρησιμοποιήστε την επιλογή --βοήθεια';
$string['cliyesnoprompt'] = 'πατώντας y (σημαίνει yes=ναι) αλλιώς πατώντας n (σημαίνει no=όχι)';
$string['environmentrequireinstall'] = 'απαιτείται να εγκατασταθεί/ ενεργοποιηθεί';
$string['environmentrequireversion'] = 'απαιτείται η έκδοση {$a->needed} ενώ εσείς έχετε την {$a->current}';
$string['upgradekeyset'] = 'Κλειδί αναβάθμισης (αφήστε κενό για να μην το ορίσετε)';
+13 -11
View File
@@ -30,19 +30,21 @@
defined('MOODLE_INTERNAL') || die();
$string['cannotcreatedboninstall'] = '<p>Αδυναμία δημιουργίας βάσης δεδομένων.</p> <p>Η βάση δεδομένων που προσδιορίστηκε δεν υπάρχει και ο χρήστης που δόθηκε δεν έχει δικαίωμα να δημιουργήσει την βάση δεδομένων.</p> <p>Ο διαχειριστής του ιστοτόπου πρέπει να επαληθεύσει τις ρυθμίσεις της βάσης δεδομένων.</p>';
$string['cannotcreatelangdir'] = 'Δε δημιουργήθηκε φάκελος γλώσσας.';
$string['cannotcreatetempdir'] = 'Δε δημιουργήθηκε φάκελος temp.';
$string['cannotdownloadcomponents'] = 'Δεν κατέβηκαν τα τμήματα.';
$string['cannotdownloadzipfile'] = 'Δεν κατέβηκε το αρχείο ZIP.';
$string['cannotfindcomponent'] = 'Δεν βρέθηκε το τμήμα.';
$string['cannotsavemd5file'] = 'Δεν αποθηκεύτηκε το αρχείο md5.';
$string['cannotsavezipfile'] = 'Δεν αποθηκεύτηκε το αρχείο ZIP.';
$string['cannotunzipfile'] = 'Δεν έγινε αποσυμπίεση του αρχείου.';
$string['componentisuptodate'] = 'Το τμήμα είναι ενημερωμένο.';
$string['downloadedfilecheckfailed'] = 'Το κατέβασμα ελέγχου αρχείου απέτυχε.';
$string['cannotcreatetempdir'] = 'Αδυναμία δημιουργίας προσωρινού φακέλου';
$string['cannotdownloadcomponents'] = 'Δεν μπορεί να γίνει λήψη των στοιχείων λογισμικού';
$string['cannotdownloadzipfile'] = 'Δεν μπορεί να γίνει λήψη του αρχείου ZIP.';
$string['cannotfindcomponent'] = 'Δεν βρέθηκε το στοιχείο λογισμικού.';
$string['cannotsavemd5file'] = 'Αδυναμία αποθήκευσης αρχείου md5.';
$string['cannotsavezipfile'] = 'Αδυναμία αποθήκευσης συμπιεσμένου αρχείου';
$string['cannotunzipfile'] = 'Αδυναμία αποσυμπίεσης αρχείου';
$string['componentisuptodate'] = 'Το στοιχείο λογισμικού είναι ενημερωμένο.';
$string['dmlexceptiononinstall'] = '<p>Παρουσιάστηκε σφάλμα βάσης δεδομένων [{$a->errorcode}].<br />{$a->debuginfo}</p>';
$string['downloadedfilecheckfailed'] = 'Αποτυχία ελέγχου αρχείου που έγινε λήψη';
$string['invalidmd5'] = 'Μη έγκυρο md5';
$string['missingrequiredfield'] = 'Κάποιο απαιτούμενο πεδίο λείπει';
$string['remotedownloaderror'] = 'Απέτυχε η λήψη του τμήματος στο διακομιστή σας, παρακαλώ επιβεβαιώστε τις ρυθμίσεις του διακομιστή proxy, η επέκταση PHP cURL συνιστάται θερμά.<br /><br />Πρέπει να κατεβάσετε το <a href="{$a->url}">{$a->url}</a> χειροκίνητα, να το αντιγράψετε στο "{$a->dest}" στο διακομιστή σας και να το αποσυμπιέσετε εκεί.';
$string['wrongdestpath'] = 'Λανθασμένη διαδρομή προορισμού.';
$string['remotedownloaderror'] = '<p>Απέτυχε η λήψη του τμήματος στον εξυπηρετητή σας. Παρακαλούμε επιβεβαιώστε τις ρυθμίσεις του διακομιστή μεσολάβησης (proxy η επέκταση PHP cURL συνιστάται θερμά.</p> <p>Πρέπει να κατεβάσετε το <a href="{$a->url}">{$a->url}</a> χειροκίνητα, να το αντιγράψετε στο "{$a->dest}" στον εξυπηρετητή σας και να το αποσυμπιέσετε εκεί.</p>';
$string['wrongdestpath'] = 'Λανθασμένη διαδρομή προορισμού (πλήρες όνομα).';
$string['wrongsourcebase'] = 'Λανθασμένη βάση πηγής URL.';
$string['wrongzipfilename'] = 'Λανθασμένo όνομα αρχείου ZIP.';
+24 -36
View File
@@ -30,51 +30,39 @@
defined('MOODLE_INTERNAL') || die();
$string['admindirname'] = 'Φάκελος Admin';
$string['availablelangs'] = 'Λίστα διαθέσιμων γλωσσών';
$string['admindirname'] = 'Φάκελος διαχειριστή';
$string['availablelangs'] = 'Λίστα διαθέσιμων πακέτων γλωσσών';
$string['chooselanguagehead'] = 'Επιλογή γλώσσας';
$string['chooselanguagesub'] = 'Παρακαλώ, επιλέξτε γλώσσα για την εγκατάσταση ΜΟΝΟ. Θα μπορείτε να επιλέξετε γλώσσα ιστοσελίδας και χρηστών σε μια μετέπειτα οθόνη.';
$string['chooselanguagesub'] = 'Παρακαλούμε, επιλέξτε γλώσσα για την εγκατάσταση. Αυτή η γλώσσα θα χρησιμοποιηθεί επίσης ως προεπιλεγμένη γλώσσα για τον ιστότοπο, αν και μπορεί να αλλάξει αργότερα.';
$string['clialreadyconfigured'] = 'Το αρχείο ρυθμίσεων config.php υπάρχει ήδη. Χρησιμοποιήστε το admin/cli/install_database.php για να εγκαταστήσετε το Moodle για αυτόν τον ιστότοπο.';
$string['clialreadyinstalled'] = 'Το αρχείο ρυθμίσεων config.php υπάρχει ήδη. Χρησιμοποιήστε το admin/cli/install_database.php για να αναβαθμίσετε το Moodle για αυτόν τον ιστότοπο.';
$string['cliinstallheader'] = 'Moodle {$a} πρόγραμμα εγκατάστασης γραμμής εντολών';
$string['databasehost'] = 'Κεντρικός Υπολογιστής Βάσης Δεδομένων';
$string['databasename'] = 'Όνομα Βάσης Δεδομένων';
$string['databasetypehead'] = 'Επιλογή οδηγού βάσης δεδομένων';
$string['dataroot'] = 'Φάκελος Δεδομένων';
$string['dataroot'] = 'Φάκελος δεδομένων';
$string['datarootpermission'] = 'Άδεια φακέλων/καταλόγων δεδομένων';
$string['dbprefix'] = 'Πρόθεμα πινάκων';
$string['dirroot'] = 'Φάκελος ΠΗΛΕΑΣ';
$string['dirroot'] = 'Φάκελος Moodle';
$string['environmenthead'] = 'Έλεγχος περιβάλλοντος...';
$string['environmentsub2'] = 'Κάθε έκδοση Moodle έχει κάποια ελάχιστη απαίτηση σχετικά με την έκδοση της PHP και ενός αριθμού από αναγκαίες επεκτάσεις PHP.
Ο πλήρης έλεγχος του περιβάλλοντος πραγματοποιείται πριν κάθε εγκατάσταση και αναβάθμιση. Παρακαλούμε επικοινωνήστε με τον διαχειριστή του εξυπηρετητή εάν δεν ξέρετε πως να εγκαταστήσετε νέα έκδοση της PHP ή να ενεργοποιήσετε επεκτάσεις της.';
$string['errorsinenvironment'] = 'Ο έλεγχος του περιβάλλοντος απέτυχε!';
$string['installation'] = 'Εγκατάσταση';
$string['langdownloaderror'] = 'Δυστυχώς η γλώσσα "{$a}" δεν είναι εγκατεστημένη. Η εγκατάσταση θα συνεχιστεί στα αγγλικά.';
$string['memorylimithelp'] = '<p>Το memory limit της PHP στο server σας είναι ορισμένο αυτή τη στιγμή στα {$a}.</p>
<p>Αυτό μπορεί να προκαλέσει προβλήματα μνήμης στο ΠΗΛΕΑΣ στη συνέχεια, ειδικά αν έχετε πολλά ενεργοποιημένα αρθρώματα και/ή πολλούς χρήστες.</p>
<p>Προτείνεται η ρύθμιση της PHP με μεγαλύτερο όριο, αν αυτό είναι δυνατό, π.χ. 16M. Υπάρχουν πολλοί τρόποι που μπορείτε να δοκιμάσετε να το κάνετε αυτό:</p>
<ol>
<li>Αν έχετε τη δυνατότητα, κάνετε επαναμεταγλώττιση την PHP με την παράμετρο <i>--enable-memory-limit</i>.
Αυτό θα επιτρέψει στο Moodle να ορίσει μόνο του το memory limit.</li>
<li>Αν έχετε πρόσβαση στο αρχείο php.ini, μπορείτε να αλλάξετε τη ρύθμιση <b>memory_limit</b>
σε 16M. Αν δεν έχετε πρόσβαση ζητήστε από το διαχειριστή να το κάνει για εσάς.</li>
<li>Σε κάποιους εξυπηρετητές PHP μπορείτε να δημιουργήσετε ένα αρχείο .htaccess στο φάκελο του ΠΗΛΕΑΣ που να περιέχει τις παρακάτω γραμμές:<p><blockquote>php_value memory_limit 16M</blockquote></p>
<p>Ωστόσο, σε κάποιους εξυπηρετητές αυτό θα εμποδίσει τη λειτουργία <b>όλων</b> των σελιδών PHP
(θα βλέπετε σφάλματα όταν ανοίγετε τις σελίδες), σε αυτήν την περίπτωση θα πρέπει να διαγράψετε το αρχείο .htaccess.</p></li>
</ol>';
$string['memorylimithelp'] = '<p>Το όριο μνήμης της PHP στον εξυπηρετητή σας είναι ορισμένο αυτή τη στιγμή στα {$a}.</p> <p>Αυτό μπορεί να προκαλέσει προβλήματα μνήμης στο Moodle στη συνέχεια, ειδικά αν έχετε πολλά ενεργοποιημένα αρθρώματα και/ή πολλούς χρήστες.</p> <p>Προτείνεται η ρύθμιση της PHP με μεγαλύτερο όριο, αν αυτό είναι δυνατό, π.χ. 40M. Υπάρχουν πολλοί τρόποι να το κάνετε αυτό, τους οποίους μπορείτε να δοκιμάσετε:</p> <ol> <li>Αν έχετε τη δυνατότητα, κάνετε επαναμεταγλώττιση την PHP με την παράμετρο <i>--enable-memory-limit</i>. Αυτό θα επιτρέψει στο Moodle να ορίσει μόνο του το όριο μνήμης.</li> <li>Αν έχετε πρόσβαση στο αρχείο php.ini, μπορείτε να αλλάξετε τη ρύθμιση <b>memory_limit</b> σε 40M. Αν δεν έχετε πρόσβαση ζητήστε από το διαχειριστή να το κάνει για εσάς.</li> <li>Σε κάποιους εξυπηρετητές PHP μπορείτε να δημιουργήσετε ένα αρχείο .htaccess στο φάκελο του Moodle που να περιέχει τις παρακάτω γραμμές:<p><blockquote>php_value memory_limit 40M</div></blockquote> <p>Ωστόσο, σε κάποιους εξυπηρετητές αυτό θα εμποδίσει τη λειτουργία <b>όλων</b> των σελιδών PHP (θα βλέπετε σφάλματα όταν ανοίγετε τις σελίδες), οπότε θα πρέπει να διαγράψετε το αρχείο .htaccess.</p></li> </ol>';
$string['paths'] = 'Διαδρομές';
$string['pathserrcreatedataroot'] = 'Ο Φάκελος Δεδομένων ({$a->dataroot}) δεν μπορεί να δημιουργθεί από το πρόγραμμα εγκατάστασης.';
$string['pathserrcreatedataroot'] = 'Ο Φάκελος δεδομένων ({$a->dataroot}) δεν μπορεί να δημιουργθεί από το πρόγραμμα εγκατάστασης.';
$string['pathshead'] = 'Επιβεβαίωση Διαδρομών';
$string['pathsrodataroot'] = 'Ο Φάκελος Δεδομένων δεν είναι εγγράψιμος.';
$string['pathsroparentdataroot'] = 'Ο Φάκελος γονέας ({$a->parent}) δεν είναι εγγράψιμος. Ο Φάκελος Δεδομένων ({$a->dataroot}) δεν μπορεί να δημιουργθεί από το πρόγραμμα εγκατάστασης.';
$string['pathssubadmindir'] = 'Λίγοι κεντρικοί υπολογιστές ιστού χρησιμοποιούν το /admin σαν ένα ειδικό URL για να έχετε πρόσβαση
σε έναν πίνακα ελέγχου ή κάτι παρόμοιο. Δυστυχώς αυτό έρχεται σε σύγκρουση με την πρότυπη τοποθεσία για τις σελίδες διαχείρισης του Moodle. Μπορείτε να το διορθώσετε αυτό
μετονομάζοντας τον φάκελο admin στην εγκατάσταση σας, και βάζοντας ένα νέο όνομα εδώ. Για παράδειγμα: <em>moodleadmin</em>. Αυτό θα διορθώσει τους συνδέσμους στο Moodle.';
$string['pathssubdataroot'] = 'Χρειάζεστε ένα μέρος όπου το Moodle μπορεί να αποθηκεύει τα ανεβασμένα αρχεία. Αυτός ο φάκελος θα πρέπει να μπορεί να διαβάζεται και να εγγράφεται από τον χρήστη του εξυπηρετητή ιστού
(συνήθως \'nobody\' ή \'apache\'), αλλά δεν πρέπει να είναι προσβάσιμος απευθείας μέσω ιστού. Το πρόγραμμα εγκατάστασης θα προσπαθήσει να τον δημιουργήσει εάν δεν υπάρχει.';
$string['pathssubdirroot'] = 'Πλήρης διαδρομή φακέλου για την εγκατάσταση moodle. Αλλάξτε την μόνο εάν χρειάζεται να χρησιμοποιήστε symbolic links.';
$string['pathssubwwwroot'] = 'Πλήρης διεύθυνση ιστού από την οποία θα υπάρχει πρόσβαση στο moodle.
Δεν είναι δυνατόν να έχετε πρόβαση στο Moodle χρησιμοποιώντας πολλαπλές διευθύνσεις.
Εάν ο ιστοχώρος έχει πολλαπλές δημόσιες διευθύνσεις θα πρέπει να ρυθμίσετε μόνιμες ανακατευθύνσεις σε καθεμία από αυτές εκτός από αυτήν.
Εάν ο ιστοχώρος σας είναι προσβάσιμος και από intranet και από το Διαδίκτυο χρησιμοποιήστε την δημόσια διεύθυνση εδώ και ρυθμίστε τον DNS ώστε οι χρήστες του inranet να μπορούν να χρησιμοποιούν και αυτοί την δημόσια διεύθυνση.';
$string['pathsroparentdataroot'] = 'Ο γονικός φάκελος ({$a->parent}) δεν είναι εγγράψιμος. Ο φάκελος δεδομένων ({$a->dataroot}) δεν μπορεί να δημιουργθεί από το πρόγραμμα εγκατάστασης.';
$string['pathssubadmindir'] = 'Κάποιοι λίγοι κεντρικοί υπολογιστές ιστού χρησιμοποιούν το /admin ως ειδική διεύθυνση URL για την πρόσβαση σε κάποιο πίνακα ελέγχου ή κάτι τέτοιο. Δυστυχώς αυτό έρχεται σε αντίθεση με την τυπική τοποθεσία των σελίδων διαχείρισης (admin) του Moodle. Αυτό μπορεί να διορθωθεί με την μετονομασία του admin φακέλου στην εγκατάστασή σας, και βάζοντας αυτό το καινούργιο όνομα εδώ. Για παράδειγμα: <em>moodleadmin</em>. Αυτό θα διορθώσει όλους τους συνδέσμους με το admin στην διεύθυνσή τους σε όλη την εγκατάσταση του Moodle σας.';
$string['pathssubdataroot'] = '<p>Ένας φάκελος όπου το Moodle θα αποθηκεύει όλα τα ανεβασμένα από τους χρήστες αρχεία.</p> <p>Αυτος ο φάκελος θα πρέπει να είναι αναγνώσιμος ΚΑΙ ΕΓΓΡΑΨΙΜΟΣ από τον χρήστη του εξυπηρετητή ιστού (συνήθως \'nobody\' ή \'apache\').</p> <p>Δεν πρέπει να είναι προσβάσιμος κατευθείαν από τον ιστό.</p> <p>Αν ο φάκελος δεν υπάρχει, η διαδικασία εγκατάστασης θα προσπαθήσει να τον δημιουργήσει.</p>';
$string['pathssubdirroot'] = '<p>Η πλήρης διαδρομή του φακέλου που περιέχει τα αρχεία κώδικα του Moodle.</p>';
$string['pathssubwwwroot'] = '<p>Η πλήρης διεύθυνση (ιστού) από την οποία θα γίνεται η πρόσβαση στο Moodle, δηλαδή η διεύθυνση που οι χρήστες θα εισάγουν στην γραμμή διεύθυνσης του περιηγητή, για να έχουν πρόσβαση στου Moodle.</p>
<p>Δεν είναι δυνατόν να έχετε πρόβαση στο Moodle χρησιμοποιώντας πολλαπλές διευθύνσεις. Εάν ο ιστότοπος θα είναι προσβάσιμος μέσω πολλαπλών διευθύνσεων τότε επιλέξτε την ευκολότερη και εγκαταστήστε μια μόνιμη ανακατεύθυνση για καθεμία από τις άλλες διευθύνσεις.</p>
<p>Εάν ο ιστότοπός σας είναι προσβάσιμος τόσο από το Διαδίκτυο όσο και από ένα εσωτερικό δίκτυο (που συχνά λέγεται intranet) τότε χρησιμοποιήστε εδώ την δημόσια διεύθυνση.</p>
<p>Αν η τρέχουσα διεύθυνση δεν είναι σωστή, παρακαλούμε αλλάξτε την URL διεύθυνση στην γραμμή διευθύνσεων του περιηγητή σας και επανεκκινήστε την εγκατάσταση.</p>';
$string['pathsunsecuredataroot'] = 'Η τοποθεσία του Φάκελου Δεδομένων δεν είναι ασφαλής';
$string['pathswrongadmindir'] = 'Ο Φάκελος Admin δεν υπάρχει';
$string['phpextension'] = 'Επέκταση {$a} της PHP';
@@ -85,9 +73,9 @@ $string['phpversionhelp'] = '<p>Το ΠΗΛΕΑΣ απαιτεί η έκδοση
(Σε περίπτωση που έχετε την 5.0.x μπορείτε επίσης να κάνετε και υποβάθμιση στην έκδοση 4.4.x)</p>';
$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
$string['welcomep20'] = 'Βλέπετε αυτή τη σελίδα γιατί εγκαταστήσατε και ξεκινήσατε με επιτυχία το πακέτο <strong>{$a->packname} {$a->packversion}</strong> στον υπολογιστή σας. Συγχαρητήρια!';
$string['welcomep30'] = 'Αυτή η έκδοση <strong>{$a->installername}</strong> περιλαμβάνει τις εφαρμογές για τη δημιουργία ενός περιβάλλοντος μέσα στο οποίο θα λειτουργεί το <strong>ΠΗΛΕΑΣ </strong>:';
$string['welcomep40'] = 'Το πακέτο περιλαμβάνει επίσης <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
$string['welcomep50'] = 'Η χρήση όλων των εφαρμογών σε αυτό το πακέτο υπόκειται στις αντίστοιχες άδειες. Ολόκληρο το πακέτο <strong>{$a->installername}</strong> είναι <a href="http://www.opensource.org/docs/definition_plain.html">open source</a> και διανέμεται με την <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a> άδεια.';
$string['welcomep60'] = 'Οι παρακάτω σελίδες θα σας καθοδηγήσουν με εύκολα βήματα στην εγκατάσταση και ρύθμιση του <strong>ΠΗΛΕΑΣ </strong> στο υπολογιστή σας. Μπορείτε να δεχθείτε τις προκαθορισμένες ρυθμίσεις ή να τις αλλάξετε ανάλογα με τις ανάγκες σας.';
$string['welcomep30'] = 'Αυτή η έκδοση/διανομή <strong>{$a->installername}</strong> περιλαμβάνει τις εφαρμογές για τη δημιουργία ενός περιβάλλοντος μέσα στο οποίο θα λειτουργεί το <strong>Moodle</strong>, ονομαστικά:';
$string['welcomep40'] = 'Το πακέτο περιλαμβάνει επίσης το <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
$string['welcomep50'] = 'Η χρήση όλων των εφαρμογών σε αυτό το πακέτο υπόκειται στις αντίστοιχες άδειες. Ολόκληρο το πακέτο <strong>{$a->installername}</strong> είναι <a href="http://www.opensource.org/docs/definition_plain.html">λογισμικό ανοικτού κώδικα</a> και διανέμεται με την <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a> άδεια.';
$string['welcomep60'] = 'Οι παρακάτω σελίδες θα σας καθοδηγήσουν με εύκολα βήματα στην εγκατάσταση και ρύθμιση του <strong>Moodle</strong> στον υπολογιστή σας. Μπορείτε να δεχθείτε τις προεπιλεγμένες ρυθμίσεις ή προαιρετικά, να τις τροποποιήσετε ανάλογα με τις ανάγκες σας.';
$string['welcomep70'] = 'Πατήστε το κουμπί "Συνέχεια" για να συνεχίσετε με την εκγατάσταση του <strong>Moodle</strong>.';
$string['wwwroot'] = 'Διεύθυνση ιστοσελίδας';
$string['wwwroot'] = 'Διεύθυνση ιστού';
+7 -6
View File
@@ -32,12 +32,13 @@ defined('MOODLE_INTERNAL') || die();
$string['clianswerno'] = 'e';
$string['cliansweryes'] = 'b';
$string['cliincorrectvalueerror'] = 'Errorea, "{$a->value}" balorea ez da egokia "{$a->option}"-rako';
$string['cliincorrectvalueretry'] = 'Balore ezegokia, mesedez saiatu berriz';
$string['clitypevalue'] = 'Sartu balorea';
$string['clitypevaluedefault'] = 'sartu balorea, sakatu Enter-i berezko balorea erabiltzeko ({$a})';
$string['cliunknowoption'] = 'Aukera ezezagunak:{$a}
Mesedez, erabili --laguntza aukera.';
$string['cliincorrectvalueerror'] = 'Errorea, "{$a->value}" balioa ez da egokia "{$a->option}"-rako';
$string['cliincorrectvalueretry'] = 'Balio ezegokia, mesedez saiatu berriz';
$string['clitypevalue'] = 'Sartu balioa';
$string['clitypevaluedefault'] = 'sartu balioa, sakatu Enter-i berezko balioa erabiltzeko ({$a})';
$string['cliunknowoption'] = 'Aukera ezezagunak:
{$a}
Mesedez, erabili --help aukera.';
$string['cliyesnoprompt'] = 'idatzi b (bai esateko) edo e (ez esateko)';
$string['environmentrequireinstall'] = 'derrigorrezkoa da instalatuta eta gaituta izatea';
$string['environmentrequireversion'] = '{$a->needed} bertsioa beharrezkoa da eta zu {$a->current} ari zara egikaritzen';
+1 -1
View File
@@ -43,7 +43,7 @@ $string['cannotsavezipfile'] = 'Ezin da ZIP fitxategia gorde';
$string['cannotunzipfile'] = 'Ezin da fitxategia deskonprimatu';
$string['componentisuptodate'] = 'Osagaia eguneratu da';
$string['dmlexceptiononinstall'] = '<p>Datu-basearen errorea gertatu da [{$a->errorcode}].<br />{$a->debuginfo}</p>';
$string['downloadedfilecheckfailed'] = 'Jaitsitako fitxategiaren konprobazioak kale egin du.';
$string['downloadedfilecheckfailed'] = 'Jaitsitako fitxategiaren egiaztatzeak huts egin du.';
$string['invalidmd5'] = 'Kontrolerako aldagaia gaizki zegoen - saiatu berriz ere';
$string['missingrequiredfield'] = 'Beharrezko eremuren bat falta da.';
$string['remotedownloaderror'] = '<p>Errorea osagaia zure zerbitzarira jaistean. Mesedez egiaztatu proxy-ezarpenak; PHP cURL luzapea erabat gomendatzen da.</p>
+2 -2
View File
@@ -98,6 +98,6 @@ $string['welcomep50'] = 'Paketeko aplikazio guztien erabilpena dagozkien lizentz
arautzen dute. <strong>{$a->installername}</strong> aplikazioak
<a href="http://www.opensource.org/docs/definition_plain.html">kode irekia</a> dauka eta
<a href="http://www.gnu.org/copyleft/gpl.html">GPL</a> lizentziapean banatzen da.';
$string['welcomep60'] = 'Datozen orriek urrats erraz batzuen bidez gidatuko zaituzte <strong>Moodle</strong> zure ordenagailuan instalatu eta konfiguratzeko. Aholkatzen diren lehentsitako baloreak mantendu edo, nahi izanez gero, alda ditzakezu zure beharrei erantzun diezaieten.';
$string['welcomep70'] = '"Hurrengoa" botoia sakatu <strong>Moodle</strong>ren konfigurazioarekin jarraitzeko.';
$string['welcomep60'] = 'Datozen orriek urrats erraz batzuen bidez gidatuko zaituzte <strong>Moodle</strong> zure ordenagailuan instalatu eta konfiguratzeko. Aholkatzen diren lehenetsitako balioak mantendu edo, nahi izanez gero, alda ditzakezu zure beharrei erantzun diezaieten.';
$string['welcomep70'] = 'Egin klik "Hurrengoa" botoian <strong>Moodle</strong>ren konfigurazioarekin jarraitzeko.';
$string['wwwroot'] = 'Web helbidea';
+1
View File
@@ -30,5 +30,6 @@
defined('MOODLE_INTERNAL') || die();
$string['parentlanguage'] = '';
$string['thisdirection'] = 'ltr';
$string['thislanguage'] = 'Euskara';
+1
View File
@@ -32,3 +32,4 @@ defined('MOODLE_INTERNAL') || die();
$string['language'] = 'Tungumál';
$string['next'] = 'Næsta';
$string['previous'] = 'Undanfarna';
+2 -2
View File
@@ -39,7 +39,7 @@ $string['cannotdownloadcomponents'] = 'Non foi posíbel descargar compoñentes';
$string['cannotdownloadzipfile'] = 'Non foi posíbel descargar o ficheiro ZIP';
$string['cannotfindcomponent'] = 'Non foi posíbel atopar o compoñente';
$string['cannotsavemd5file'] = 'Non é posíbel gardar o ficheiro md5';
$string['cannotsavezipfile'] = 'Non é posíbel gardar o ficheiro ZIP';
$string['cannotsavezipfile'] = 'Non é posíbel gardar o arquivo ZIP';
$string['cannotunzipfile'] = 'Non é posíbel descomprimir o ficheiro';
$string['componentisuptodate'] = 'O compoñente está actualizado';
$string['dmlexceptiononinstall'] = '<p>Produciuse un erro na base de datos [{$a->errorcode}].<br />{$a->debuginfo}</p>';
@@ -50,4 +50,4 @@ $string['remotedownloaderror'] = '<p>Fallo a descarga do compoñente cara o seu
<p>Debe descargar o ficheiro <a href="{$a->url}">{$a->url}</a> manualmente, copialo en «{$a->dest}» no seu servidor e descomprimilo alí.</p>';
$string['wrongdestpath'] = 'Camiño de destino errado.';
$string['wrongsourcebase'] = 'URL da fonte errado.';
$string['wrongzipfilename'] = 'Nome de ficheiro ZIP errado.';
$string['wrongzipfilename'] = 'Nome de arquivo ZIP errado';
+3
View File
@@ -30,6 +30,9 @@
defined('MOODLE_INTERNAL') || die();
$string['cannotcreatedboninstall'] = '<p>Ne mogu stvoriti bazu podataka.</p>
<p>Navedena baza podataka ne postoji i korisnik nema prava stvaranja baze podataka.</p>
<p>Administrator treba provjeriti postavke baze podataka.</p>';
$string['cannotcreatelangdir'] = 'Nije moguće stvoriti lang mapu';
$string['cannotcreatetempdir'] = 'Nije moguće stvoriti privremenu (TEMP) mapu';
$string['cannotdownloadcomponents'] = 'Nije moguće preuzimanje komponenti';
+3 -6
View File
@@ -30,7 +30,7 @@
defined('MOODLE_INTERNAL') || die();
$string['admindirname'] = 'Rendszergazdakönyvtár';
$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.';
@@ -59,11 +59,8 @@ $string['pathsroparentdataroot'] = 'A felettes könyvtár ({$a->parent}) nem ír
$string['pathssubadmindir'] = 'Egy pár webes gazdagép esetén az /admin speciális URL pl. a vezérlőpanel eléréséhez. Ez ütközik a Moodle admin oldalainak standard helyével. Javítás: a telepítésben nevezze át a rendszergazda könyvtárát, az új nevet pedig írja be ide. Például: <em>moodleadmin</em>. Ezzel helyrehozhatók a Moodle rendszergazdai ugrópontjai.';
$string['pathssubdataroot'] = 'Szüksége van egy helyre, ahol a Moodle mentheti a feltöltött állományokat. Ez a könyvtár a webszerver felhasználója (általában \'nobody\' vagy \'apache\') számára legyen mind olvasható, MIND ÍRHATÓ. Ha nem létezik, a telepítő megpróbálja létrehozni.';
$string['pathssubdirroot'] = 'Teljes útvonal a Moodle telepítéséhez. ';
$string['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 az URL-t, hogy a telepítés egy másik értékkel induljon újra.';
$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.';
$string['pathsunsecuredataroot'] = 'Az adatok gyökérkönyvtára nem biztonságos.';
$string['pathswrongadmindir'] = 'Nem létezik az admin könyvtár.';
$string['phpextension'] = '{$a} PHP-bővítmény';
+1
View File
@@ -31,6 +31,7 @@
defined('MOODLE_INTERNAL') || die();
$string['language'] = 'Bahasa';
$string['moodlelogo'] = 'Logo Moodle';
$string['next'] = 'Selanjutnya';
$string['previous'] = 'Sebelumnya';
$string['reload'] = 'Muat ulang';
+1
View File
@@ -31,6 +31,7 @@
defined('MOODLE_INTERNAL') || die();
$string['language'] = 'Tungumál';
$string['moodlelogo'] = 'Moodle merkið';
$string['next'] = 'Áfram';
$string['previous'] = 'Til baka';
$string['reload'] = 'Endurhlaða';
+1 -1
View File
@@ -46,7 +46,7 @@ $string['dbprefix'] = 'テーブル接頭辞';
$string['dirroot'] = 'Moodleディレクトリ';
$string['environmenthead'] = 'あなたの環境を確認しています ...';
$string['environmentsub2'] = 'それぞれのMoodleリリースにはPHPバージョンの最小必要条件および多くの必須PHP拡張モジュールがあります。完全な環境チェックはインストールおよびアップグレードごとに実行されます。新しいPHPバージョンのインストールまたはPHP拡張モジュールの有効化に関して分からない場合、あなたのサーバ管理者にご連絡ください。';
$string['errorsinenvironment'] = '環境チェック失敗しました!';
$string['errorsinenvironment'] = '環境チェック失敗しました!';
$string['installation'] = 'インストレーション';
$string['langdownloaderror'] = '残念ですが、言語「 {$a} 」をダウンロードできませんでした。インストール処理は英語で継続されます。';
$string['memorylimithelp'] = '<p>現在、サーバのPHPメモリ制限が {$a} に設定されています。</p>
+1
View File
@@ -30,5 +30,6 @@
defined('MOODLE_INTERNAL') || die();
$string['parentlanguage'] = '';
$string['thisdirection'] = 'ltr';
$string['thislanguage'] = 'Lietuvių';
+2 -2
View File
@@ -36,8 +36,8 @@ $string['cannotcreatetempdir'] = 'Não é possível criar a pasta de ficheiros t
$string['cannotdownloadcomponents'] = 'Não é possível descarregar os componentes.';
$string['cannotdownloadzipfile'] = 'Não é possível descarregar o ficheiro ZIP.';
$string['cannotfindcomponent'] = 'Não é possível encontrar o componente';
$string['cannotsavemd5file'] = 'Não é possível gravar o ficheiro md5';
$string['cannotsavezipfile'] = 'Não é possível gravar o ficheiro ZIP';
$string['cannotsavemd5file'] = 'Não é possível guardar o ficheiro md5';
$string['cannotsavezipfile'] = 'Não é possível guardar o ficheiro ZIP';
$string['cannotunzipfile'] = 'Não é possível descompactar o ficheiro ZIP';
$string['componentisuptodate'] = 'O componente está atualizado.';
$string['dmlexceptiononinstall'] = '<p>Ocorreu um erro de base de dados [{$a->errorcode}].<br />{$a->debuginfo}</p>';
+2 -2
View File
@@ -30,8 +30,8 @@
defined('MOODLE_INTERNAL') || die();
$string['clianswerno'] = 'n';
$string['cliansweryes'] = 'y';
$string['clianswerno'] = 'нет';
$string['cliansweryes'] = 'да';
$string['cliincorrectvalueerror'] = 'Ошибка, некорректное значение «{$a->value}» для «{$a->option}»';
$string['cliincorrectvalueretry'] = 'Некорректное значение, пожалуйста, попробуйте заново';
$string['clitypevalue'] = 'введите значение';
+8 -4
View File
@@ -34,15 +34,18 @@ $string['admindirname'] = 'Adresár pre správu (admin)';
$string['availablelangs'] = 'Dostupné jazykové balíčky';
$string['chooselanguagehead'] = 'Vyberte jazyk';
$string['chooselanguagesub'] = 'Zvoľte si jazyk pre inštaláciu. Tento jazyk bude tiež použitý ako východzí jazyk portálu, ale môže byť neskôr zmenený.';
$string['clialreadyinstalled'] = 'Súbor config.php už existuje. Použite admin/cli/upgrade.php ak chcete aktualizovať váš portál.';
$string['clialreadyconfigured'] = 'Konfiguračný súbor config.php už existuje. Spusťte admin/cli/install_database.php, ak chcete inštalovať Moodle pre tento portál.';
$string['clialreadyinstalled'] = 'Súbor config.php už existuje. Použite admin/cli/install_database.php ak chcete aktualizovať váš portál.';
$string['cliinstallheader'] = 'Moodle {$a} inštalačný program z príkazového riadku';
$string['databasehost'] = 'Databázový server';
$string['databasename'] = 'Názov databázy';
$string['databasetypehead'] = 'Vyberte ovládač pre databázu';
$string['dataroot'] = 'Adresár pre údaje';
$string['datarootpermission'] = 'Prístupové práva k údajovému adresáru';
$string['dbprefix'] = 'Predpona tabuliek';
$string['dirroot'] = 'Adresár Moodle';
$string['environmenthead'] = 'Kontrola programového prostredia...';
$string['environmentsub2'] = 'Každé vydanie Moodle vyžaduje určitú minimálnu verziu PHP a niekoľko povinných rozšírení PHP. Plná kontrola prostredia sa vykonáva pred každou inštaláciou a aktualizáciou. Prosím, kontaktujte správcu servera, ak neviete, ako nainštalovať novú verziu, alebo povoliť rozšírenia PHP.';
$string['errorsinenvironment'] = 'Kontrola programového prostredia zlyhala!';
$string['installation'] = 'Inštalácia';
$string['langdownloaderror'] = 'Bohužiaľ, jazyk "{$a}" sa nepodarilo nainštalovať. Inštalácia bude pokračovať v angličtine.';
@@ -62,8 +65,9 @@ $string['pathserrcreatedataroot'] = 'Inštalátor nemôže vytvoriť dátový ad
$string['pathshead'] = 'Vytvoriť cesty';
$string['pathsrodataroot'] = 'Kmeňový adresár nie je zapisovateľný';
$string['pathsroparentdataroot'] = 'Nadriadený adresár ({$a->parent}) nie je zapisovateľný. Inštalátor nemôže vytvoriť dátový adresár ({$a->dataroot}). ';
$string['pathssubdataroot'] = 'Potrebujete adresár, kam Moodle bude ukladať nahrané súbory. Adresár by mal povoliť čítanie a zapisovanie údajov používateľom web serveru, ale nesmie byť prístupný priamo cez web rozhranie. Pokiaľ ešte neexistuje, inštalácia sa pokúsi o jeho vytvorenie. ';
$string['pathssubdirroot'] = 'Plná cesta adresára moodle inštalácie';
$string['pathssubdataroot'] = '<p>Potrebujete adresár, kam Moodle bude ukladať nahrané súbory.</p>
<p>Adresár by mal povoliť čítanie a zapisovanie údajov používateľom web serveru (webový server býva väčšinou spustený pod používateľom "www-data" alebo "apache"), ale nesmie byť prístupný priamo cez web rozhranie. Pokiaľ ešte neexistuje, inštalácia sa pokúsi o jeho vytvorenie. </p>';
$string['pathssubdirroot'] = '<p>Absolútna cesta adresára Moodle inštalácie.</p>';
$string['pathsunsecuredataroot'] = 'Umiestnenie dátového adresára nie je bezpečné';
$string['pathswrongadmindir'] = 'Administrátorský adresár neexistuje';
$string['phpextension'] = 'Rozšírenie PHP {$a}';
@@ -73,7 +77,7 @@ $string['phpversionhelp'] = '<p>Moodle si vyžaduje verziu PHP aspoň 4.3.0 ale
<p>Musíte aktualizovať PHP alebo sa presunúť na hostiteľský počítač s novšou verziou PHP!<br />(V prípade 5.0.X môžete tiež prejsť na verziu 4.4.x)</p>';
$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
$string['welcomep20'] = 'Podarilo so vám úspešne nainštalovať a spustiť balíček <strong>{$a->packname} {$a->packversion}</strong>. Gratulujeme!';
$string['welcomep30'] = '<strong>{$a->installername}</strong> obsahuje aplikáciu k vytvoreniu prostredia, v ktorom bude prevádzkovaný váš <strong>Moodle</strong>. Menovite sa jedná o:';
$string['welcomep30'] = 'Táto verzia <strong>{$a->installername}</strong> obsahuje aplikáciu k vytvoreniu prostredia, v ktorom bude prevádzkovaný váš <strong>Moodle</strong>. Menovite sa jedná o:';
$string['welcomep40'] = 'Balíček tiež obsahuje <strong>Moodle vo verzii {$a->moodlerelease} ({$a->moodleversion})</strong>.';
$string['welcomep50'] = 'Použitie všetkých aplikácií v tomto balíčku je viazané ich príslušnými licenciami. Kompletný balíček <strong>{$a->installername}</strong> je software s <a href="http://www.opensource.org/docs/definition_plain.html"> otvoreným kódom (open source)</a> a je šírený pod licenciou <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>.';
$string['welcomep60'] = 'Nasledujúce stránky vás povedú v nekoľkých jednoduchých krokoch nastavením <strong>Moodle</strong> na vašom počítači. Môžete prijať východzie nastavenie, alebo si ich upraviť podľa svojich potrieb.';
+1
View File
@@ -42,3 +42,4 @@ Uporabite --help opcijo.';
$string['cliyesnoprompt'] = 'pritisnite d (pomeni da) ali n (pomeni ne)';
$string['environmentrequireinstall'] = 'namestitev oz. omogočanje je zahtevano.';
$string['environmentrequireversion'] = 'različica {$a->needed} je zahtevana, vi uporabljate {$a->current}';
$string['upgradekeyset'] = 'Ključ za nadgradnjo (pustite prazno, če ga ne želite nastaviti)';
+1
View File
@@ -42,3 +42,4 @@ $string['cliunknowoption'] = 'Unrecognised ఎంపికలు:
$string['cliyesnoprompt'] = 'y (అంటే ఔనని) గానీ, n (అంటే వద్దని) గానీ నొక్కండి';
$string['environmentrequireinstall'] = 'స్థాపించి, చేతనం చెయ్యడం తప్పనిసరి';
$string['environmentrequireversion'] = '{$a->needed} వెర్షను తప్పనిసరి. మీరేమో {$a->current} వెర్షను వాడుతున్నారు';
$string['upgradekeyset'] = 'అప్గ్రేడ్ కీ (ఇది సెట్ చేయకుండా ఖాళీగా వదలండి)';
+6
View File
@@ -30,9 +30,15 @@
defined('MOODLE_INTERNAL') || die();
$string['cannotcreatedboninstall'] = '<p> డేటాబేస్ను సృష్టించలేరు. </ p>
<p> పేర్కొన్న డేటాబేస్ ఉనికిలో లేదు మరియు ఇచ్చిన యూజర్కు డాటాబేస్ను సృష్టించడానికి అనుమతి లేదు. </ p>
<p> సైట్ నిర్వాహకుడు డేటాబేస్ కాన్ఫిగరేషన్ను ధృవీకరించాలి. </ p>';
$string['cannotcreatelangdir'] = 'భాష డైరెక్టరీని సృష్టించలేం';
$string['cannotcreatetempdir'] = 'టెంప్ డైరెక్టరీని సృష్టించలేం';
$string['cannotdownloadcomponents'] = 'కాంపొనెంట్లను దించుకోలేరు';
$string['cannotdownloadzipfile'] = 'ZIP దస్త్రాలను దించుకోలేరు';
$string['cannotfindcomponent'] = 'కాంపొనెంటు కనబడలేదు';
$string['cannotsavemd5file'] = 'Md5 ఫైల్ను సేవ్ చేయలేరు';
$string['cannotsavezipfile'] = 'జిప్ ఫైల్ను సేవ్ చేయడం సాధ్యపడదు';
$string['cannotunzipfile'] = 'ఫైల్ అన్జిప్ చేయలేరు';
$string['componentisuptodate'] = 'కాంపొనెంటు తాజాగా ఉంది';
+1
View File
@@ -31,6 +31,7 @@
defined('MOODLE_INTERNAL') || die();
$string['language'] = 'భాష';
$string['moodlelogo'] = 'మూడ్లె లోగో';
$string['next'] = 'తరువాతి';
$string['previous'] = 'గత';
$string['reload'] = 'మళ్ళీ లోడు చెయ్యి';
+10
View File
@@ -30,5 +30,15 @@
defined('MOODLE_INTERNAL') || die();
$string['clianswerno'] = 'n';
$string['cliansweryes'] = 'y';
$string['cliincorrectvalueerror'] = 'Error, maling halagang "{$a->value}" para sa "{$a->option}"';
$string['cliincorrectvalueretry'] = 'Maling halaga, ulitin po';
$string['clitypevalue'] = 'iteklado ang halaga';
$string['clitypevaluedefault'] = 'iteklado ang halaga, pindutin ang Enter para magamit ang default na halaga ({$a})';
$string['cliunknowoption'] = 'Di-kilalang opsiyon:
{$a}
Gamit po ang --help na opsiyon';
$string['cliyesnoprompt'] = 'iteklado ang y (ibig sabihin ay yes/oo) o n (ibig sabihin ay no/hindi)';
$string['environmentrequireinstall'] = 'ay kinakailangang maluklok/mabuhay';
$string['environmentrequireversion'] = 'ang bersiyon {$a->needed} ay kinakailangan at ang pinatatakbo mo ay {$a->current}';
+2
View File
@@ -31,5 +31,7 @@
defined('MOODLE_INTERNAL') || die();
$string['language'] = 'Wikà';
$string['moodlelogo'] = 'Logo ng Moodle';
$string['next'] = 'Susunod';
$string['previous'] = 'Nakaraan';
$string['reload'] = 'I-reload';
-88
View File
@@ -1,88 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* GeoIP tests
*
* @package core_iplookup
* @category phpunit
* @copyright 2012 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* GeoIp data file parsing test.
*/
class core_iplookup_geoip_testcase extends advanced_testcase {
public function setUp() {
global $CFG;
require_once("$CFG->libdir/filelib.php");
require_once("$CFG->dirroot/iplookup/lib.php");
if (!PHPUNIT_LONGTEST) {
// this may take a long time
$this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
}
$this->resetAfterTest();
// let's store the file somewhere
$gzfile = "$CFG->dataroot/phpunit/geoip/GeoLiteCity.dat.gz";
check_dir_exists(dirname($gzfile));
if (file_exists($gzfile) and (filemtime($gzfile) < time() - 60*60*24*30)) {
// delete file if older than 1 month
unlink($gzfile);
}
if (!file_exists($gzfile)) {
download_file_content('http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz', null, null, false, 300, 20, false, $gzfile);
}
$this->assertTrue(file_exists($gzfile));
$zd = gzopen($gzfile, "r");
$contents = gzread($zd, 50000000);
gzclose($zd);
$geoipfile = "$CFG->dataroot/geoip/GeoLiteCity.dat";
check_dir_exists(dirname($geoipfile));
$fp = fopen($geoipfile, 'w');
fwrite($fp, $contents);
fclose($fp);
$this->assertTrue(file_exists($geoipfile));
$CFG->geoipfile = $geoipfile;
}
public function test_ipv4() {
$result = iplookup_find_location('192.30.255.112');
$this->assertEquals('array', gettype($result));
$this->assertEquals('San Francisco', $result['city']);
$this->assertEquals(-122.3933, $result['longitude'], 'Coordinates are out of accepted tolerance', 0.01);
$this->assertEquals(37.7697, $result['latitude'], 'Coordinates are out of accepted tolerance', 0.01);
$this->assertNull($result['error']);
$this->assertEquals('array', gettype($result['title']));
$this->assertEquals('San Francisco', $result['title'][0]);
$this->assertEquals('United States', $result['title'][1]);
}
}
+1 -1
View File
@@ -47,7 +47,7 @@ class core_iplookup_geoplugin_testcase extends advanced_testcase {
}
public function test_geoip_ipv4() {
$result = iplookup_find_location('192.30.255.112');
$result = iplookup_find_location('50.0.184.0');
$this->assertEquals('array', gettype($result));
$this->assertEquals('San Francisco', $result['city']);
+2
View File
@@ -982,6 +982,7 @@ $string['sitepolicy_help'] = 'If you have a site policy that all registered user
$string['sitepolicyguest'] = 'Site policy URL for guests';
$string['sitepolicyguest_help'] = 'If you have a site policy that all guests must see and agree to before using this site, then specify the URL to it here, otherwise leave this field blank. This setting can contain any public URL. Note: access of not-logged-in users may be prevented with forcelogin setting.';
$string['sitesectionhelp'] = 'If selected, a topic section will be displayed on the site\'s front page.';
$string['sixtyfourbitswarning'] = 'It has been detected that your site is not using a 64-bit PHP version. It is recommended that you upgrade your site to ensure future compatibility.';
$string['slasharguments'] = 'Use slash arguments';
$string['slashargumentswarning'] = 'It is recommended that the use of slash arguments is enabled. In future it will be required. For more details, see the documentation <a href="https://docs.moodle.org/en/admin/environment/slasharguments">Using slash arguments</a>.';
$string['smartpix'] = 'Smart pix search';
@@ -1090,6 +1091,7 @@ $string['unsupporteddbtablerowformat'] = 'Your database has tables using Antelop
$string['unsupportedphpversion7'] = 'PHP version 7 is not supported.';
$string['unsupportedphpversion71'] = 'PHP version 7.1 is not supported.';
$string['unsupportedphpversion72'] = 'PHP version 7.2 is not supported.';
$string['unsupportedphpversion73'] = 'PHP version 7.3 is not supported.';
$string['unsuspenduser'] = 'Activate user account';
$string['updateaccounts'] = 'Update existing accounts';
$string['updatecomponent'] = 'Update component';
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
define(["core/ajax","jquery"],function(a,b){return{processResults:function(a,c){var d=[],e=0,f=String(b(a).data("exclude")).split(",");for(e=0;e<c.courses.length;e++)-1===f.indexOf(String(c.courses[e].id))&&d.push({value:c.courses[e].id,label:c.courses[e].displayname});return d},transport:function(c,d,e,f){var g=b(c),h=g.data("requiredcapabilities");h=""!==h.trim()?h.split(","):[];var i=g.data("limittoenrolled"),j=g.data("includefrontpage"),k=null;"undefined"==typeof d&&(d="");var l={criterianame:"search",criteriavalue:d,page:0,perpage:100,requiredcapabilities:h,limittoenrolled:i},m=[{methodname:"core_course_search_courses",args:l}];j&&m.push({methodname:"core_course_get_courses",args:{options:{ids:[j]}}}),k=a.call(m),b.when.apply(b.when,k).done(function(a,b){if(b&&1==b.length){var c=b.pop(),f=""===d||c.fullname.toUpperCase().indexOf(d.toUpperCase())>-1||c.shortname.toUpperCase().indexOf(d.toUpperCase())>-1;f&&a.courses.splice(0,0,c)}e(a)}).fail(f)}}});
define(["core/ajax","jquery"],function(a,b){return{processResults:function(a,c){var d=[],e=0,f=String(b(a).data("exclude")).split(",");for(e=0;e<c.courses.length;e++)f.indexOf(String(c.courses[e].id))===-1&&d.push({value:c.courses[e].id,label:c.courses[e].displayname});return d},transport:function(c,d,e,f){var g=b(c),h=g.data("requiredcapabilities");h=""!==h.trim()?h.split(","):[];var i=g.data("limittoenrolled"),j=g.data("includefrontpage"),k=null;"undefined"==typeof d&&(d="");var l={criterianame:"search",criteriavalue:d,page:0,perpage:100,requiredcapabilities:h,limittoenrolled:i},m=[{methodname:"core_course_search_courses",args:l}];j&&m.push({methodname:"core_course_get_courses",args:{options:{ids:[j]}}}),k=a.call(m),b.when.apply(b.when,k).done(function(a,b){if(b&&1==b.length){var c=b.pop(),f=""===d||c.fullname.toUpperCase().indexOf(d.toUpperCase())>-1||c.shortname.toUpperCase().indexOf(d.toUpperCase())>-1;f&&a.courses.splice(0,0,c)}e(a)}).fail(f)}}});
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/ajax","core/templates","core/notification","core/str","core/config","core/url"],function(a,b,c,d,e,f,g){return a("body").on("click keypress","[data-inplaceeditable] [data-inplaceeditablelink]",function(h){if("keypress"!==h.type||13===h.keyCode){h.stopImmediatePropagation(),h.preventDefault();var i=a(this),j=i.closest("[data-inplaceeditable]"),k=function(b){b.addClass("updating");var c=b.find("img.spinner");c.length?c.show():(c=a("<img/>").attr("src",g.imageUrl("i/loading_small")).addClass("spinner").addClass("smallicon"),b.append(c))},l=function(a){a.removeClass("updating"),a.find("img.spinner").hide()},m=function(e,f){k(e),b.call([{methodname:"core_update_inplace_editable",args:{itemid:e.attr("data-itemid"),component:e.attr("data-component"),itemtype:e.attr("data-itemtype"),value:f},done:function(b){var d=e.attr("data-value");c.render("core/inplace_editable",b).done(function(f,g){var h=a(f);c.replaceNode(e,h,g),h.find("[data-inplaceeditablelink]").focus(),h.trigger({type:"updated",ajaxreturn:b,oldvalue:d})})},fail:function(b){var c=a.Event("updatefailed",{exception:b,newvalue:f});l(e),e.trigger(c),c.isDefaultPrevented()||d.exception(b)}}],!0)},n=function(a){a.find("input").off(),a.find("select").off(),a.html(a.attr("data-oldcontent")),a.removeAttr("data-oldcontent"),a.removeClass("inplaceeditingon"),a.find("[data-inplaceeditablelink]").focus()},o=function(){a("span.inplaceeditable.inplaceeditingon").each(function(){n(a(this))})},p=function(b,c){var d,e=b;for(d=0;c>d;d++)e+=String(Math.floor(10*Math.random()));return 0===a("#"+e).length?e:p(b,c)},q=function(b){e.get_string("edittitleinstructions").done(function(c){var d=a('<span class="editinstructions">'+c+"</span>").attr("id",p("id_editinstructions_",20)),e=a('<input type="text"/>').attr("id",p("id_inplacevalue_",20)).attr("value",b.attr("data-value")).attr("aria-describedby",d.attr("id")).addClass("ignoredirty"),g=a('<label class="accesshide">'+j.attr("data-editlabel")+"</label>").attr("for",e.attr("id"));b.html("").append(d).append(g).append(e),e.focus(),e.select(),e.on("keyup keypress focusout",function(a){if(!f.behatsiterunning||"focusout"!==a.type){if("keypress"===a.type&&13===a.keyCode){var c=e.val();n(b),m(b,c)}("keyup"===a.type&&27===a.keyCode||"focusout"===a.type)&&n(b)}})})},r=function(a,b){n(a),m(a,b)},s=function(b,c){var d,e=a("<select></select>").attr("id",p("id_inplacevalue_",20)),g=a('<label class="accesshide">'+j.attr("data-editlabel")+"</label>").attr("for",e.attr("id"));for(d in c)e.append(a("<option>").attr("value",c[d].key).html(c[d].value));e.val(b.attr("data-value")),b.html("").append(g).append(e),e.focus(),e.select(),e.on("keyup change focusout",function(a){if(!f.behatsiterunning||"focusout"!==a.type){if("change"===a.type){var c=e.val();n(b),m(b,c)}("keyup"===a.type&&27===a.keyCode||"focusout"===a.type)&&n(b)}})},t=function(b){b.addClass("inplaceeditingon"),b.attr("data-oldcontent",b.html());var c=b.attr("data-type"),d=b.attr("data-options");"toggle"===c?r(b,d):"select"===c?s(b,a.parseJSON(d)):q(b)};o(),t(j)}}),{}});
define(["jquery","core/ajax","core/templates","core/notification","core/str","core/config","core/url"],function(a,b,c,d,e,f,g){return a("body").on("click keypress","[data-inplaceeditable] [data-inplaceeditablelink]",function(h){if("keypress"!==h.type||13===h.keyCode){h.stopImmediatePropagation(),h.preventDefault();var i=a(this),j=i.closest("[data-inplaceeditable]"),k=function(b){b.addClass("updating");var c=b.find("img.spinner");c.length?c.show():(c=a("<img/>").attr("src",g.imageUrl("i/loading_small")).addClass("spinner").addClass("smallicon"),b.append(c))},l=function(a){a.removeClass("updating"),a.find("img.spinner").hide()},m=function(e,f){k(e),b.call([{methodname:"core_update_inplace_editable",args:{itemid:e.attr("data-itemid"),component:e.attr("data-component"),itemtype:e.attr("data-itemtype"),value:f},done:function(b){var d=e.attr("data-value");c.render("core/inplace_editable",b).done(function(f,g){var h=a(f);c.replaceNode(e,h,g),h.find("[data-inplaceeditablelink]").focus(),h.trigger({type:"updated",ajaxreturn:b,oldvalue:d})})},fail:function(b){var c=a.Event("updatefailed",{exception:b,newvalue:f});l(e),e.trigger(c),c.isDefaultPrevented()||d.exception(b)}}],!0)},n=function(a){a.find("input").off(),a.find("select").off(),a.html(a.attr("data-oldcontent")),a.removeAttr("data-oldcontent"),a.removeClass("inplaceeditingon"),a.find("[data-inplaceeditablelink]").focus()},o=function(){a("span.inplaceeditable.inplaceeditingon").each(function(){n(a(this))})},p=function(b,c){var d,e=b;for(d=0;d<c;d++)e+=String(Math.floor(10*Math.random()));return 0===a("#"+e).length?e:p(b,c)},q=function(b){e.get_string("edittitleinstructions").done(function(c){var d=a('<span class="editinstructions">'+c+"</span>").attr("id",p("id_editinstructions_",20)),e=a('<input type="text"/>').attr("id",p("id_inplacevalue_",20)).attr("value",b.attr("data-value")).attr("aria-describedby",d.attr("id")).addClass("ignoredirty"),g=a('<label class="accesshide">'+j.attr("data-editlabel")+"</label>").attr("for",e.attr("id"));b.html("").append(d).append(g).append(e),e.focus(),e.select(),e.on("keyup keypress focusout",function(a){if(!f.behatsiterunning||"focusout"!==a.type){if("keypress"===a.type&&13===a.keyCode){var c=e.val();n(b),m(b,c)}("keyup"===a.type&&27===a.keyCode||"focusout"===a.type)&&n(b)}})})},r=function(a,b){n(a),m(a,b)},s=function(b,c){var d,e=a("<select></select>").attr("id",p("id_inplacevalue_",20)),g=a('<label class="accesshide">'+j.attr("data-editlabel")+"</label>").attr("for",e.attr("id"));for(d in c)e.append(a("<option>").attr("value",c[d].key).html(c[d].value));e.val(b.attr("data-value")),b.html("").append(g).append(e),e.focus(),e.select(),e.on("keyup change focusout",function(a){if(!f.behatsiterunning||"focusout"!==a.type){if("change"===a.type){var c=e.val();n(b),m(b,c)}("keyup"===a.type&&27===a.keyCode||"focusout"===a.type)&&n(b)}})},t=function(b){b.addClass("inplaceeditingon"),b.attr("data-oldcontent",b.html());var c=b.attr("data-type"),d=b.attr("data-options");"toggle"===c?r(b,d):"select"===c?s(b,a.parseJSON(d)):q(b)};o(),t(j)}}),{}});
+1 -1
View File
@@ -1 +1 @@
define(["core/config"],function(a){var b=!1,c="",d="",e=null,f=function(){if(-1==a.jsrev)return!1;if("undefined"==typeof window.localStorage)return!1;var b="test";try{return e=window.localStorage,null===e?!1:(e.setItem(b,"1"),e.removeItem(b),!0)}catch(c){return!1}},g=function(a){return c+a},h=function(){var b=e.getItem(d);if(null===b)return void e.setItem(d,a.jsrev);var c=a.jsrev;c!=b&&(e.clear(),e.setItem(d,a.jsrev))},i=function(a){var b,c,d,e=0;if(0===a.length)return e;for(b=0,d=a.length;d>b;b++)c=a.charCodeAt(b),e=(e<<5)-e+c,e|=0;return e},j=function(){b=f();var e=a.wwwroot+"/"+a.jsrev,g=i(e);c=g+"/",e=a.wwwroot+"/",g=i(e),d=g+"/jsrev"};return j(),{get:function(a){return b?(h(),a=g(a),e.getItem(a)):!1},set:function(a,c){if(!b)return!1;h(),a=g(a);try{e.setItem(a,c)}catch(d){return!1}return!0}}});
define(["core/config"],function(a){var b=!1,c="",d="",e=null,f=function(){if(a.jsrev==-1)return!1;if("undefined"==typeof window.localStorage)return!1;var b="test";try{return e=window.localStorage,null!==e&&(e.setItem(b,"1"),e.removeItem(b),!0)}catch(c){return!1}},g=function(a){return c+a},h=function(){var b=e.getItem(d);if(null===b)return void e.setItem(d,a.jsrev);var c=a.jsrev;c!=b&&(e.clear(),e.setItem(d,a.jsrev))},i=function(a){var b,c,d,e=0;if(0===a.length)return e;for(b=0,d=a.length;b<d;b++)c=a.charCodeAt(b),e=(e<<5)-e+c,e|=0;return e},j=function(){b=f();var e=a.wwwroot+"/"+a.jsrev,g=i(e);c=g+"/",e=a.wwwroot+"/",g=i(e),d=g+"/jsrev"};return j(),{get:function(a){return!!b&&(h(),a=g(a),e.getItem(a))},set:function(a,c){if(!b)return!1;h(),a=g(a);try{e.setItem(a,c)}catch(d){return!1}return!0}}});
+1 -1
View File
@@ -1 +1 @@
!function(a,b){"use strict";"object"==typeof module&&module.exports&&"function"==typeof require?module.exports=b():"function"==typeof define&&"object"==typeof define.amd?define(b):a.log=b()}(this,function(){"use strict";function a(a){return typeof console===h?!1:void 0!==console[a]?b(console,a):void 0!==console.log?b(console,"log"):g}function b(a,b){var c=a[b];if("function"==typeof c.bind)return c.bind(a);try{return Function.prototype.bind.call(c,a)}catch(d){return function(){return Function.prototype.apply.apply(c,[a,arguments])}}}function c(a,b,c){return function(){typeof console!==h&&(d.call(this,b,c),this[a].apply(this,arguments))}}function d(a,b){for(var c=0;c<i.length;c++){var d=i[c];this[d]=a>c?g:this.methodFactory(d,a,b)}}function e(b,d,e){return a(b)||c.apply(this,arguments)}function f(a,b,c){function f(a){var b=(i[a]||"silent").toUpperCase();try{return void(window.localStorage[l]=b)}catch(c){}try{window.document.cookie=encodeURIComponent(l)+"="+b+";"}catch(c){}}function g(){var a;try{a=window.localStorage[l]}catch(b){}if(typeof a===h)try{var c=window.document.cookie,d=c.indexOf(encodeURIComponent(l)+"=");d&&(a=/^([^;]+)/.exec(c.slice(d))[1])}catch(b){}return void 0===k.levels[a]&&(a=void 0),a}var j,k=this,l="loglevel";a&&(l+=":"+a),k.levels={TRACE:0,DEBUG:1,INFO:2,WARN:3,ERROR:4,SILENT:5},k.methodFactory=c||e,k.getLevel=function(){return j},k.setLevel=function(b,c){if("string"==typeof b&&void 0!==k.levels[b.toUpperCase()]&&(b=k.levels[b.toUpperCase()]),!("number"==typeof b&&b>=0&&b<=k.levels.SILENT))throw"log.setLevel() called with invalid level: "+b;return j=b,c!==!1&&f(b),d.call(k,b,a),typeof console===h&&b<k.levels.SILENT?"No console available for logging":void 0},k.setDefaultLevel=function(a){g()||k.setLevel(a,!1)},k.enableAll=function(a){k.setLevel(k.levels.TRACE,a)},k.disableAll=function(a){k.setLevel(k.levels.SILENT,a)};var m=g();null==m&&(m=null==b?"WARN":b),k.setLevel(m,!1)}var g=function(){},h="undefined",i=["trace","debug","info","warn","error"],j=new f,k={};j.getLogger=function(a){if("string"!=typeof a||""===a)throw new TypeError("You must supply a name when creating a logger.");var b=k[a];return b||(b=k[a]=new f(a,j.getLevel(),j.methodFactory)),b};var l=typeof window!==h?window.log:void 0;return j.noConflict=function(){return typeof window!==h&&window.log===j&&(window.log=l),j},j});
!function(a,b){"use strict";"object"==typeof module&&module.exports&&"function"==typeof require?module.exports=b():"function"==typeof define&&"object"==typeof define.amd?define(b):a.log=b()}(this,function(){"use strict";function a(a){return typeof console!==h&&(void 0!==console[a]?b(console,a):void 0!==console.log?b(console,"log"):g)}function b(a,b){var c=a[b];if("function"==typeof c.bind)return c.bind(a);try{return Function.prototype.bind.call(c,a)}catch(d){return function(){return Function.prototype.apply.apply(c,[a,arguments])}}}function c(a,b,c){return function(){typeof console!==h&&(d.call(this,b,c),this[a].apply(this,arguments))}}function d(a,b){for(var c=0;c<i.length;c++){var d=i[c];this[d]=c<a?g:this.methodFactory(d,a,b)}}function e(b,d,e){return a(b)||c.apply(this,arguments)}function f(a,b,c){function f(a){var b=(i[a]||"silent").toUpperCase();try{return void(window.localStorage[l]=b)}catch(c){}try{window.document.cookie=encodeURIComponent(l)+"="+b+";"}catch(c){}}function g(){var a;try{a=window.localStorage[l]}catch(b){}if(typeof a===h)try{var c=window.document.cookie,d=c.indexOf(encodeURIComponent(l)+"=");d&&(a=/^([^;]+)/.exec(c.slice(d))[1])}catch(b){}return void 0===k.levels[a]&&(a=void 0),a}var j,k=this,l="loglevel";a&&(l+=":"+a),k.levels={TRACE:0,DEBUG:1,INFO:2,WARN:3,ERROR:4,SILENT:5},k.methodFactory=c||e,k.getLevel=function(){return j},k.setLevel=function(b,c){if("string"==typeof b&&void 0!==k.levels[b.toUpperCase()]&&(b=k.levels[b.toUpperCase()]),!("number"==typeof b&&b>=0&&b<=k.levels.SILENT))throw"log.setLevel() called with invalid level: "+b;if(j=b,c!==!1&&f(b),d.call(k,b,a),typeof console===h&&b<k.levels.SILENT)return"No console available for logging"},k.setDefaultLevel=function(a){g()||k.setLevel(a,!1)},k.enableAll=function(a){k.setLevel(k.levels.TRACE,a)},k.disableAll=function(a){k.setLevel(k.levels.SILENT,a)};var m=g();null==m&&(m=null==b?"WARN":b),k.setLevel(m,!1)}var g=function(){},h="undefined",i=["trace","debug","info","warn","error"],j=new f,k={};j.getLogger=function(a){if("string"!=typeof a||""===a)throw new TypeError("You must supply a name when creating a logger.");var b=k[a];return b||(b=k[a]=new f(a,j.getLevel(),j.methodFactory)),b};var l=typeof window!==h?window.log:void 0;return j.noConflict=function(){return typeof window!==h&&window.log===j&&(window.log=l),j},j});
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
define(["jquery"],function(a){var b=null,c=function(a){b.hasClass("expanded")?e():d(a)},d=function(c){var d=a(document).width();if("keydown"!==c.type||13===c.keyCode||32===c.keyCode)return 767>=d&&("click"===c.type||"keydown"===c.type)?void f():void(767>=d||("keydown"===c.type&&c.preventDefault(),b.addClass("expanded"),b.find("form").addClass("expanded"),b.find("input").focus()))},e=function(){b.removeClass("expanded"),b.find("form").removeClass("expanded")},f=function(){b.find("form").submit()};return{init:function(d){b=a("#"+d),b.on("click mouseover keydown","div",c)}}});
define(["jquery"],function(a){var b=null,c=function(a){b.hasClass("expanded")?e():d(a)},d=function(c){var d=a(document).width();if("keydown"!==c.type||13===c.keyCode||32===c.keyCode)return d<=767&&("click"===c.type||"keydown"===c.type)?void f():void(d<=767||("keydown"===c.type&&c.preventDefault(),b.addClass("expanded"),b.find("form").addClass("expanded"),b.find("input").focus()))},e=function(){b.removeClass("expanded"),b.find("form").removeClass("expanded")},f=function(){b.find("form").submit()};return{init:function(d){b=a("#"+d),b.on("click mouseover keydown","div",c)}}});
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
define(["core/mustache","jquery","core/ajax","core/str","core/notification","core/url","core/log","core/config","core/localstorage","core/event","core/yui","core/log"],function(a,b,c,d,e,f,g,h,i,j,k,l){var m=0,n={},o={},p=function(){this.requiredStrings=[],this.requiredJS=[],this.currentThemeName=""};p.prototype.requiredStrings=null,p.prototype.requiredJS=null,p.prototype.currentThemeName="",p.prototype.getTemplate=function(a){var d=a.split("/"),e=d.shift(),f=d.shift(),g=this.currentThemeName+"/"+a;if(g in o)return o[g];var h=i.get("core_template/"+g);if(h)return n[g]=h,o[g]=b.Deferred().resolve(h).promise(),o[g];var j=c.call([{methodname:"core_output_load_template",args:{component:e,template:f,themename:this.currentThemeName}}],!0,!1);return o[g]=j[0].then(function(a){return n[g]=a,i.set("core_template/"+g,a),a}),o[g]},p.prototype.partialHelper=function(a){var b=this.currentThemeName+"/"+a;return b in n||e.exception(new Error("Failed to pre-fetch the template: "+a)),n[b]},p.prototype.pixHelper=function(b,c,d){var e,g=c.split(","),h="",i="",j="";g.length>0&&(h=g.shift().trim()),g.length>0&&(i=g.shift().trim()),g.length>0&&(j=g.join(",").trim());var k=f.imageUrl(h,i),l={attributes:[{name:"src",value:k},{name:"alt",value:d(j)},{name:"title",value:d(j)},{name:"class",value:"smallicon"}]},m=this.currentThemeName+"/core/pix_icon",o=n[m];return e=a.render(o,l,this.partialHelper.bind(this)),e.trim()},p.prototype.jsHelper=function(a,b,c){return this.requiredJS.push(c(b,a)),""},p.prototype.stringHelper=function(a,b,c){var d=b.split(","),e="",f="",g="";d.length>0&&(e=d.shift().trim()),d.length>0&&(f=d.shift().trim()),d.length>0&&(g=d.join(",").trim()),""!==g&&(g=c(g,a)),0===g.indexOf("{")&&0!==g.indexOf("{{")&&(g=JSON.parse(g));var h=this.requiredStrings.length;return this.requiredStrings.push({key:e,component:f,param:g}),"[[_s"+h+"]]"},p.prototype.quoteHelper=function(a,b,c){var d=c(b.trim(),a);return d=d.replace('"','\\"').replace(/([\{\}]{2,3})/g,"{{=<% %>=}}$1<%={{ }}=%>"),'"'+d+'"'},p.prototype.addHelpers=function(a,b){this.currentThemeName=b,this.requiredStrings=[],this.requiredJS=[],a.uniqid=m++,a.str=function(){return this.stringHelper.bind(this,a)}.bind(this),a.pix=function(){return this.pixHelper.bind(this,a)}.bind(this),a.js=function(){return this.jsHelper.bind(this,a)}.bind(this),a.quote=function(){return this.quoteHelper.bind(this,a)}.bind(this),a.globals={config:h},a.currentTheme=b},p.prototype.getJS=function(a){var b="";return this.requiredJS.length>0&&(b=this.requiredJS.join(";\n")),this.treatStringsInContent(b,a)},p.prototype.treatStringsInContent=function(a,b){var c,d,e,f,g,h,i=/\[\[_s\d+\]\]/;do{for(c="",d=a.search(i);d>-1;){c+=a.substring(0,d),a=a.substr(d),e="",f=4,g=a.substr(f,1);do e+=g,f++,g=a.substr(f,1);while("]"!=g);h=b[parseInt(e,10)],"undefined"==typeof h&&(l.debug("Could not find string for pattern [[_s"+e+"]]."),h=""),c+=h,a=a.substr(6+e.length),d=a.search(i)}a=c+a,d=a.search(i)}while(d>-1);return a},p.prototype.doRender=function(c,e,f){return this.currentThemeName=f,this.getTemplate("core/pix_icon").then(function(){this.addHelpers(e,f);var g=a.render(c,e,this.partialHelper.bind(this));return this.requiredStrings.length>0?d.get_strings(this.requiredStrings).then(function(a){return g=this.treatStringsInContent(g,a),b.Deferred().resolve(g,this.getJS(a)).promise()}.bind(this)):b.Deferred().resolve(g.trim(),this.getJS([])).promise()}.bind(this))};var q=function(a){if(""!==a.trim()){var c=b("<script>").attr("type","text/javascript").html(a);b("head").append(c)}},r=function(a,c,d,e){var f=b(a);if(f.length){var g=b(c),h=null;e?(h=new k.NodeList(f.children().get()),h.destroy(!0),f.empty(),f.append(g)):(h=new k.NodeList(f.get()),h.destroy(!0),f.replaceWith(g)),q(d),j.notifyFilterContentUpdated(g)}};return p.prototype.scanForPartials=function(b){var c=a.parse(b),d=[],e=function(a,b){var c,d;for(c=0;c<a.length;c++)d=a[c],(">"==d[0]||"<"==d[0])&&b.push(d[1]),d.length>4&&e(d[4],b)};return e(c,d),d},p.prototype.cachePartials=function(a){return this.getTemplate(a).then(function(a){var c,d=this.scanForPartials(a),e=[];for(c=0;c<d.length;c++){var f=this.currentThemeName+"/"+d[c];f in o?e.push(o[f]):e.push(this.cachePartials(d[c]))}return b.when.apply(b,e).then(function(){return a})}.bind(this))},p.prototype.render=function(a,b,c){return"undefined"==typeof c&&(c=h.theme),this.currentThemeName=c,this.cachePartials(a).then(function(a){return this.doRender(a,b,c)}.bind(this))},{render:function(a,b,c){var d=new p;return d.render(a,b,c)},runTemplateJS:q,replaceNodeContents:function(a,b,c){return r(a,b,c,!0)},replaceNode:function(a,b,c){return r(a,b,c,!1)}}});
define(["core/mustache","jquery","core/ajax","core/str","core/notification","core/url","core/log","core/config","core/localstorage","core/event","core/yui","core/log"],function(a,b,c,d,e,f,g,h,i,j,k,l){var m=0,n={},o={},p=function(){this.requiredStrings=[],this.requiredJS=[],this.currentThemeName=""};p.prototype.requiredStrings=null,p.prototype.requiredJS=null,p.prototype.currentThemeName="",p.prototype.getTemplate=function(a){var d=a.split("/"),e=d.shift(),f=d.shift(),g=this.currentThemeName+"/"+a;if(g in o)return o[g];var h=i.get("core_template/"+g);if(h)return n[g]=h,o[g]=b.Deferred().resolve(h).promise(),o[g];var j=c.call([{methodname:"core_output_load_template",args:{component:e,template:f,themename:this.currentThemeName}}],!0,!1);return o[g]=j[0].then(function(a){return n[g]=a,i.set("core_template/"+g,a),a}),o[g]},p.prototype.partialHelper=function(a){var b=this.currentThemeName+"/"+a;return b in n||e.exception(new Error("Failed to pre-fetch the template: "+a)),n[b]},p.prototype.pixHelper=function(b,c,d){var e,g=c.split(","),h="",i="",j="";g.length>0&&(h=g.shift().trim()),g.length>0&&(i=g.shift().trim()),g.length>0&&(j=g.join(",").trim());var k=f.imageUrl(h,i),l={attributes:[{name:"src",value:k},{name:"alt",value:d(j)},{name:"title",value:d(j)},{name:"class",value:"smallicon"}]},m=this.currentThemeName+"/core/pix_icon",o=n[m];return e=a.render(o,l,this.partialHelper.bind(this)),e.trim()},p.prototype.jsHelper=function(a,b,c){return this.requiredJS.push(c(b,a)),""},p.prototype.stringHelper=function(a,b,c){var d=b.split(","),e="",f="",g="";d.length>0&&(e=d.shift().trim()),d.length>0&&(f=d.shift().trim()),d.length>0&&(g=d.join(",").trim()),""!==g&&(g=c(g,a)),0===g.indexOf("{")&&0!==g.indexOf("{{")&&(g=JSON.parse(g));var h=this.requiredStrings.length;return this.requiredStrings.push({key:e,component:f,param:g}),"[[_s"+h+"]]"},p.prototype.quoteHelper=function(a,b,c){var d=c(b.trim(),a);return d=d.replace('"','\\"').replace(/([\{\}]{2,3})/g,"{{=<% %>=}}$1<%={{ }}=%>"),'"'+d+'"'},p.prototype.addHelpers=function(a,b){this.currentThemeName=b,this.requiredStrings=[],this.requiredJS=[],a.uniqid=m++,a.str=function(){return this.stringHelper.bind(this,a)}.bind(this),a.pix=function(){return this.pixHelper.bind(this,a)}.bind(this),a.js=function(){return this.jsHelper.bind(this,a)}.bind(this),a.quote=function(){return this.quoteHelper.bind(this,a)}.bind(this),a.globals={config:h},a.currentTheme=b},p.prototype.getJS=function(a){var b="";return this.requiredJS.length>0&&(b=this.requiredJS.join(";\n")),this.treatStringsInContent(b,a)},p.prototype.treatStringsInContent=function(a,b){var c,d,e,f,g,h,i=/\[\[_s\d+\]\]/;do{for(c="",d=a.search(i);d>-1;){c+=a.substring(0,d),a=a.substr(d),e="",f=4,g=a.substr(f,1);do e+=g,f++,g=a.substr(f,1);while("]"!=g);h=b[parseInt(e,10)],"undefined"==typeof h&&(l.debug("Could not find string for pattern [[_s"+e+"]]."),h=""),c+=h,a=a.substr(6+e.length),d=a.search(i)}a=c+a,d=a.search(i)}while(d>-1);return a},p.prototype.doRender=function(c,e,f){return this.currentThemeName=f,this.getTemplate("core/pix_icon").then(function(){this.addHelpers(e,f);var g=a.render(c,e,this.partialHelper.bind(this));return this.requiredStrings.length>0?d.get_strings(this.requiredStrings).then(function(a){return g=this.treatStringsInContent(g,a),b.Deferred().resolve(g,this.getJS(a)).promise()}.bind(this)):b.Deferred().resolve(g.trim(),this.getJS([])).promise()}.bind(this))};var q=function(a){if(""!==a.trim()){var c=b("<script>").attr("type","text/javascript").html(a);b("head").append(c)}},r=function(a,c,d,e){var f=b(a);if(f.length){var g=b(c),h=null;e?(h=new k.NodeList(f.children().get()),h.destroy(!0),f.empty(),f.append(g)):(h=new k.NodeList(f.get()),h.destroy(!0),f.replaceWith(g)),q(d),j.notifyFilterContentUpdated(g)}};return p.prototype.scanForPartials=function(b){var c=a.parse(b),d=[],e=function(a,b){var c,d;for(c=0;c<a.length;c++)d=a[c],">"!=d[0]&&"<"!=d[0]||b.push(d[1]),d.length>4&&e(d[4],b)};return e(c,d),d},p.prototype.cachePartials=function(a){return this.getTemplate(a).then(function(a){var c,d=this.scanForPartials(a),e=[];for(c=0;c<d.length;c++){var f=this.currentThemeName+"/"+d[c];f in o?e.push(o[f]):e.push(this.cachePartials(d[c]))}return b.when.apply(b,e).then(function(){return a})}.bind(this))},p.prototype.render=function(a,b,c){return"undefined"==typeof c&&(c=h.theme),this.currentThemeName=c,this.cachePartials(a).then(function(a){return this.doRender(a,b,c)}.bind(this))},{render:function(a,b,c){var d=new p;return d.render(a,b,c)},runTemplateJS:q,replaceNodeContents:function(a,b,c){return r(a,b,c,!0)},replaceNode:function(a,b,c){return r(a,b,c,!1)}}});
+1 -1
View File
File diff suppressed because one or more lines are too long
+5
View File
@@ -63,6 +63,11 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str'
// Set cell 'time modified' to 'now' when any of the element is updated in this row.
$('body').on('updated', '[data-inplaceeditable]', function(e) {
str.get_string('selecttag', 'core_tag', e.ajaxreturn.value)
.then(function(s) {
return $('label[for="tagselect' + e.ajaxreturn.itemid + '"]').html(s);
})
.fail(notification.exception);
str.get_string('now').done(function(s) {
$(e.target).closest('tr').find('td.col-timemodified').html(s);
});
+101
View File
@@ -46,6 +46,9 @@ class manager {
/** @var bool $sessionactive Is the session active? */
protected static $sessionactive = null;
/** @var string $logintokenkey Key used to get and store request protection for login form. */
protected static $logintokenkey = 'core_auth_login';
/**
* Start user session.
*
@@ -906,4 +909,102 @@ class manager {
)));
}
/**
* Generate a new login token and store it in the session.
*
* @return array The current login state.
*/
private static function create_login_token() {
global $SESSION;
$state = [
'token' => random_string(32),
'created' => time() // Server time - not user time.
];
if (!isset($SESSION->logintoken)) {
$SESSION->logintoken = [];
}
// Overwrite any previous values.
$SESSION->logintoken[self::$logintokenkey] = $state;
return $state;
}
/**
* Get the current login token or generate a new one.
*
* All login forms generated from Moodle must include a login token
* named "logintoken" with the value being the result of this function.
* Logins will be rejected if they do not include this token as well as
* the username and password fields.
*
* @return string The current login token.
*/
public static function get_login_token() {
global $CFG, $SESSION;
$state = false;
if (!isset($SESSION->logintoken)) {
$SESSION->logintoken = [];
}
if (array_key_exists(self::$logintokenkey, $SESSION->logintoken)) {
$state = $SESSION->logintoken[self::$logintokenkey];
}
if (empty($state)) {
$state = self::create_login_token();
}
// Check token lifespan.
if ($state['created'] < (time() - $CFG->sessiontimeout)) {
$state = self::create_login_token();
}
// Return the current session login token.
if (array_key_exists('token', $state)) {
return $state['token'];
} else {
return false;
}
}
/**
* Check the submitted value against the stored login token.
*
* @param mixed $token The value submitted in the login form that we are validating.
* If false is passed for the token, this function will always return true.
* @return boolean If the submitted token is valid.
*/
public static function validate_login_token($token = false) {
global $CFG;
if (!empty($CFG->alternateloginurl) || !empty($CFG->disablelogintoken)) {
// An external login page cannot generate the login token we need to protect CSRF on
// login requests.
// Other custom login workflows may skip this check by setting disablelogintoken in config.
return true;
}
if ($token === false) {
// authenticate_user_login is a core function was extended to validate tokens.
// For existing uses other than the login form it does not
// validate that a token was generated.
// Some uses that do not validate the token are login/token.php,
// or an auth plugin like auth/ldap/auth.php.
return true;
}
$currenttoken = self::get_login_token();
// We need to clean the login token so the old one is not valid again.
self::create_login_token();
if ($currenttoken !== $token) {
// Fail the login.
return false;
}
return true;
}
}
+3 -2
View File
@@ -355,7 +355,8 @@ class redis extends handler {
}
try {
return $this->connection->exists($sid);
$sessionexists = $this->connection->exists($sid);
return !empty($sessionexists);
} catch (RedisException $e) {
return false;
}
@@ -389,4 +390,4 @@ class redis extends handler {
$this->handler_destroy($sid);
}
}
}
+1
View File
@@ -1069,6 +1069,7 @@ $capabilities = array(
),
'moodle/course:managegroups' => array(
'riskbitmask' => RISK_XSS,
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
+11
View File
@@ -1604,3 +1604,14 @@ function restrict_php_version_71(&$result) {
function restrict_php_version_72(&$result) {
return restrict_php_version($result, '7.2');
}
/**
* Check if the current PHP version is greater than or equal to
* PHP version 7.3.
*
* @param object $result an environment_results instance
* @return bool result of version check
*/
function restrict_php_version_73(&$result) {
return restrict_php_version($result, '7.3');
}
+21 -1
View File
@@ -2441,6 +2441,9 @@ function dayofweek($day, $month, $year) {
/**
* Returns full login url.
*
* Any form submissions for authentication to this URL must include username,
* password as well as a logintoken generated by \core\session\manager::get_login_token().
*
* @return string login url
*/
function get_login_url() {
@@ -2962,6 +2965,10 @@ function require_course_login($courseorid, $autologinguest = true, $cm = null, $
// Always login for hidden activities.
require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect);
} else if (isloggedin() && !isguestuser()) {
// User is already logged in. Make sure the login is complete (user is fully setup, policies agreed).
require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect);
} else if ($issite) {
// Login for SITE not required.
// We still need to instatiate PAGE vars properly so that things that rely on it like navigation function correctly.
@@ -4137,9 +4144,10 @@ function guest_user() {
* @param string $password User's password
* @param bool $ignorelockout useful when guessing is prevented by other mechanism such as captcha or SSO
* @param int $failurereason login failure reason, can be used in renderers (it may disclose if account exists)
* @param mixed logintoken If this is set to a string it is validated against the login token for the session.
* @return stdClass|false A {@link $USER} object or false if error
*/
function authenticate_user_login($username, $password, $ignorelockout=false, &$failurereason=null) {
function authenticate_user_login($username, $password, $ignorelockout=false, &$failurereason=null, $logintoken=false) {
global $CFG, $DB;
require_once("$CFG->libdir/authlib.php");
@@ -4161,6 +4169,18 @@ function authenticate_user_login($username, $password, $ignorelockout=false, &$f
}
}
// Make sure this request came from the login form.
if (!\core\session\manager::validate_login_token($logintoken)) {
$failurereason = AUTH_LOGIN_FAILED;
// Trigger login failed event.
$event = \core\event\user_login_failed::create(array('userid' => $user->id,
'other' => array('username' => $username, 'reason' => $failurereason)));
$event->trigger();
error_log('[client '.getremoteaddr()."] $CFG->wwwroot Invalid Login Token: $username ".$_SERVER['HTTP_USER_AGENT']);
return false;
}
$authsenabled = get_enabled_auth_plugins();
if ($user) {
+12 -2
View File
@@ -21,6 +21,10 @@
require_once('PEAR.php');
require_once('HTML/Common.php');
/**
* Static utility methods.
*/
require_once('HTML/QuickForm/utils.php');
$GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'] =
array(
@@ -824,9 +828,15 @@ class HTML_QuickForm extends HTML_Common {
} elseif (false !== ($pos = strpos($elementName, '['))) {
$base = substr($elementName, 0, $pos);
$idx = "['" . str_replace(array(']', '['), array('', "']['"), substr($elementName, $pos + 1, -1)) . "']";
$keys = str_replace(
array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
substr($elementName, $pos + 1, -1)
);
$idx = "['" . $keys . "']";
$keyArray = explode("']['", $keys);
if (isset($this->_submitValues[$base])) {
$value = eval("return (isset(\$this->_submitValues['{$base}']{$idx})) ? \$this->_submitValues['{$base}']{$idx} : null;");
$value = HTML_QuickForm_utils::recursiveValue($this->_submitValues[$base], $keyArray, NULL);
}
if ((is_array($value) || null === $value) && isset($this->_submitFiles[$base])) {
+16 -6
View File
@@ -20,6 +20,10 @@
// $Id$
require_once('HTML/Common.php');
/**
* Static utility methods.
*/
require_once('HTML/QuickForm/utils.php');
/**
* Base class for form elements
@@ -351,8 +355,12 @@ class HTML_QuickForm_element extends HTML_Common
if (isset($values[$elementName])) {
return $values[$elementName];
} elseif (strpos($elementName, '[')) {
$myVar = "['" . str_replace(array(']', '['), array('', "']['"), $elementName) . "']";
return eval("return (isset(\$values$myVar)) ? \$values$myVar : null;");
$keys = str_replace(
array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
$elementName
);
$arrayKeys = explode("']['", $keys);
return HTML_QuickForm_utils::recursiveValue($values, $arrayKeys);
} else {
return null;
}
@@ -483,10 +491,12 @@ class HTML_QuickForm_element extends HTML_Common
if (!strpos($name, '[')) {
return array($name => $value);
} else {
$valueAry = array();
$myIndex = "['" . str_replace(array(']', '['), array('', "']['"), $name) . "']";
eval("\$valueAry$myIndex = \$value;");
return $valueAry;
$keys = str_replace(
array('\\', '\'', ']', '['), array('\\\\', '\\\'', '', "']['"),
$name
);
$keysArray = explode("']['", $keys);
return HTML_QuickForm_utils::recursiveBuild($keysArray, $value);
}
}
}
+17 -10
View File
@@ -22,6 +22,10 @@
require_once('HTML/QuickForm/group.php');
require_once('HTML/QuickForm/select.php');
/**
* Static utility methods.
*/
require_once 'HTML/QuickForm/utils.php';
/**
* Class to dynamically create two or more HTML Select elements
@@ -233,16 +237,19 @@ class HTML_QuickForm_hierselect extends HTML_QuickForm_group
*/
function _setOptions()
{
$toLoad = '';
$arrayKeys = [];
foreach (array_keys($this->_elements) AS $key) {
$array = eval("return isset(\$this->_options[{$key}]{$toLoad})? \$this->_options[{$key}]{$toLoad}: null;");
if (is_array($array)) {
$select =& $this->_elements[$key];
$select->_options = array();
$select->loadArray($array);
$value = is_array($v = $select->getValue()) ? $v[0] : key($array);
$toLoad .= '[\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $value) . '\']';
if (isset($this->_options[$key])) {
if ((empty($arrayKeys)) || HTML_QuickForm_utils::recursiveIsset($this->_options[$key], $arrayKeys)) {
$array = empty($arrayKeys) ? $this->_options[$key] : HTML_QuickForm_utils::recursiveValue($this->_options[$key], $arrayKeys);
if (is_array($array)) {
$select =& $this->_elements[$key];
$select->_options = array();
$select->loadArray($array);
$value = is_array($v = $select->getValue()) ? $v[0] : key($array);
$arrayKeys[] = $value;
}
}
}
}
} // end func _setOptions
@@ -585,4 +592,4 @@ JAVASCRIPT;
// }}}
} // end class HTML_QuickForm_hierselect
?>
?>
+159
View File
@@ -0,0 +1,159 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* utility functions
*
* PHP versions 4 and 5
*
* LICENSE: This source file is subject to version 3.01 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_01.txt If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category HTML
* @package HTML_QuickForm
* @author Chuck Burgess <ashnazg@php.net>
* @copyright 2001-2018 The PHP Group
* @license http://www.php.net/license/3_01.txt PHP License 3.01
* @version CVS: $Id$
* @link http://pear.php.net/package/HTML_QuickForm
*/
/**
* Provides a collection of static methods for array manipulation.
*
* (courtesy of CiviCRM project (https://civicrm.org/)
*
* @category HTML
* @package HTML_QuickForm
* @author Chuck Burgess <ashnazg@php.net>
* @version Release: @package_version@
* @since 3.2
*/
class HTML_QuickForm_utils
{
/**
* Get a single value from an array-tree.
*
* @param array $values Ex: ['foo' => ['bar' => 123]].
* @param array $path Ex: ['foo', 'bar'].
* @param mixed $default
* @return mixed Ex 123.
*
* @access public
* @static
*/
static function pathGet($values, $path, $default = NULL) {
foreach ($path as $key) {
if (!is_array($values) || !isset($values[$key])) {
return $default;
}
$values = $values[$key];
}
return $values;
}
/**
* Check if a key isset which may be several layers deep.
*
* This is a helper for when the calling function does not know how many layers deep
* the path array is so cannot easily check.
*
* @param array $values
* @param array $path
* @return bool
*
* @access public
* @static
*/
static function pathIsset($values, $path) {
foreach ($path as $key) {
if (!is_array($values) || !isset($values[$key])) {
return FALSE;
}
$values = $values[$key];
}
return TRUE;
}
/**
* Set a single value in an array tree.
*
* @param array $values Ex: ['foo' => ['bar' => 123]].
* @param array $pathParts Ex: ['foo', 'bar'].
* @param mixed $value Ex: 456.
* @return void
*
* @access public
* @static
*/
static function pathSet(&$values, $pathParts, $value) {
$r = &$values;
$last = array_pop($pathParts);
foreach ($pathParts as $part) {
if (!isset($r[$part])) {
$r[$part] = array();
}
$r = &$r[$part];
}
$r[$last] = $value;
}
/**
* Check if a key isset which may be several layers deep.
*
* This is a helper for when the calling function does not know how many layers deep the
* path array is so cannot easily check.
*
* @param array $array
* @param array $path
* @return bool
*
* @access public
* @static
*/
static function recursiveIsset($array, $path) {
return self::pathIsset($array, $path);
}
/**
* Check if a key isset which may be several layers deep.
*
* This is a helper for when the calling function does not know how many layers deep the
* path array is so cannot easily check.
*
* @param array $array
* @param array $path An array of keys,
* e.g [0, 'bob', 8] where we want to check if $array[0]['bob'][8]
* @param mixed $default Value to return if not found.
* @return bool
*
* @access public
* @static
*/
static function recursiveValue($array, $path, $default = NULL) {
return self::pathGet($array, $path, $default);
}
/**
* Append the value to the array using the key provided.
*
* e.g if value is 'llama' & path is [0, 'email', 'location'] result will be
* [0 => ['email' => ['location' => 'llama']]
*
* @param $path
* @param $value
* @param array $source
* @return array
*
* @access public
* @static
*/
static function recursiveBuild($path, $value, $source = array()) {
self::pathSet($source, $path, $value);
return $source;
}
}
?>
+3 -3
View File
@@ -117,9 +117,9 @@ class portfolio_exporter {
* @param portfolio_caller_base $caller portfolio caller (passed by reference)
* @param string $callercomponent the name of the callercomponent
*/
public function __construct(&$instance, &$caller, $callercomponent) {
$this->instance =& $instance;
$this->caller =& $caller;
public function __construct($instance, portfolio_caller_base $caller, $callercomponent) {
$this->instance = $instance;
$this->caller = $caller;
if ($instance) {
$this->instancefile = 'portfolio/' . $instance->get('plugin') . '/lib.php';
$this->instance->set('exporter', $this);
+5 -2
View File
@@ -1357,8 +1357,11 @@ function portfolio_include_callback_file($component, $class = null) {
throw new portfolio_button_exception('nocallbackfile', 'portfolio', '', $component);
}
if (!is_null($class) && !class_exists($class)) {
throw new portfolio_button_exception('nocallbackclass', 'portfolio', '', $class);
if (!is_null($class)) {
// If class is specified, check it exists and extends portfolio_caller_base.
if (!class_exists($class) || !is_subclass_of($class, 'portfolio_caller_base')) {
throw new portfolio_button_exception('nocallbackclass', 'portfolio', '', $class);
}
}
}
+53
View File
@@ -200,6 +200,59 @@ class core_authlib_testcase extends advanced_testcase {
$this->assertSame($eventdata['other']['reason'], AUTH_LOGIN_FAILED);
$this->assertEventContextNotUsed($event);
// Capture failed login token.
unset($CFG->alternateloginurl);
unset($CFG->disablelogintoken);
$sink = $this->redirectEvents();
$result = authenticate_user_login('username1', 'password1', false, $reason, 'invalidtoken');
$events = $sink->get_events();
$sink->close();
$event = array_pop($events);
$this->assertFalse($result);
$this->assertEquals(AUTH_LOGIN_FAILED, $reason);
// Test Event.
$this->assertInstanceOf('\core\event\user_login_failed', $event);
$expectedlogdata = array(SITEID, 'login', 'error', 'index.php', 'username1');
$this->assertEventLegacyLogData($expectedlogdata, $event);
$eventdata = $event->get_data();
$this->assertSame($eventdata['other']['username'], 'username1');
$this->assertSame($eventdata['other']['reason'], AUTH_LOGIN_FAILED);
$this->assertEventContextNotUsed($event);
// Login should work with invalid token if CFG login token settings override it.
$CFG->alternateloginurl = 'http://localhost/';
$sink = $this->redirectEvents();
$result = authenticate_user_login('username1', 'password1', false, $reason, 'invalidtoken');
$events = $sink->get_events();
$sink->close();
$this->assertEmpty($events);
$this->assertInstanceOf('stdClass', $result);
$this->assertEquals(AUTH_LOGIN_OK, $reason);
unset($CFG->alternateloginurl);
$CFG->disablelogintoken = true;
$sink = $this->redirectEvents();
$result = authenticate_user_login('username1', 'password1', false, $reason, 'invalidtoken');
$events = $sink->get_events();
$sink->close();
$this->assertEmpty($events);
$this->assertInstanceOf('stdClass', $result);
$this->assertEquals(AUTH_LOGIN_OK, $reason);
unset($CFG->disablelogintoken);
// Normal login with valid token.
$reason = null;
$token = \core\session\manager::get_login_token();
$sink = $this->redirectEvents();
$result = authenticate_user_login('username1', 'password1', false, $reason, $token);
$events = $sink->get_events();
$sink->close();
$this->assertEmpty($events);
$this->assertInstanceOf('stdClass', $result);
$this->assertEquals(AUTH_LOGIN_OK, $reason);
$reason = null;
// Capture failed login event.
$sink = $this->redirectEvents();
+41 -15
View File
@@ -32,26 +32,52 @@ defined('MOODLE_INTERNAL') || die();
class core_environment_testcase extends advanced_testcase {
/**
* Test the environment.
* Test the environment check status.
*/
public function test_environment() {
public function test_environment_check_status() {
global $CFG;
require_once($CFG->libdir.'/environmentlib.php');
list($envstatus, $environment_results) = check_moodle_environment(normalize_version($CFG->release), ENV_SELECT_RELEASE);
$this->assertNotEmpty($envstatus);
foreach ($environment_results as $environment_result) {
if ($environment_result->part === 'php_setting'
and $environment_result->info === 'opcache.enable'
and $environment_result->getLevel() === 'optional'
and $environment_result->getStatus() === false
) {
$this->markTestSkipped('OPCache extension is not necessary for unit testing.');
continue;
}
$this->assertTrue($environment_result->getStatus(), "Problem detected in environment ($environment_result->part:$environment_result->info), fix all warnings and errors!");
$results = check_moodle_environment(normalize_version($CFG->release), ENV_SELECT_RELEASE);
// The first element of the results array contains the environment check status.
$status = reset($results);
$this->assertTrue($status);
}
/**
* Data provider for Moodle environment check tests.
*
* @return array
*/
public function environment_provider() {
global $CFG;
require_once($CFG->libdir.'/environmentlib.php');
$results = check_moodle_environment(normalize_version($CFG->release), ENV_SELECT_RELEASE);
// The second element of the results array contains the list of environment results.
$environmentresults = end($results);
return array_map(function($result) {
return [$result];
}, $environmentresults);
}
/**
* Test the environment.
*
* @dataProvider environment_provider
* @param environment_results $result
*/
public function test_environment($result) {
if ($result->part === 'php_setting'
&& $result->info === 'opcache.enable'
&& $result->getLevel() === 'optional'
&& $result->getStatus() === false) {
$this->markTestSkipped('OPCache extension is not necessary for unit testing.');
}
$info = "{$result->part}:{$result->info}";
$this->assertTrue($result->getStatus(), "Problem detected in environment ($info), fix all warnings and errors!");
}
/**
+16
View File
@@ -2261,6 +2261,22 @@ function check_is_https(environment_results $result) {
return null;
}
/**
* Check if the site is using 64 bits PHP.
*
* @param environment_results $result
* @return environment_results|null updated results object, or null if the site is using 64 bits PHP.
*/
function check_sixtyfour_bits(environment_results $result) {
if (PHP_INT_SIZE === 4) {
$result->setInfo('php not 64 bits');
$result->setStatus(false);
return $result;
}
return null;
}
/**
* Upgrade the minmaxgrade setting.
*
+23 -4
View File
@@ -62,6 +62,21 @@ function profiling_is_saved($value = null) {
return $saved;
}
/**
* Whether PHP profiling is available.
*
* This check ensures that one of the available PHP Profiling extensions is available.
*
* @return bool
*/
function profiling_available() {
$hasextension = extension_loaded('tideways_xhprof');
$hasextension = $hasextension || extension_loaded('tideways');
$hasextension = $hasextension || extension_loaded('xhprof');
return $hasextension;
}
/**
* Start profiling observing all the configuration
*/
@@ -69,7 +84,7 @@ function profiling_start() {
global $CFG, $SESSION, $SCRIPT;
// If profiling isn't available, nothing to start
if (!extension_loaded('xhprof') && !extension_loaded('tideways')) {
if (!profiling_available()) {
return false;
}
@@ -146,7 +161,9 @@ function profiling_start() {
// Arrived here, the script is going to be profiled, let's do it
$ignore = array('call_user_func', 'call_user_func_array');
if (extension_loaded('tideways')) {
if (extension_loaded('tideways_xhprof')) {
tideways_xhprof_enable(TIDEWAYS_XHPROF_FLAGS_CPU + TIDEWAYS_XHPROF_FLAGS_MEMORY);
} else if (extension_loaded('tideways')) {
tideways_enable(TIDEWAYS_FLAGS_CPU + TIDEWAYS_FLAGS_MEMORY, array('ignored_functions' => $ignore));
} else {
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY, array('ignored_functions' => $ignore));
@@ -164,7 +181,7 @@ function profiling_stop() {
global $CFG, $DB, $SCRIPT;
// If profiling isn't available, nothing to stop
if (!extension_loaded('xhprof') && !extension_loaded('tideways')) {
if (!profiling_available()) {
return false;
}
@@ -183,7 +200,9 @@ function profiling_stop() {
// Arrived here, profiling is running, stop and save everything
profiling_is_running(false);
if (extension_loaded('tideways')) {
if (extension_loaded('tideways_xhprof')) {
$data = tideways_xhprof_disable();
} else if (extension_loaded('tideways')) {
$data = tideways_disable();
} else {
$data = xhprof_disable();
+2 -1
View File
@@ -80,9 +80,10 @@ class login_change_password_form extends moodleform {
function validation($data, $files) {
global $USER;
$errors = parent::validation($data, $files);
$reason = null;
// ignore submitted username
if (!$user = authenticate_user_login($USER->username, $data['password'], true)) {
if (!$user = authenticate_user_login($USER->username, $data['password'], true, $reason, false)) {
$errors['password'] = get_string('invalidlogin');
return $errors;
}
+4 -3
View File
@@ -80,13 +80,13 @@ if (!empty($SESSION->has_timed_out)) {
$session_has_timed_out = false;
}
/// auth plugins may override these - SSO anyone?
$frm = false;
$user = false;
$authsequence = get_enabled_auth_plugins(true); // auths, in sequence
foreach($authsequence as $authname) {
$authplugin = get_auth_plugin($authname);
// The auth plugin's loginpage_hook() can eventually set $frm and/or $user.
$authplugin->loginpage_hook();
}
@@ -145,13 +145,14 @@ if ($frm and isset($frm->username)) { // Login WITH
}
if ($user) {
//user already supplied by aut plugin prelogin hook
// The auth plugin has already provided the user via the loginpage_hook() called above.
} else if (($frm->username == 'guest') and empty($CFG->guestloginbutton)) {
$user = false; /// Can't log in as guest if guest button is disabled
$frm = false;
} else {
if (empty($errormsg)) {
$user = authenticate_user_login($frm->username, $frm->password, false, $errorcode);
$logintoken = isset($frm->logintoken) ? $frm->logintoken : '';
$user = authenticate_user_login($frm->username, $frm->password, false, $errorcode, $logintoken);
}
}
+3 -1
View File
@@ -57,6 +57,7 @@ if (empty($CFG->authloginviaemail)) {
<script>document.getElementById('anchor').value = location.hash</script>
<input type="submit" id="loginbtn" value="<?php print_string("login") ?>" />
<div class="forgetpass"><a href="forgot_password.php"><?php print_string("forgotten") ?></a></div>
<input type="hidden" name="logintoken" value="<?php echo s(\core\session\manager::get_login_token()); ?>" />
</form>
<div class="desc">
<?php
@@ -73,9 +74,10 @@ if (empty($CFG->authloginviaemail)) {
</div>
<form action="index.php" method="post" id="guestlogin">
<div class="guestform">
<input type="hidden" name="logintoken" value="<?php echo s(\core\session\manager::get_login_token()); ?>" />
<input type="hidden" name="username" value="guest" />
<input type="hidden" name="password" value="guest" />
<input type="submit" value="<?php print_string("loginguest") ?>" />
<input type="submit" value="<?php print_string("loginguest"); ?>" />
</div>
</form>
</div>

Some files were not shown because too many files have changed in this diff Show More