Compare commits

...

277 Commits

Author SHA1 Message Date
Eloy Lafuente (stronk7) c0523b9857 Moodle release 3.2.6 2017-11-11 19:29:31 +01:00
AMOS bot becebd955f Automatically generated installer lang files 2017-11-11 00:05:56 +00:00
David Monllao 0c7a83a632 weekly release 3.2.5+ 2017-11-10 15:15:20 +01:00
David Monllao 92d19efe4c Merge branch 'install_32_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_32_STABLE 2017-11-10 15:15:19 +01:00
Jun Pataleta 13c21e81b8 Merge branch 'MDL-60771-32' of git://github.com/lameze/moodle into MOODLE_32_STABLE 2017-11-10 18:03:08 +13:00
Damyon Wiese 7121cdfc3e Merge branch 'MDL-60749-32' of git://github.com/sarjona/moodle into MOODLE_32_STABLE 2017-11-10 12:06:56 +08:00
Simey Lameze 1d24a0fe2f MDL-60771 mod_scorm: typecast score to integer 2017-11-10 12:02:59 +08:00
Andrew Nicols dab49d9fcd Merge branch 'MDL-52838-32' of git://github.com/damyon/moodle into MOODLE_32_STABLE 2017-11-10 11:50:19 +08:00
Damyon Wiese eecc7ff372 MDL-52838 workshop: Each criterion > 0 levels
Add validation to the edit assessment form so each criterion in a rubric requires at least one level.
2017-11-10 10:22:35 +08:00
Sara Arjona adfc2dd7a6 MDL-60749 scorm: Remove   from files when downloading 2017-11-09 10:56:51 +01:00
Sara Arjona 80ad2ce7ce MDL-60550 user: Add more restrictions in keyword searches
Original patch provided by Tim Schroeder.
2017-11-09 15:50:27 +08:00
David Monllao fda021dcc6 Merge branch 'MDL-60615-32' of git://github.com/damyon/moodle into MOODLE_32_STABLE 2017-11-09 08:49:11 +01:00
Damyon Wiese 7b47a1e464 Merge branch 'MDL-60752-32' of git://github.com/andrewnicols/moodle into MOODLE_32_STABLE 2017-11-09 15:11:02 +08:00
Damyon Wiese 49212a0e82 MDL-60615 imscc: string to array fix
Sloppy typing in the imscc converter is causing errors on php7.1

Variable is initialised as a string and then used as an array.
2017-11-09 15:06:48 +08:00
Andrew Nicols 9875c6c899 MDL-60752 lti: Compare text in types_config properly 2017-11-09 14:27:16 +08:00
AMOS bot 83939aeed6 Automatically generated installer lang files 2017-11-09 00:05:20 +00:00
David Monllao b5a794e133 Merge branch 'MDL-60720-m32' of https://github.com/sammarshallou/moodle into MOODLE_32_STABLE 2017-11-08 17:32:48 +01:00
David Monllao ab05a777b8 Merge branch 'MDL-58699-32' of git://github.com/damyon/moodle into MOODLE_32_STABLE 2017-11-08 15:56:50 +01:00
David Monllao 4126e44fa3 MDL-60733 oauth: Remove outdated comment 2017-11-08 12:05:10 +01:00
David Monllao 768e1558be Merge branch 'MDL-60733-32' of git://github.com/damyon/moodle into MOODLE_32_STABLE 2017-11-08 12:05:03 +01:00
David Monllao f42720e3f9 weekly release 3.2.5+ 2017-11-08 09:47:23 +01:00
David Monllao 60fbdc0e23 Merge branch 'install_32_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_32_STABLE 2017-11-08 09:47:21 +01:00
Damyon Wiese 306a3eba3f MDL-60733 core: B/C for google_oauth
The google_oauth class extends oauth2client which was modified to send "Accept" headers.

The "Accept" headers break picasa and could break any other plugin that was using google_oauth.
2017-11-08 15:25:37 +08:00
Jun Pataleta 3d75433495 Merge branch 'MDL-60717-32-enfix' of git://github.com/mudrd8mz/moodle into MOODLE_32_STABLE 2017-11-08 14:43:54 +13:00
AMOS bot f55ffd1d37 Automatically generated installer lang files 2017-11-08 00:05:21 +00:00
Helen Foster 2ab4e9e320 MDL-60717 lang: Merge English strings from the en_fix language pack
Significant string changes:

- needbcmath,auth_ldap - 'grace logins' changed to 'expired password
  checking'
2017-11-07 21:59:23 +01:00
sam marshall 016d93e1df MDL-60720 core_search: Indexing halts on failed get_document
The recordsets used for search indexing sometimes return results
which are invalid (e.g. cannot be found in database). When this
happens, the result in the iterator for the recordset will be
false. Due to a bug, the iterator used to stop when it encountered
a false value, which prevented indexing from getting past the
problematic record.

In addition, the iterator that skips future data resulted in the
current() function of its parent indicator being called twice per
entry, which meant that search indexing called get_document()
twice as many times.
2017-11-07 16:47:58 +00:00
Jake Dallimore a15fae38cb Merge branch 'MDL-57772-32' of git://github.com/damyon/moodle into MOODLE_32_STABLE 2017-11-07 15:02:12 +08:00
Damyon Wiese c1d666c078 MDL-58699 mod_quiz: Require javascript for popup
If any of the access rules require the attempt to open in a new window, assume we
require javascript to attempt the quiz. This makes it harder to bypass the javascript
pseudo security restrictions.
2017-11-07 12:50:26 +08:00
Damyon Wiese ccca9cf794 MDL-57772 chat: BEEP is back baby! 2017-11-07 11:25:21 +08:00
sam marshall 9f9350068b MDL-60671 core_search: Cron output should use mtrace
The mtrace function is preferable for plain text logging/progress
output because it can be redirected if necessary. By convention it
is normally used in cron and can be used in CLI tasks if required.

This change makes the text_progress_trace class use mtrace instead
of echo and then flush. (Default behaviour of mtrace is to do
exactly that, but it can be redirected too.)

Before this change, if anybody is relying on mtrace behaviour to
redirect logs of cron output, this will fail for some parts of the
search cron output (and some other places like auth plugins).
2017-11-07 11:08:13 +08:00
David Monllao 3c665aed99 Merge branch 'MDL-60424-32' of git://github.com/jleyva/moodle into MOODLE_32_STABLE 2017-11-06 21:12:39 +01:00
Damyon Wiese da0bb6a820 Merge branch 'MDL-59858-32' of git://github.com/junpataleta/moodle into MOODLE_32_STABLE 2017-11-06 11:15:14 +08:00
Damyon Wiese 36043eacd3 Merge branch 'MDL-60437_32-multilang-html-block-titles' of https://github.com/lucaboesch/moodle into MOODLE_32_STABLE 2017-11-06 10:12:17 +08:00
Jun Pataleta 9434133480 MDL-59858 amd: Focus on the element that actually triggers the modal 2017-11-06 13:23:23 +13:00
AMOS bot 2e6b69cbca Automatically generated installer lang files 2017-11-05 00:06:23 +00:00
Luca Bösch a0ec6413d5 MDL-60437 blocks: HTML block title multilang 2017-11-03 16:37:13 +01:00
David Monllao 1d1086e3e5 weekly release 3.2.5+ 2017-11-03 10:25:12 +01:00
Juan Leyva 311076f3a2 MDL-60424 webservice: Allow CORS requests in webservice/upload.php
This will allow to upload files via Web Services using AJAX from
different domains, browser plugins, web apps, etc…
2017-11-03 09:42:00 +01:00
Jake Dallimore 107ea0f3c7 Merge branch 'MDL-58047-32-fix1' of http://github.com/damyon/moodle into MOODLE_32_STABLE 2017-11-03 16:11:19 +08:00
Damyon Wiese bd2c01bb9e MDL-58047 assign: submission sorting
Only exclude new submission records from the sorting, draft and reopened submission are valid.
2017-11-03 15:56:36 +08:00
David Monllao 0e7e457214 Merge branch 'MDL-58047-32-sortbysubmission' of https://github.com/roperto/moodle into MOODLE_32_STABLE 2017-11-02 16:58:05 +01:00
David Monllao 1e802bb449 Merge branch 'MDL-51945-32' of git://github.com/jleyva/moodle into MOODLE_32_STABLE 2017-11-02 16:55:51 +01:00
David Monllao 5bd85d7f4f Merge branch 'MDL-60634-32' of git://github.com/jleyva/moodle into MOODLE_32_STABLE 2017-11-02 13:26:12 +01:00
David Monllao ed76eb03f7 Merge branch 'MDL-60633-32' of git://github.com/andrewnicols/moodle into MOODLE_32_STABLE 2017-11-02 12:04:27 +01:00
David Monllao db1898291d Merge branch 'MDL-53501-32' of git://github.com/jleyva/moodle into MOODLE_32_STABLE 2017-11-02 08:30:57 +01:00
Jake Dallimore 2d56bc1c72 Merge branch 'MOODLE_32_STABLE_MDL-60007' of https://github.com/CengageEng/moodle into MOODLE_32_STABLE 2017-11-02 08:51:26 +08:00
Eloy Lafuente (stronk7) 2ba8535459 weekly release 3.2.5+ 2017-11-01 13:38:55 +01:00
Eloy Lafuente (stronk7) 88bbfa1dc2 Merge branch 'MDL-60503-32' of git://github.com/damyon/moodle into MOODLE_32_STABLE 2017-11-01 11:51:23 +01:00
Damyon Wiese c4c6e31630 MDL-60503 npm: Lock required node 8.9.x (LTS) 2017-11-01 14:54:03 +08:00
Daniel Thee Roperto f6db012818 MDL-58047 gradebook: fix sort by submission order. 2017-11-01 15:11:16 +11:00
Damyon Wiese d83e2ba4cd Merge branch 'MDL-52037-32-fix' of https://github.com/andrewnicols/moodle into MOODLE_32_STABLE 2017-11-01 11:15:44 +08:00
Andrew Nicols baab74b9d3 MDL-52037 theme: Correct question feedback width
This relates to the cloze question answer when hovered.
2017-11-01 11:13:52 +08:00
Vervoort, Claude 44b817cf60 MDL-60007 mod lti: allow delete without content-type 2017-10-31 09:58:54 -04:00
Juan Leyva 590706db1f MDL-60634 tool_mobile: Avoid CURL request to check HTTPS 2017-10-31 12:07:08 +01:00
David Monllao a7f16bb296 MDL-52037 theme: Update compiled css 2017-10-31 11:03:55 +01:00
Luca Bösch 042dd6335d MDL-52037 questions: „Whether correct“-feedback marks adaptive width 2017-10-31 10:44:00 +01:00
Jake Dallimore 0bd1bd92dc Merge branch 'MDL-60607_32' of git://github.com/timhunt/moodle into MOODLE_32_STABLE 2017-10-31 13:00:19 +08:00
Jun Pataleta c03a53e8d8 Merge branch 'MDL-57560-32' of git://github.com/damyon/moodle into MOODLE_32_STABLE 2017-10-31 15:41:40 +13:00
Andrew Nicols 267a719a17 Merge branch 'MDL-60139_32' of git://github.com/timhunt/moodle into MOODLE_32_STABLE 2017-10-31 09:16:10 +08:00
Andrew Nicols eaea57597c Merge branch 'MDL-60522-32' of https://github.com/Kathrin84/moodle into MOODLE_32_STABLE 2017-10-31 08:21:26 +08:00
Andrew Nicols 0dc5bfa27e MDL-60633 core: Add pendingjs checks for inplace editable 2017-10-31 07:05:06 +08:00
Tim Hunt b18cde3450 MDL-60607 quiz reports: catch separate groups & user has no group case 2017-10-30 17:58:25 +00:00
Tim Hunt a0b2649a16 MDL-60607 quiz reports: move duplicate code to superclass method 2017-10-30 17:58:23 +00:00
David Monllao 9a11ca8fd6 Merge branch 'MDL-60528-m32' of https://github.com/micaherne/moodle into MOODLE_32_STABLE 2017-10-30 17:59:48 +01:00
Juan Leyva 7ec9a6daa7 MDL-51945 core_user: Prevent duplicated emails in update_users WS 2017-10-30 17:42:34 +01:00
David Monllao ee461eee7f Merge branch 'MDL-52037_32-cloze-whether-correct-feedback-width' of https://github.com/lucaboesch/moodle into MOODLE_32_STABLE 2017-10-30 16:06:17 +01:00
Juan Leyva 55711a938a MDL-53501 webservice: Avoid values higher than PHP_INT_MAX
Integers coming from site settings needs casting to int to avoid
returning values higher than PHP_INT_MAX.
2017-10-30 16:04:39 +01:00
Michael Aherne c860ca5c91 MDL-60528 grading: Accurate class names in PHPDoc 2017-10-30 14:31:04 +00:00
Tim Hunt 828a24f784 MDL-60139 question manual grading: move code to reduce confusion
Move the variable definition closer to where it is used.
2017-10-30 12:58:26 +00:00
Tim Hunt 78e92b3fb1 MDL-60139 question manual grading: redisplay mark as typed if editing
When the teacher is upgrading a previously entered grade, we re-display
exactly what they typed before if possible, rather than displaying with
a set number of decimal places.
2017-10-30 12:58:24 +00:00
Tim Hunt 48dbf89252 MDL-60139 phpunit: Make assertTag verify attribute values with ===
I had a test that cared about the difference between value="5.0" and value="5".
2017-10-30 12:58:22 +00:00
David Monllao 83d284be42 Merge branch 'MDL-60377-32' of git://github.com/jleyva/moodle into MOODLE_32_STABLE 2017-10-30 11:42:55 +01:00
Luca Bösch 263528b0d8 MDL-52037 questions: „Whether correct“-feedback marks adaptive width 2017-10-30 10:41:16 +00:00
Kathrin Osswald 966c52eb3d MDL-60522 message: Removed additional tooltips
I removed the additional tooltips because I think that they are just used
in the notifications and messages context and duplicate the all over used
title tag that gives the same information when hovering. So the whole system
stays more consistently.
2017-10-30 08:04:08 +01:00
Damyon Wiese 438da5c13b MDL-57560 boost: File upload progress
Copy / adapt some styles from the bootstrap progress widget to match the DOM used for file upload progress.

Bootstrap changed this alot in the current beta so I opted to do a minimal change (affect the scss for boost only), rather
than adapt the HTML to something that will change again anyway when we upgrade to the release version of bootstrap 4.
2017-10-30 13:14:04 +08:00
Jake Dallimore bc299c8d4d Merge branch 'MDL-59606_32' of git://github.com/timhunt/moodle into MOODLE_32_STABLE 2017-10-30 11:24:03 +08:00
Andrew Nicols 29e276eeea Merge branch 'MDL-60605-32' of https://github.com/dvdcastro/moodle into MOODLE_32_STABLE 2017-10-30 10:51:54 +08:00
Andrew Nicols 4c28e8abe3 Merge branch 'MOODLE_32_STABLE_MDL-60360_enable_file_indexing_retroactively' of https://github.com/mattporritt/moodle into MOODLE_32_STABLE 2017-10-30 09:21:27 +08:00
Jun Pataleta 570b297303 Merge branch 'MDL-60572-32' of git://github.com/jleyva/moodle into MOODLE_32_STABLE 2017-10-30 10:26:05 +13:00
David Castro 261af24e61 MDL-60605 assignment: Added some styles to fix spacing in YUI file tree 2017-10-27 11:05:25 -05:00
Tim Hunt 20df9e8faa MDL-59606 quiz responses: fix edge cases in the report
This patch conbines valuable contributions from Kashmira Nagwekar and
Luca Bösch. Many thanks to them. However, the final form of the fix,
and hence the blame, falls to me -- Tim.

There were several issues here:

* The load_questions_usages_by_activity method in
  question/engine/datalib.php was incorrectly treating the case
  when no data was returned. (Looks like a historic copy-pase from
  other methods that fetch one item by unique id, which therefore
  must exist.)

* The report was not correctly handling the display when the 'Which
  tries' was set to 'with, and without, attempts'.

* It was possible to select the 'All tries' option when also saying
  'Users without attempts'. This combination makes not sense, so
  a disabledIf rule was added to the form.
2017-10-27 16:57:34 +01:00
David Monllao 14f2ce60a7 weekly release 3.2.5+ 2017-10-27 12:48:27 +02:00
Juan Leyva 00c2d21bab MDL-60572 admin: Fix forgottenpasswordurl for WS
We should expect URLs in that field.
The tool_mobile change is to not break the WS response if
forgottenpasswordurl does not contain a URL.
2017-10-27 10:48:54 +02:00
Matt Porritt ba3904e81b MDL-60360 Global Search: Enable file indexing message update.
If you have Global Search set up on a site without file
indexing enabled, then at a later date you enable file indexing
files associated with existing objects are not added.

The only way to have files for existing objects indexed is to
run a reindex of all content.

This patches updates the file indexing language string in the
solr search settings of Global Search to make this clear
to the site administrator.
2017-10-27 11:16:35 +11:00
Jun Pataleta 6e90b081c2 Merge branch 'MDL-60265-32' of git://github.com/jleyva/moodle into MOODLE_32_STABLE 2017-10-27 11:52:47 +13:00
David Monllao 1a4b29ae88 Merge branch 'wip-MDL-57055-32' of git://github.com/abgreeve/moodle into MOODLE_32_STABLE 2017-10-26 19:18:05 +02:00
Juan Leyva b627bcfd25 MDL-60265 tool_mobile: Return sitepolicy in tool_mobile_get_config WS 2017-10-26 11:05:51 +02:00
Damyon Wiese 8e378ca989 Merge branch 'MDL-60366_feedback_upgrade_32' of git://github.com/davosmith/moodle into MOODLE_32_STABLE 2017-10-26 15:41:02 +08:00
Andrew Nicols 41c8216718 Merge branch 'wip-MDL-60543-32' of git://github.com/marinaglancy/moodle into MOODLE_32_STABLE 2017-10-26 14:35:12 +08:00
Andrew Nicols ad80abc65c Merge branch 'MDL-60162_32' of git://github.com/timhunt/moodle into MOODLE_32_STABLE 2017-10-26 14:07:51 +08:00
Adrian Greeve 40be01a636 MDL-57055 mod_label: Add label administration for boost.
This patch adds the label adminstration settings to the
label edit page.
2017-10-26 13:58:57 +08:00
Andrew Nicols 5b497b1bde Merge branch 'MDL-60535_32-questionbank-button-styled' of https://github.com/lucaboesch/moodle into MOODLE_32_STABLE 2017-10-26 13:19:24 +08:00
Andrew Nicols fc6209584d Merge branch 'MOODLE_32_MDL-51892' of https://github.com/fwsl/moodle into MOODLE_32_STABLE 2017-10-26 11:31:06 +08:00
Jake Dallimore 3a3198767c Merge branch 'MDL-59686-32' of git://github.com/lameze/moodle into MOODLE_32_STABLE 2017-10-26 10:20:30 +08:00
Simey Lameze f94376bfc4 MDL-59686 form: fix autosave support for editor field 2017-10-26 09:05:00 +08:00
Jun Pataleta 086815b1d6 Merge branch 'MDL-60571_32-manualgrading-savegotonextpage-styled' of https://github.com/lucaboesch/moodle into MOODLE_32_STABLE 2017-10-26 10:04:01 +13:00
David Monllao 5a03d41860 Merge branch 'MDL-60538-32' of https://github.com/mihailges/moodle into MOODLE_32_STABLE 2017-10-25 15:09:50 +02:00
David Monllao 470a2e32fa weekly release 3.2.5+ 2017-10-25 11:13:48 +02:00
David Monllao 1a58e38ea2 Merge branch 'install_32_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_32_STABLE 2017-10-25 11:13:47 +02:00
Andrew Nicols 3e2732fbc7 Merge branch 'MDL-36580_32' of https://github.com/stronk7/moodle into MOODLE_32_STABLE 2017-10-25 12:19:14 +08:00
Andrew Nicols 494d18b16a Merge branch 'MDL-36580_32' of https://github.com/stronk7/moodle into MOODLE_32_STABLE 2017-10-25 12:19:14 +08:00
Mihail Geshoski 6b818f0534 MDL-60538 lesson: check if max attempts exceeded, use new lang string 2017-10-25 09:11:26 +08:00
Eloy Lafuente (stronk7) cf3ee0a406 MDL-36580 backup: Avoid PHP notice restoring old backups
Before this implementation, both resourcekey and password
were not being included in the backups, so old backups are
missing them. To keep upwards compatibility and avoid a PHP
Notice (undefined property), existence is checked via isset(),
that is the usual way all over the restore process.
2017-10-24 23:03:29 +02:00
Tim Hunt 4635a07e6a MDL-60162 quiz reports: refactor duplicated code into the base class
This is needed to fix the unit test in the last commit.
2017-10-24 18:14:41 +01:00
Tim Hunt 661e129873 MDL-60162 quiz reports: too many rows fetched on download
This happened if one user had multiple enrolments in a course, and was
quite inefficient.
2017-10-24 18:14:39 +01:00
AMOS bot 6644d7328e Automatically generated installer lang files 2017-10-25 00:06:15 +08:00
Luca Bösch d969814e09 MDL-60535 quiz: question bank button styled 2017-10-24 16:09:26 +01:00
Luca Bösch a00083a947 MDL-60571 quiz: Manual grading Save and go to next page button styled 2017-10-24 12:17:48 +01:00
Grzegorz Ziółek 858fd41248 MDL-51892 logging: Proper description of login errors. 2017-10-24 10:56:53 +02:00
Davo Smith c69f396769 MDL-60366 mod_feedback: fix deletion of valid anonymous duplicates 2017-10-24 09:38:06 +01:00
Andrew Nicols 8fa79442fd MDL-57477 session: Comment tidyup 2017-10-24 08:23:22 +08:00
Andrew Nicols 03488ecc9c Merge branch 'MDL-57477_32' of https://github.com/appalachianstate/moodle into MOODLE_32_STABLE 2017-10-24 08:13:37 +08:00
Fred Woolard c4bb09b742 MDL-57477 core: If memcached 3.x mimic 2.2.0 lock acquisition behavior 2017-10-23 13:49:01 -04:00
David Monllao 0b3e013f64 Merge branch 'MDL-60527_32-action-menu-links-missing-spaces-attributes' of https://github.com/lucaboesch/moodle into MOODLE_32_STABLE 2017-10-23 16:59:31 +02:00
Andrew Nicols fde74736a4 MDL-60489 javascript: Add missing promise fails 2017-10-23 20:32:01 +08:00
Andrew Nicols 17b978cd90 Merge branch 'MDL-60489-32' of git://github.com/ryanwyllie/moodle into MOODLE_32_STABLE 2017-10-23 20:30:50 +08:00
Eloy Lafuente (stronk7) 73728cb33e Merge branch 'm32_MDL-59100_MySQL8_INFORMATION_SCHEMAs_Need_Lowercasing' of https://github.com/scara/moodle into MOODLE_32_STABLE 2017-10-23 12:11:15 +02:00
Ryan Wyllie 9f021bd587 MDL-60489 javascript: add animations to modal setBody 2017-10-23 08:12:05 +00:00
Marina Glancy 43f269a3d8 MDL-60543 env: Moodle 3.2 and 3.3 do no support PHP7.2 2017-10-23 14:16:57 +08:00
Damyon Wiese 8caec2eb7a Merge branch 'MDL-52653-32' of http://github.com/damyon/moodle into MOODLE_32_STABLE 2017-10-23 13:20:02 +08:00
Damyon Wiese a1dee21ec1 MDL-52653 scorm: Comment for cms.completion_status 2017-10-23 13:12:56 +08:00
Christian Lawson-Perfect 56df23be4f MDL-52653 SCORM: fix scorm_check_mode on v1.3
SCORM 2004 uses the element 'cmi.completion_status' to store the
completion status of a SCO, not 'cmi.core.lesson_status'.

This amends scorm_check_mode so that the right element is looked up.

When scorm_version_check returns false, SCORM 1.2 is assumed.
2017-10-23 13:12:55 +08:00
Luca Bösch 1712134d00 MDL-60527 templates: missing spaces round attribute and aria-labelledby 2017-10-22 22:55:56 +01:00
Matteo Scaramuccia 71db3b4410 MDL-59100 dml: Lower the case of INFORMATION_SCHEMA.* fields. 2017-10-21 14:35:59 +02:00
Eloy Lafuente (stronk7) b8e10f239b weekly release 3.2.5+ 2017-10-20 23:54:56 +02:00
Andrew Nicols a3b0fce39c Merge branch 'MDL-60456-32' of git://github.com/damyon/moodle into MOODLE_32_STABLE 2017-10-20 10:29:24 +08:00
David Monllao 1b0d340042 Merge branch 'MDL-60123-32' of https://github.com/snake/moodle into MOODLE_32_STABLE 2017-10-20 02:22:43 +02:00
Eloy Lafuente (stronk7) 81b900a2f2 Merge branch 'MDL-60342-32' of https://github.com/patkira/moodle into MOODLE_32_STABLE 2017-10-19 23:25:13 +02:00
Eloy Lafuente (stronk7) 4c3d434cb4 Merge branch 'wip-MDL-60314-32' of git://github.com/marinaglancy/moodle into MOODLE_32_STABLE 2017-10-19 23:19:36 +02:00
Eloy Lafuente (stronk7) 8835fd01c5 Merge branch 'MDL-60449-32-enfix' of git://github.com/mudrd8mz/moodle into MOODLE_32_STABLE 2017-10-19 22:21:37 +02:00
Helen Foster a57c2774e8 MDL-60449 lang: Merge English strings from the en_fix language pack
Significant string changes:

* errorretrievingkey in message_airnotifier - improved wording and
  removing reference to Moodle.org
* enddate_help and courseduration_desc in core - clearer wording
  explaining what the date actually does
* restore:viewautomatedfilearea in core_role - changing wording to match
  the behaviour
* dropzones_help in qtype_ddmarker - improved wording
* autologinkeygenerationlockout in tool_mobile - updated error message
* configallowemailaddresses in core_admin - clearer description
* subscriptionmode_helpin mod_forum - removing misleading sentence about
  subscription mode changes not affecting existing users
2017-10-19 18:16:51 +02:00
David Monllao 9a4fbd4574 Merge branch 'wip-MDL-58915-32' of git://github.com/marinaglancy/moodle into MOODLE_32_STABLE 2017-10-19 15:44:43 +02:00
David Monllao 4270255272 Merge branch 'MDL-60233-32' of git://github.com/jleyva/moodle into MOODLE_32_STABLE 2017-10-19 13:52:23 +02:00
Nadav Kavalerchik 778d746f6c MDL-60182 Glossary: Fix print icon label in RTL mode 2017-10-19 13:40:42 +02:00
David Monllao 4e41d6c56f Merge branch 'MDL-60469-32' of git://github.com/andrewnicols/moodle into MOODLE_32_STABLE 2017-10-19 10:56:01 +02:00
David Monllao 04b1f4254e Merge branch 'MDL-60247_32-multilang-html-glossary-block-titles' of https://github.com/lucaboesch/moodle into MOODLE_32_STABLE 2017-10-19 10:34:54 +02:00
Eloy Lafuente (stronk7) d58ae0c075 MDL-36580 backup: Apply the decrypt() method to lti "secrets" 2017-10-19 10:20:21 +02:00
Eloy Lafuente (stronk7) dab2233925 MDL-36580 backup: General support for decrypted contents in restore
- Uses site generated (on backup) key.
- Can be applied potentially everywhere in the restore process.
- Covered with unit tests.
- Authentication / integrity aware so can be used between any 2 servers
  (just requires matching key).
2017-10-19 10:20:21 +02:00
Eloy Lafuente (stronk7) 370f78715e MDL-36580 backup: Use the encrypted_final_element for lti "secrets" 2017-10-19 10:20:21 +02:00
Eloy Lafuente (stronk7) 6c436ac37e MDL-36580 backup: General support for encrypted contents in backups
- Built using standard backup custom fields.
- Can be applied potentially everywhere.
- Automatically addded 'encrypted' attribute.
- Defaults to site generated key.
- Enforces key robutness / provides authentication (hmac integrity)
- Covered with unit tests.
2017-10-19 10:20:18 +02:00
Andrew Nicols 6df049fa3c MDL-60469 behat: Replace I press with I click on 2017-10-19 11:59:44 +08:00
Damyon Wiese c7813fa674 MDL-60456 javascript: Rebuild npm-shrinkwrap
Build npm-shrinkwrap with the latest node version and only test the latest node version on travis.
2017-10-19 11:53:17 +08:00
Jun Pataleta 61a96642f0 Merge branch 'wip-MDL-60335-32' of git://github.com/marinaglancy/moodle into MOODLE_32_STABLE 2017-10-19 15:37:37 +13:00
Jun Pataleta 09b1711d94 Merge branch 'mdl59843-moodle32' of https://github.com/tlock/moodle into MOODLE_32_STABLE 2017-10-19 13:20:19 +13:00
Eloy Lafuente (stronk7) 0fe0954344 weekly release 3.2.5+ 2017-10-19 00:11:06 +02:00
Eloy Lafuente (stronk7) f6d4edd3aa Merge branch 'install_32_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_32_STABLE 2017-10-19 00:11:04 +02:00
Pat Kira 18f5851994 MDL-60342 test: Reset user agent after tests
- Add a test that proves this useragent is not being reset after a test
- Reset user agent
2017-10-18 13:59:17 +11:00
Marina Glancy b9fef33112 MDL-60335 admin: fix encoding of nonlatin site names in blocked hosts 2017-10-17 12:59:39 +08:00
Jake Dallimore 0730e8a380 Merge branch 'wip-MDL-60033-32' of git://github.com/marinaglancy/moodle into MOODLE_32_STABLE 2017-10-16 15:37:24 +08:00
Jake Dallimore cdd836011f MDL-60123 assign: Allow teachers to deselect pdf annotations in editpdf
Clicking a blank area of the canvas will now deselect any currently
selected annotation.
2017-10-16 08:45:33 +08:00
AMOS bot c9b29b832b Automatically generated installer lang files 2017-10-14 00:08:45 +08:00
Luca Bösch d93d2a0d86 MDL-60247 blocks: Multilang in Random glossary and in HTML block titles. 2017-10-13 13:52:50 +02:00
Jake Dallimore ef89f89988 weekly release 3.2.5+ 2017-10-13 14:33:13 +08:00
Jake Dallimore fe53da02a3 Merge branch 'install_32_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_32_STABLE 2017-10-13 14:33:12 +08:00
Marina Glancy 0233c84101 MDL-58915 search_solr: connection to solr can use blocked hosts 2017-10-13 12:18:15 +08:00
Jake Dallimore c3b3d04ca6 Merge branch 'MDL-60357-32-fix' of https://github.com/andrewnicols/moodle into MOODLE_32_STABLE 2017-10-13 11:40:46 +08:00
Andrew Nicols 59dd0cc761 MDL-60357 search: Ensure that the document is valid
We were previously testing tha the parent is valid, which it was, and
then fetching the current record, before fetching data from it.

However, the way in which the recordset walk works, the valid function
checks whether the _record_ itself is valid, whilst the current allows
for a callback to be applied.

In this instance, the data-entry was failing because the count of
indexfields was < 2. The recordset data itself was valid, but the view
was not, and as a result, the current() function returned false.

This false was not previously handled.

I've changed the logic so that we handle this case, and have removed a
double-negative in the process.
2017-10-13 09:46:43 +08:00
Jun Pataleta 7fa35eca49 Merge branch 'MDL-59854-32' of git://github.com/junpataleta/moodle into MOODLE_32_STABLE 2017-10-12 12:28:24 +08:00
Tobias Reischmann cf266bd3e2 MDL-59854 forum: Created unique db key for forum_subscriptions
Due to race conditions in the function subscribe_user
it was possible to create duplicate forum subscriptions.
This lead to error messages, when displaying the list of
all subscriptions.
This patch removes all existing duplicate entries and
creates a unique db key to prevent this from happening in
the future.
2017-10-12 12:19:21 +08:00
Eloy Lafuente (stronk7) 6b0bf399e2 Merge branch 'MDL-60357-m32' of https://github.com/sammarshallou/moodle into MOODLE_32_STABLE 2017-10-11 20:50:11 +02:00
Andrew Nicols fb00e2dc97 Merge branch 'MOODLE_32_STABLE_MDL-60276' of https://github.com/CengageEng/moodle into MOODLE_32_STABLE 2017-10-11 09:41:00 +08:00
Eloy Lafuente (stronk7) abfaf22dfb Merge branch 'MDL-60300-m32' of https://github.com/NeillM/moodle into MOODLE_32_STABLE 2017-10-11 01:40:13 +02:00
Eloy Lafuente (stronk7) 69865a1de3 Merge branch 'MDL-60346-m32' of https://github.com/sammarshallou/moodle into MOODLE_32_STABLE 2017-10-11 01:13:57 +02:00
Eloy Lafuente (stronk7) 66ccbfeb99 Merge branch 'MDL-60364-m32' of https://github.com/NeillM/moodle into MOODLE_32_STABLE 2017-10-11 01:00:48 +02:00
Juan Leyva 19bda8aa7e MDL-60377 webservice: Format correctly text returned by WS 2017-10-10 15:17:12 +02:00
AMOS bot e17f45f120 Automatically generated installer lang files 2017-10-10 00:12:25 +08:00
Andrew Nicols c63b1749ba Merge branch 'MDL-60317_32' of git://github.com/timhunt/moodle into MOODLE_32_STABLE 2017-10-09 14:10:44 +08:00
Marina Glancy 6f7bff5aa9 MDL-60314 navigation: fix overriding variable value 2017-10-09 10:19:18 +08:00
sam marshall 68049f376f MDL-60357 core_search: Future modified times cause serious problems 2017-10-06 14:16:54 +01:00
Neill Magill cf97659678 MDL-60300 Quiz: Offline update time not set correctly 2017-10-06 13:30:50 +01:00
Neill Magill 6a74606965 MDL-60364 Web service: E_ERROR in course_check_updates web service
The error stated that course_check_updates() is undefined, this function
is in the course lib.php file.
2017-10-06 13:30:31 +01:00
sam marshall 4d286aa730 MDL-60346 core_search: Solr connection ignores proxy settings 2017-10-06 11:41:28 +01:00
Jake Dallimore ff93f3915a weekly release 3.2.5+ 2017-10-06 14:34:34 +08:00
Jake Dallimore 95b73b0858 Merge branch 'install_32_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_32_STABLE 2017-10-06 14:34:33 +08:00
Jake Dallimore 3c051e549a Merge branch 'MDL-57228_32' of git://github.com/timhunt/moodle into MOODLE_32_STABLE 2017-10-04 13:45:45 +08:00
Eloy Lafuente (stronk7) e4b90ebdab Merge branch 'MDL-59882-32' of git://github.com/andrewnicols/moodle into MOODLE_32_STABLE 2017-10-03 20:52:14 +02:00
Eloy Lafuente (stronk7) 939b9ab977 Merge branch 'MDL-60198-32' of git://github.com/jleyva/moodle into MOODLE_32_STABLE 2017-10-03 20:16:09 +02:00
AMOS bot 2b3ebab6dd Automatically generated installer lang files 2017-10-04 00:10:47 +08:00
Andrew Nicols a5fc11023b Merge branch 'MDL-60210-32-upgradecheck' of git://github.com/mudrd8mz/moodle into MOODLE_32_STABLE 2017-10-03 10:34:05 +08:00
Tim Hunt 2923e19928 MDL-60317 quiz reports: fix regression caused by MDL-57511 2017-10-02 18:24:56 +01:00
Andrew Nicols c26afb9b76 Merge branch 'MDL-58790_32' of git://github.com/timhunt/moodle into MOODLE_32_STABLE 2017-10-02 15:40:41 +08:00
Andrew Nicols ac5e3e9c6b MDL-59882 behat: Update known uses of dialogue CSS 2017-10-02 12:50:41 +08:00
Andrew Nicols a9739a84dc MDL-59882 behat: Add newer modal type to selectors 2017-10-02 12:50:41 +08:00
Andrew Nicols 4b1402490a Merge branch 'MDL-60306-32' of git://github.com/junpataleta/moodle into MOODLE_32_STABLE 2017-10-02 10:17:44 +08:00
Jun Pataleta 3ee60271fa MDL-60306 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.
2017-10-02 09:18:57 +08:00
ddelblanco 579b44ef14 MDL-60276 LTI Content Item: does not populate tool url when https 2017-09-28 09:51:58 -07:00
AMOS bot 76fd4da35d Automatically generated installer lang files 2017-09-29 00:06:26 +08:00
Jake Dallimore c2d1467a7d weekly release 3.2.5+ 2017-09-28 14:27:27 +08:00
Tim Lock 6eb39155d4 MDL-59843 mod_choice: Fix horizontal display mode
This re-implements the feature in the boost and bootstrap themes.
2017-09-28 12:29:05 +10:00
Eloy Lafuente (stronk7) b3b909e1b4 Merge branch 'MDL-60243-32' of https://github.com/snake/moodle into MOODLE_32_STABLE 2017-09-27 20:48:48 +02:00
Jake Dallimore 77917ed26b Merge branch 'MDL-59780-32' of git://github.com/ankitagarwal/moodle into MOODLE_32_STABLE 2017-09-27 13:44:16 +08:00
Ankit Agarwal 1da8d303ef MDL-59780 mathjax: Make sure mathjax url doesn't become empty 2017-09-27 09:16:11 +05:30
Jake Dallimore 6d01904503 MDL-60243 competencies: fix ordering bug in api_test unit test
list_user_competencies_to_review() orders by shortname, but the test
creates 2 user competencies with the same short name, resulting in
unpredictable results. This patch fixes that.
2017-09-27 09:28:36 +08:00
Eloy Lafuente (stronk7) fe6903b33f Merge branch 'MDL-59931_32_STABLE' of https://github.com/ctam/moodle into MOODLE_32_STABLE 2017-09-27 01:16:26 +02:00
Eloy Lafuente (stronk7) 1dbe5c038e Merge branch 'MDL-59220-32' of git://github.com/damyon/moodle into MOODLE_32_STABLE 2017-09-27 00:52:20 +02:00
Juan Leyva c457cf5d35 MDL-60198 webservice: Add missing MOODLE_INTERNAL checks 2017-09-26 23:04:51 +02:00
Eloy Lafuente (stronk7) 4495103f17 Merge branch 'MDL-59645-32-flickr' of git://github.com/mudrd8mz/moodle into MOODLE_32_STABLE 2017-09-26 19:35:39 +02:00
Tim Hunt ce7cb88198 MDL-58790 quiz editing: translate hard-coded new heading string 2017-09-26 11:18:28 +01:00
Juan Leyva 67ad699c28 MDL-60233 mod_assign: Avoid HTML in the item field of external warnings
The item field is defined as PARAM_TEXT (no HTML tags allowed except
for multilang).
Using the s that add quotes to HTML characters we avoid potential Web
Services invalid parameters errors.
2017-09-26 12:13:40 +02:00
Andrew Nicols d94ac2bfbc Merge branch 'MDL-60141-32' of git://github.com/jleyva/moodle into MOODLE_32_STABLE 2017-09-26 15:48:46 +08:00
Jake Dallimore 3a1a441a7b Merge branch 'MDL-60121-multi-enrol-backup-MOODLE_32_STABLE' of https://github.com/mpetrowi/moodle into MOODLE_32_STABLE 2017-09-26 15:25:42 +08:00
Juan Leyva 7b7f45307a MDL-60141 auth_email: Fix sitepolicy field type in get_signup_settings 2017-09-26 09:11:27 +02:00
Simey Lameze 5f3cb3de39 MDL-60052 theme_bootstrapbase: proper handling of large modals 2017-09-26 11:21:28 +08:00
Andrew Nicols 1284339766 Merge branch 'MDL-60052-32' of https://github.com/xow/moodle into MOODLE_32_STABLE 2017-09-26 09:31:38 +08:00
Andrew Nicols b1517ff214 Merge branch 'MOODLE_32_STABLE' of https://github.com/ConnorSheremeta/moodle into MOODLE_32_STABLE 2017-09-26 09:26:34 +08:00
Carson Tam e9f31bb710 MDL-59931 mod_quiz: Fixing incorrect pagination count. 2017-09-25 12:51:58 -07:00
Eloy Lafuente (stronk7) 0c95cbef53 Merge branch 'wip-MDL-60167-32' of git://github.com/marinaglancy/moodle into MOODLE_32_STABLE 2017-09-25 20:19:50 +02:00
Shamim Rezaie c4a970c345 MDL-57228 quiz editing: unit test for the move case 2017-09-25 12:55:27 +01:00
Tim Hunt 0525300ebc MDL-57228 quiz: fix editing when there are one-question sections
Fix based on a patch by Joost van der Borg <j.van.der.borg@ssr.nl>.
2017-09-25 12:55:26 +01:00
Marina Glancy 930ef87ff8 MDL-60167 upgrade: Fix duplicate site registrations 2017-09-24 18:53:23 +08:00
Dan Poltawski 469c46aa3a weekly release 3.2.5+ 2017-09-22 12:43:15 +01:00
Dan Poltawski facf5f3b6f Merge branch 'install_32_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_32_STABLE 2017-09-22 12:43:13 +01:00
David Mudrák f4ef37425a MDL-60210 admin: Check if the site needs upgrade on admin/search.php too
The page admin/search.php is the default administration page in Boost
based themes. It should behave the same as admin/index.php or
my/index.php and check if the site needs upgrade.
2017-09-22 13:24:18 +02:00
Jun Pataleta c27af3af45 Merge branch 'MDL-37810-32-fix' of https://github.com/snake/moodle into MOODLE_32_STABLE 2017-09-22 10:55:06 +08:00
Ryan Wyllie 9648379ea2 MDL-60052 javascript: fix large styling for modals 2017-09-22 10:03:45 +08:00
Damyon Wiese 074034db86 MDL-59220 setuplib: Redirect on https mismatch
When the wwwroot indicates https support and a page is accessed over http,
redirect to the wwwroot. This is a better experience than displaying an error.

Backport of MDL-58318.
2017-09-22 09:48:35 +08:00
AMOS bot 9c65fc25cb Automatically generated installer lang files 2017-09-22 00:08:32 +08:00
AMOS bot 74b092ca47 Automatically generated installer lang files 2017-09-22 00:08:31 +08:00
Jake Dallimore 9cd7403fe6 MDL-37810 roles: fix profile roles logic to include all roles
If the user has the role:assign capability then the list of profile roles
will include any role assigned in the context or above.
2017-09-21 22:27:42 +08:00
AMOS bot e667a98f86 Automatically generated installer lang files 2017-09-21 00:06:31 +08:00
Eloy Lafuente (stronk7) d016049dc9 Merge branch 'MDL-60132-32' of git://github.com/jleyva/moodle into MOODLE_32_STABLE 2017-09-19 22:38:56 +02:00
David Mudrák 82aab5855c MDL-59645 flickrlib: Show debug notice when using legacy authentication 2017-09-19 14:45:44 +02:00
David Mudrák 38bd68868d MDL-59645 portfolio_flickr: Make the Flickr portfolio export work again
The patch modifies the Flickr portfolio to make it use of the new oauth1
based client.
2017-09-19 14:45:44 +02:00
David Mudrák df61d236f5 MDL-59645 repository_flickr: Drop legacy auth tokens and nsids
The values stored in these user preferences were valid for the old
flickr auth mechanism and are not usable any more. The new oauth1 based
version needs to store both the token (in the flickr_access_token
preference) and the token secret (flickr_access_token_secret). The new
version does not need to store the user's nsid.

The cryptic names of these legacy settings are a result of how dealing
with user preferences was originally implemented.
2017-09-19 14:45:44 +02:00
David Mudrák 6c0671bbf0 MDL-59645 repository_flickr: Make the Flickr repository work again
The patch makes the Flickr repository use the new oauth1 based client.
Beside that, other improvements include:

* Does not attempt to guess the photo URL any more. Instead uses
  url_sq and url_o extras of the flickr.photos.search call.
* The photos.search does not return the information about the photo size
  so we set it to null (previously was returned as 'unknown' which made
  it be displayed as zero).
* Does not perform additional API request to obtain the manage URL, uses
  https://www.flickr.com/photos/organize instead.
2017-09-19 14:45:44 +02:00
David Mudrák a7c710c1b8 MDL-59645 oauth1: Implement a new simple Flickr API client
Flickr has switched over to OAuth 1.0 based authentication. This is a
simple client allowing Moodle to perform authenticated calls to the
Flickr API.
2017-09-19 14:45:44 +02:00
David Mudrák a247bf678e MDL-59645 oauth1: Improve reporting of token errors
Provide a more meaningful error message and debuginfo allowing to
diagnose what is going on. In case of flickr, this is typically thrown
when flickr API responses with their "bad, bad panda" HTML page instead
of the expected reply.
2017-09-19 14:45:44 +02:00
David Mudrák c51c6351b3 MDL-59645 oauth1: Pass oauth_callback only to obtain the request token
As per the oauth1 spec, the oauth_callback is supposed to be passed only
when obtaining the initial request token. The client used to append it
automatically to all requests which broke the request signature.
2017-09-19 14:45:44 +02:00
Matt Petro 5b9fc0b69b MDL-60121 enrol: Fix enrol plugin backup
Allow more than one enrol plugin to add backup structure.
2017-09-19 07:05:48 -04:00
Jun Pataleta a1a2903db4 Merge branch 'MDL-60048-32' of https://github.com/Kathrin84/moodle into MOODLE_32_STABLE 2017-09-19 17:21:02 +08:00
Dan Poltawski 821c414049 Merge branch 'MDL-60018-32' of git://github.com/jleyva/moodle into MOODLE_32_STABLE 2017-09-19 07:28:08 +01:00
Eloy Lafuente (stronk7) 2904e5e987 Merge branch 'MDL-60105_32' of git://github.com/dmonllao/moodle into MOODLE_32_STABLE 2017-09-19 01:56:54 +02:00
Eloy Lafuente (stronk7) 2337e280cf Merge branch 'MDL-52131-32' of git://github.com/andrewnicols/moodle into MOODLE_32_STABLE 2017-09-19 01:54:02 +02:00
Eloy Lafuente (stronk7) f5a1435789 Merge branch 'MDL-37810-32' of https://github.com/snake/moodle into MOODLE_32_STABLE 2017-09-19 01:49:20 +02:00
Eloy Lafuente (stronk7) 335f04772b Merge branch 'MDL-53244_32_STABLE' of git://github.com/Chocolate-lightning/moodle into MOODLE_32_STABLE 2017-09-19 01:43:52 +02:00
Jake Dallimore cb617fa262 MDL-37810 roles: added manager case to test_get_user_roles_in_course()
Managers can assign managers, and should be able to see that role on
the course profile page, as a link to the participants page.
2017-09-18 10:22:54 +08:00
Jun Pataleta d19291fbf3 Merge branch 'MDL-59994-32' of git://github.com/lameze/moodle into MOODLE_32_STABLE 2017-09-18 09:09:28 +08:00
Jake Dallimore 7fb6fdf6a7 MDL-37810 roles: get_user_roles_in_course returns all relevant roles
Fixed to return both those roles in the profileroles site policy and
any roles which the current user can assign in the respective context,
meaning a user can see a link to any role they can assign.
2017-09-18 09:01:50 +08:00
Jake Dallimore d4fd2325fe MDL-37810 roles: unit tests for get_profile_roles() 2017-09-18 09:01:50 +08:00
Jake Dallimore d549a9d973 MDL-37810 roles: fix get_profile_roles() so it returns assignable roles 2017-09-18 09:01:50 +08:00
Simey Lameze 437a07a572 MDL-59994 core_competency: improve unit test to cover deleted users 2017-09-18 08:34:33 +08:00
Simey Lameze c225ebf975 MDL-59994 core_competency: dont list competencies from deleted users 2017-09-18 08:34:33 +08:00
Dan Poltawski cc60733069 weekly release 3.2.5+ 2017-09-15 08:49:26 +01:00
Dan Poltawski 7e364756ae Merge branch 'install_32_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_32_STABLE 2017-09-15 08:49:25 +01:00
Kathrin Osswald 43d4117912 MDL-60048 theme_boost: Center logo within the navbar
My solution is to remove the padding that's added within scss/bootstrap/_navbar.scss (line 72)
for the case that a logo (has-logo) is uploaded and displayed within the navbar.
Removing this padding will center the image within the navbar.
2017-09-14 14:01:03 +02:00
Juan Leyva 3a960acf1e MDL-60132 tool_mobile: Handle correctly moodle_url instances
In Moodle there are some functions that can be overridden by themes.
Some themes are returning incorrect value types in those functions
2017-09-14 12:18:08 +02:00
Juan Segarra Montesinos 3e55e065fe MDL-52131 qbehaviour: respect manualcomment format
The format of a manual comment in a question is respected when
the preferred editor is "Plain text area".
2017-09-14 13:31:30 +08:00
Matt Clarkson 856fa58440 MDL-60105 mod_folder: Set timemodified on change
Changes to the folder contents were not resulting in the
timemodied of the folder activity being set. This prevented
global search from picking up the changes.
2017-09-13 13:53:46 +02:00
Matt Clarkson 0a64999259 MDL-60105 search: Fix fatal error
If an indexed file has been modified or deleted the search index
will still reference the old file. Remove the file from search
results until the change has been indexed.
2017-09-13 13:53:46 +02:00
AMOS bot 9f861ddcbb Automatically generated installer lang files 2017-09-13 00:06:59 +08:00
Dan Poltawski dff980ab44 Merge branch 'MDL-60039_32' of git://github.com/dmonllao/moodle into MOODLE_32_STABLE 2017-09-12 11:24:21 +01:00
David Monllao 8aab2713e9 MDL-60039 search: Force messaging search areas to be reindexed 2017-09-12 12:04:47 +02:00
David Monllao f7d3978d8d MDL-60039 messaging: global search index using timeread 2017-09-12 12:01:01 +02:00
Dan Poltawski cc15eb08e7 Merge branch 'MDL-59929_32' of git://github.com/timhunt/moodle into MOODLE_32_STABLE 2017-09-12 10:56:03 +01:00
Eloy Lafuente (stronk7) 75788c63c5 Merge branch 'MDL-60086-32' of https://github.com/snake/moodle into MOODLE_32_STABLE 2017-09-12 09:56:39 +02:00
David Monllao 57d11528b0 Merge branch 'MDL-59399-32' of git://github.com/ryanwyllie/moodle into MOODLE_32_STABLE 2017-09-12 08:12:46 +02:00
David Monllao 52155a2496 Merge branch 'MDL-59867-32' of git://github.com/damyon/moodle into MOODLE_32_STABLE 2017-09-12 07:11:11 +02:00
David Monllao 1b81de7861 Merge branch 'MDL-59879-32' of https://github.com/abias/moodle into MOODLE_32_STABLE 2017-09-12 07:04:58 +02:00
Eloy Lafuente (stronk7) 5258d49a10 Merge branch 'wip-MDL-59808-32' of git://github.com/marinaglancy/moodle into MOODLE_32_STABLE 2017-09-12 00:14:01 +02:00
Eloy Lafuente (stronk7) 7e14be9814 Merge branch 'MDL-60025-32' of git://github.com/jleyva/moodle into MOODLE_32_STABLE 2017-09-11 23:51:12 +02:00
Dan Poltawski df68f1fcbd Merge branch 'MDL-35849-32' of git://github.com/ankitagarwal/moodle into MOODLE_32_STABLE 2017-09-11 14:19:22 +01:00
Jake Dallimore 9b7b9d2740 MDL-60086 travis: Bumping the postgres version to 9.6
The new Travis images don't have 9.1 installed any more.
2017-09-11 14:39:00 +08:00
Jun Pataleta 3b92e304d3 Merge branch 'wip-MDL-55849-32' of git://github.com/abgreeve/moodle into MOODLE_32_STABLE 2017-09-11 13:30:46 +08:00
Adrian Greeve cb9f449c71 MDL-55849 mod_assign: Behat update for group submission reopening. 2017-09-11 12:01:38 +08:00
Adrian Greeve 255ef8e427 MDL-55849 mod_assign: Reopening assignments only increases by one.
Group assignments when being reopened will only increase the
attempt total by one.
2017-09-11 12:01:38 +08:00
Mathew May c84a3c9c40 MDL-53244 login: Add error message for recaptcha 2017-09-08 12:58:11 +12:00
Damyon Wiese 6961e8882d MDL-59867 autocomplete: Prevent duplicate ids.
Rendering a form with 2 autocompletes in it can get messed up because of duplicated ids.
2017-09-07 09:34:04 +08:00
Marina Glancy c079d43dc1 MDL-59808 webservice_rest: comply with restformat argument 2017-09-07 08:34:40 +08:00
Juan Leyva b46369041c MDL-60025 mod_book: Return correct values for chapters update time
Instead returning the time when the chapter was created or modified we
were returning the time when the book was created or modified.
2017-09-06 12:38:34 +02:00
Juan Leyva 51cd0c4072 MDL-60018 mod_chat: Fix chatmethod field type in get_chats_by_courses WS 2017-09-06 12:16:43 +02:00
Marina Glancy def68f84a0 MDL-60033 webservice_xmlrpc: extra escaping in the server URL 2017-09-06 13:44:06 +08:00
Ryan Wyllie ad445893db MDL-59399 atto: make media plugin shortform explandable 2017-09-06 05:28:04 +00:00
Ankit Agarwal fec32f3cd7 MDL-35849 login: Add role alert to error messages
Error messages should be prominent to screen readers as well as visual users,
adding the role alert is recommended way to achieve it for screen readers and this is
also what we do for ->notification apis
2017-09-05 12:50:29 +05:30
Connor Sheremeta bd937195eb MDL-54540 lti: Add allowfullscreen attribute to LTI IFrames 2017-08-29 13:46:34 -06:00
Tim Hunt e3993969d6 MDL-59929 signup: inprove usability when duplicate email entered 2017-08-24 16:33:24 +01:00
Alexander Bias 6eeaf27bd1 MDL-59879 navigation: Add node key to competencies navigation node 2017-08-21 10:55:37 +02:00
206 changed files with 3322 additions and 721 deletions
+2 -5
View File
@@ -52,12 +52,9 @@ matrix:
fast_finish: true
include:
# Run grunt/npm install on lowest supported npm version
- php: 7.1
env: DB=none TASK=GRUNT NVM_VERSION='4'
# Run grunt/npm install on highest version ('node' is an alias for the latest node.js version.)
- php: 7.1
env: DB=none TASK=GRUNT NVM_VERSION='node'
env: DB=none TASK=GRUNT NVM_VERSION='8.9'
exclude:
# MySQL - it's just too slow.
@@ -94,7 +91,7 @@ install:
sudo service postgresql stop
sudo mv /var/lib/postgresql /mnt/ramdisk
sudo ln -s /mnt/ramdisk/postgresql /var/lib/postgresql
sudo service postgresql start 9.1
sudo service postgresql start 9.6
fi
- >
if [ "$TASK" = 'PHPUNIT' ];
+2
View File
@@ -1754,6 +1754,7 @@
<VENDOR name="oracle" version="10.2" />
</DATABASE>
<PHP version="5.6.5" level="required">
<RESTRICT function="restrict_php_version_72" message="unsupportedphpversion72" />
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
@@ -1919,6 +1920,7 @@
<VENDOR name="oracle" version="10.2" />
</DATABASE>
<PHP version="5.6.5" level="required">
<RESTRICT function="restrict_php_version_72" message="unsupportedphpversion72" />
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
+9 -1
View File
@@ -5,11 +5,19 @@
require_once('../config.php');
require_once($CFG->libdir.'/adminlib.php');
redirect_if_major_upgrade_required();
$query = trim(optional_param('query', '', PARAM_NOTAGS)); // Search string
$context = context_system::instance();
$PAGE->set_context($context);
$hassiteconfig = has_capability('moodle/site:config', $context);
if ($hassiteconfig && moodle_needs_upgrading()) {
redirect(new moodle_url('/admin/index.php'));
}
admin_externalpage_setup('search', '', array('query' => $query)); // now hidden page
$adminroot = admin_get_root(); // need all settings here
@@ -55,7 +63,7 @@ if ($errormsg !== '') {
$showsettingslinks = true;
if (has_capability('moodle/site:config', $context)) {
if ($hassiteconfig) {
require_once("admin_settings_search_form.php");
$form = new admin_settings_search_form();
$form->display();
+10 -4
View File
@@ -127,7 +127,7 @@ class api {
'rememberusername' => $CFG->rememberusername,
'authloginviaemail' => $CFG->authloginviaemail,
'registerauth' => $CFG->registerauth,
'forgottenpasswordurl' => $CFG->forgottenpasswordurl,
'forgottenpasswordurl' => clean_param($CFG->forgottenpasswordurl, PARAM_URL), // We may expect a mailto: here.
'authinstructions' => $authinstructions,
'authnoneenabled' => (int) is_enabled_auth('none'),
'enablewebservices' => $CFG->enablewebservices,
@@ -153,10 +153,11 @@ class api {
$settings['launchurl'] = $url->out(false);
}
if ($logourl = $OUTPUT->get_logo_url()) {
// Check that we are receiving a moodle_url object, themes can override get_logo_url and may return incorrect values.
if (($logourl = $OUTPUT->get_logo_url()) && $logourl instanceof moodle_url) {
$settings['logourl'] = $logourl->out(false);
}
if ($compactlogourl = $OUTPUT->get_compact_logo_url()) {
if (($compactlogourl = $OUTPUT->get_compact_logo_url()) && $compactlogourl instanceof moodle_url) {
$settings['compactlogourl'] = $compactlogourl->out(false);
}
@@ -203,12 +204,17 @@ class api {
}
if (empty($section) or $section == 'sitepolicies') {
$settings->sitepolicy = $CFG->sitepolicy;
$settings->disableuserimages = $CFG->disableuserimages;
}
if (empty($section) or $section == 'gradessettings') {
require_once($CFG->dirroot . '/user/lib.php');
$settings->mygradesurl = user_mygrades_url()->out(false);
$settings->mygradesurl = user_mygrades_url();
// The previous function may return moodle_url instances or plain string URLs.
if ($settings->mygradesurl instanceof moodle_url) {
$settings->mygradesurl = $settings->mygradesurl->out(false);
}
}
return $settings;
+1
View File
@@ -23,6 +23,7 @@
*/
namespace tool_mobile;
defined('MOODLE_INTERNAL') || die();
require_once("$CFG->libdir/externallib.php");
+1 -1
View File
@@ -22,7 +22,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['autologinkeygenerationlockout'] = 'Auto-login key generation is blocked because of too many requests within an hour.';
$string['autologinkeygenerationlockout'] = 'Auto-login key generation is blocked. You need to wait 6 minutes between requests.';
$string['autologinnotallowedtoadmins'] = 'Auto-login is not allowed for site admins.';
$string['cachedef_plugininfo'] = 'This stores the list of plugins with mobile addons';
$string['clickheretolaunchtheapp'] = 'Click here if the app does not open automatically.';
+8 -2
View File
@@ -94,12 +94,14 @@ class tool_mobile_external_testcase extends externallib_advanced_testcase {
set_config('typeoflogin', api::LOGIN_VIA_BROWSER, 'tool_mobile');
set_config('logo', 'mock.png', 'core_admin');
set_config('logocompact', 'mock.png', 'core_admin');
set_config('forgottenpasswordurl', 'mailto:fake@email.zy'); // Test old hack.
list($authinstructions, $notusedformat) = external_format_text($authinstructions, FORMAT_MOODLE, $context->id);
$expected['registerauth'] = 'email';
$expected['authinstructions'] = $authinstructions;
$expected['typeoflogin'] = api::LOGIN_VIA_BROWSER;
$expected['launchurl'] = "$CFG->wwwroot/$CFG->admin/tool/mobile/launch.php";
$expected['forgottenpasswordurl'] = ''; // Expect empty when it's not an URL.
if ($logourl = $OUTPUT->get_logo_url()) {
$expected['logourl'] = $logourl->out(false);
@@ -121,6 +123,10 @@ class tool_mobile_external_testcase extends externallib_advanced_testcase {
require_once($CFG->dirroot . '/course/format/lib.php');
$this->resetAfterTest(true);
$mysitepolicy = 'http://mysite.is/policy/';
set_config('sitepolicy', $mysitepolicy);
$result = external::get_config();
$result = external_api::clean_returnvalue(external::get_config_returns(), $result);
@@ -141,6 +147,7 @@ class tool_mobile_external_testcase extends externallib_advanced_testcase {
array('name' => 'numsections', 'value' => course_get_format($SITE)->get_course()->numsections),
array('name' => 'newsitems', 'value' => $SITE->newsitems),
array('name' => 'commentsperpage', 'value' => $CFG->commentsperpage),
array('name' => 'sitepolicy', 'value' => $mysitepolicy),
array('name' => 'disableuserimages', 'value' => $CFG->disableuserimages),
array('name' => 'mygradesurl', 'value' => user_mygrades_url()->out(false)),
);
@@ -150,8 +157,7 @@ class tool_mobile_external_testcase extends externallib_advanced_testcase {
// Change a value and retrieve filtering by section.
set_config('commentsperpage', 1);
$expected[10]['value'] = 1;
unset($expected[11]);
unset($expected[12]);
array_splice($expected, 11);
$result = external::get_config('frontpagesettings');
$result = external_api::clean_returnvalue(external::get_config_returns(), $result);
@@ -22,6 +22,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_templatelibrary;
defined('MOODLE_INTERNAL') || die();
require_once("$CFG->libdir/externallib.php");
+1 -1
View File
@@ -137,7 +137,7 @@ class auth_email_external extends external_api {
new external_value(PARAM_NOTAGS, 'The order of the name fields')
),
'passwordpolicy' => new external_value(PARAM_RAW, 'Password policy', VALUE_OPTIONAL),
'sitepolicy' => new external_value(PARAM_URL, 'Site policy url', VALUE_OPTIONAL),
'sitepolicy' => new external_value(PARAM_RAW, 'Site policy', VALUE_OPTIONAL),
'defaultcity' => new external_value(PARAM_NOTAGS, 'Default city', VALUE_OPTIONAL),
'country' => new external_value(PARAM_ALPHA, 'Default country', VALUE_OPTIONAL),
'profilefields' => new external_multiple_structure(
+1 -1
View File
@@ -119,7 +119,7 @@ $string['didntfindexpiretime'] = 'password_expire() didn\'t find expiration time
$string['didntgetusersfromldap'] = "Did not get any users from LDAP -- error? -- exiting\n";
$string['gotcountrecordsfromldap'] = "Got {\$a} records from LDAP\n";
$string['morethanoneuser'] = 'Strange! More than one user record found in ldap. Only using the first one.';
$string['needbcmath'] = 'You need the BCMath extension to use grace logins with Active Directory';
$string['needbcmath'] = 'You need the BCMath extension to use expired password checking with Active Directory.';
$string['needmbstring'] = 'You need the mbstring extension to change passwords in Active Directory';
$string['nodnforusername'] = 'Error in user_update_password(). No DN for: {$a->username}';
$string['noemail'] = 'Tried to send you an email but failed!';
+9
View File
@@ -136,6 +136,15 @@ abstract class backup implements checksumable {
* Usually same than major release zero version, mainly for informative/historic purposes.
*/
const RELEASE = '3.2';
/**
* Cipher to be used in backup and restore operations.
*/
const CIPHER = 'aes-256-cbc';
/**
* Bytes enforced for key, using the cypher above. Restrictive? Yes, but better than unsafe lengths
*/
const CIPHERKEYLEN = 32;
}
/*
+1 -1
View File
@@ -112,7 +112,7 @@ class cc_forum extends entities {
public function get_topic_data ($instance) {
$topic_data = '';
$topic_data = array();
$topic_file = $this->get_external_xml($instance['resource_indentifier']);
+1 -1
View File
@@ -68,7 +68,7 @@ class cc_quiz extends entities {
$last_question_id = 0;
$last_answer_id = 0;
$instances = '';
$instances = array();
$types = array(MOODLE_TYPE_QUIZ, MOODLE_TYPE_QUESTION_BANK);
+1 -1
View File
@@ -87,7 +87,7 @@ class cc11_basiclti extends entities11 {
public function get_basiclti_data($instance) {
$topic_data = '';
$topic_data = array();
$basiclti_file = $this->get_external_xml($instance['resource_indentifier']);
+1 -1
View File
@@ -111,7 +111,7 @@ class cc11_forum extends entities11 {
public function get_topic_data ($instance) {
$topic_data = '';
$topic_data = array();
$topic_file = $this->get_external_xml($instance['resource_indentifier']);
+1 -1
View File
@@ -82,7 +82,7 @@ class cc11_lti extends entities11 {
public function get_basiclti_data($instance) {
$topic_data = '';
$topic_data = array();
$basiclti_file = $this->get_external_xml($instance['resource_indentifier']);
+1 -1
View File
@@ -68,7 +68,7 @@ class cc11_quiz extends entities11 {
$last_question_id = 0;
$last_answer_id = 0;
$instances = '';
$instances = array();
$types = array(MOODLE_TYPE_QUIZ, MOODLE_TYPE_QUESTION_BANK);
+132
View File
@@ -97,6 +97,138 @@ class base64_encode_final_element extends backup_final_element {
}
}
/**
* Implementation of {@link backup_final_element} that provides symmetric-key AES-256 encryption of contents.
*
* This final element transparently encrypts, for secure storage and transport, any content
* that shouldn't be shown normally in plain text. Usually, passwords or keys that cannot use
* hashing algorithms, although potentially can encrypt any content. All information is encoded
* using base64.
*
* Features:
* - requires openssl extension to work. Without it contents are completely omitted.
* - automatically creates an appropriate default key for the site and stores it into backup_encryptkey config (bas64 encoded).
* - uses a different appropriate init vector for every operation, which is transmited with the encrypted contents.
* - all generated data is base64 encoded for safe transmission.
* - automatically adds "encrypted" attribute for easier detection.
* - implements HMAC for providing integrity.
*
* @copyright 2017 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class encrypted_final_element extends backup_final_element {
/** @var string cypher appropiate raw key for backups in the site. Defaults to backup_encryptkey config. */
protected $key = null;
/**
* Constructor - instantiates a encrypted_final_element, specifying its basic info.
*
* Overridden to automatically add the 'encrypted' attribute if missing.
*
* @param string $name name of the element
* @param array $attributes attributes this element will handle (optional, defaults to null)
*/
public function __construct($name, $attributes = null) {
parent::__construct($name, $attributes);
if (! $this->get_attribute('encrypted')) {
$this->add_attributes('encrypted');
}
}
/**
* Set the encryption key manually, overriding default backup_encryptkey config.
*
* @param string $key key to be used for encrypting. Required to be 256-bit key.
* Use a safe generation technique. See self::generate_encryption_random_key() below.
*/
protected function set_key($key) {
$bytes = strlen($key); // Get key length in bytes.
// Only accept keys with the expected (backup::CIPHERKEYLEN) key length. There are a number of hashing,
// random generators to achieve this esasily, like the one shown below to create the default
// site encryption key and ivs.
if ($bytes !== backup::CIPHERKEYLEN) {
$info = (object)array('expected' => backup::CIPHERKEYLEN, 'found' => $bytes);
throw new base_element_struct_exception('encrypted_final_element incorrect key length', $info);
}
// Everything went ok, store the key.
$this->key = $key;
}
/**
* Set the value of the field.
*
* This method sets the value of the element, encrypted using the specified key for it,
* defaulting to (and generating) backup_encryptkey config. HMAC is used for integrity.
*
* @param string $value plain-text content the will be stored encrypted and encoded.
*/
public function set_value($value) {
// No openssl available, skip this field completely.
if (!function_exists('openssl_encrypt')) {
return;
}
// No hmac available, skip this field completely.
if (!function_exists('hash_hmac')) {
return;
}
// Cypher not available, skip this field completely.
if (!in_array(backup::CIPHER, openssl_get_cipher_methods())) {
return;
}
// Ensure we have a good key, manual or default.
if (empty($this->key)) {
// The key has not been set manually, look for it at config (base64 encoded there).
$enckey = get_config('backup', 'backup_encryptkey');
if ($enckey === false) {
// Has not been set, calculate and save an appropiate random key automatically.
$enckey = base64_encode(self::generate_encryption_random_key(backup::CIPHERKEYLEN));
set_config('backup_encryptkey', $enckey, 'backup');
}
$this->set_key(base64_decode($enckey));
}
// Now we need an iv for this operation.
$iv = self::generate_encryption_random_key(openssl_cipher_iv_length(backup::CIPHER));
// Everything is ready, let's encrypt and prepend the 1-shot iv.
$value = $iv . openssl_encrypt($value, backup::CIPHER, $this->key, OPENSSL_RAW_DATA, $iv);
// Calculate the hmac of the value (iv + encrypted) and prepend it.
$hmac = hash_hmac('sha256', $value, $this->key, true);
$value = $hmac . $value;
// Ready, set the encoded value.
parent::set_value(base64_encode($value));
// Finally, if the field has an "encrypted" attribute, set it to true.
if ($att = $this->get_attribute('encrypted')) {
$att->set_value('true');
}
}
/**
* Generate an appropiate random key to be used for encrypting backup information.
*
* Normally used as site default encryption key (backup_encryptkey config) and also
* for calculating the init vectors.
*
* Note that until PHP 5.6.12 openssl_random_pseudo_bytes() did NOT
* use a "cryptographically strong algorithm" {@link https://bugs.php.net/bug.php?id=70014}
* But it's beyond my crypto-knowledge when it's worth finding a *real* better alternative.
*
* @param int $bytes Number of bytes to determine the key length expected.
*/
protected static function generate_encryption_random_key($bytes) {
return openssl_random_pseudo_bytes($bytes);
}
}
/**
* Implementation of backup_nested_element that provides special handling of files
*
+1 -1
View File
@@ -522,7 +522,7 @@ class backup_enrolments_structure_step extends backup_structure_step {
$enrol->annotate_ids('role', 'roleid');
// Add enrol plugin structure.
$this->add_plugin_structure('enrol', $enrol, false);
$this->add_plugin_structure('enrol', $enrol, true);
return $enrolments;
}
@@ -0,0 +1,116 @@
<?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/>.
/**
* Tests for the handling of encrypted contents in backup and restore.
*
* @package core_backup
* @copyright 2016 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
require_once($CFG->dirroot . '/backup/moodle2/backup_custom_fields.php');
class core_backup_encrypted_content_testscase extends advanced_testcase {
public function setUp() {
if (!function_exists('openssl_encrypt')) {
$this->markTestSkipped('OpenSSL extension is not loaded.');
} else if (!function_exists('hash_hmac')) {
$this->markTestSkipped('Hash extension is not loaded.');
} else if (!in_array(backup::CIPHER, openssl_get_cipher_methods())) {
$this->markTestSkipped('Expected cipher not available: ' . backup::CIPHER);
}
}
public function test_encrypted_final_element() {
$this->resetAfterTest(true);
// Some basic verifications.
$efe = new encrypted_final_element('test', array('encrypted'));
$this->assertInstanceOf('encrypted_final_element', $efe);
$this->assertSame('test', $efe->get_name());
$atts = $efe->get_attributes();
$this->assertCount(1, $atts);
$att = reset($atts);
$this->assertInstanceOf('backup_attribute', $att);
$this->assertSame('encrypted', $att->get_name());
// Using a manually defined (incorrect length) key.
$efe = new encrypted_final_element('test', array('encrypted'));
$key = 'this_in_not_correct_32_byte_key';
try {
set_config('backup_encryptkey', base64_encode($key), 'backup');
$efe->set_value('tiny_secret');
$this->fail('Expecting base_element_struct_exception exception, none happened');
} catch (exception $e) {
$this->assertInstanceOf('base_element_struct_exception', $e);
$this->assertEquals('encrypted_final_element incorrect key length', $e->errorcode);
}
// Using a manually defined (correct length) key.
$efe = new encrypted_final_element('test', array('testattr', 'encrypted'));
$key = hash('md5', 'Moodle rocks and this is not secure key, who cares, it is a test');
set_config('backup_encryptkey', base64_encode($key), 'backup');
$this->assertEmpty($efe->get_value());
$secret = 'This is a secret message that nobody else will be able to read but me 💩 ';
$efe->set_value($secret);
$atts = $efe->get_attributes();
$this->assertCount(2, $atts);
$this->assertArrayHasKey('encrypted', $atts); // We added it explicitly.
$this->assertTrue($atts['encrypted']->is_set());
$this->assertSame('true', $atts['encrypted']->get_value());
$this->assertNotEmpty($efe->get_value());
$this->assertTrue($efe->is_set());
// Get the crypted content and decrypt it manually.
$ctext = $efe->get_value();
$hmaclen = 32; // SHA256 is 32 bytes.
$ivlen = openssl_cipher_iv_length(backup::CIPHER);
list($hmac, $iv, $text) = array_values(unpack("a{$hmaclen}hmac/a{$ivlen}iv/a*text", base64_decode($ctext)));
$this->assertSame(hash_hmac('sha256', $iv . $text, $key, true), $hmac);
$this->assertSame($secret, openssl_decrypt($text, backup::CIPHER, $key, OPENSSL_RAW_DATA, $iv));
// Using the default site-generated key.
$efe = new encrypted_final_element('test', array('testattr'));
$this->assertEmpty($efe->get_value());
$secret = 'This is a secret message that nobody else will be able to read but me 💩 ';
$efe->set_value($secret);
$atts = $efe->get_attributes();
$this->assertCount(2, $atts);
$this->assertArrayHasKey('encrypted', $atts); // Was added automatcally, we did not specify it.
$this->assertTrue($atts['encrypted']->is_set());
$this->assertSame('true', $atts['encrypted']->get_value());
$this->assertNotEmpty($efe->get_value());
$this->assertTrue($efe->is_set());
// Get the crypted content and decrypt it manually.
$ctext = $efe->get_value();
$hmaclen = 32; // SHA256 is 32 bytes.
$ivlen = openssl_cipher_iv_length(backup::CIPHER);
list($hmac, $iv, $text) = array_values(unpack("a{$hmaclen}hmac/a{$ivlen}iv/a*text", base64_decode($ctext)));
$key = base64_decode(get_config('backup', 'backup_encryptkey'));
$this->assertSame(hash_hmac('sha256', $iv . $text, $key, true), $hmac);
$this->assertSame($secret, openssl_decrypt($text, backup::CIPHER, $key, OPENSSL_RAW_DATA, $iv));
}
}
+60
View File
@@ -94,6 +94,66 @@ abstract class restore_step extends base_step {
// Return the passed value with cached offset applied.
return $value + $cache[$this->get_restoreid()];
}
/**
* Returns symmetric-key AES-256 decryption of base64 encoded contents.
*
* This method is used in restore operations to decrypt contents encrypted with
* {@link encrypted_final_element} automatically decoding (base64) and decrypting
* contents using the key stored in backup_encryptkey config.
*
* Requires openssl, cipher availability, and key existence (backup
* automatically sets it if missing). Integrity is provided via HMAC.
*
* @param string $value {@link encrypted_final_element} value to decode and decrypt.
* @return string|null decoded and decrypted value or null if the operation can not be performed.
*/
public function decrypt($value) {
// No openssl available, skip this field completely.
if (!function_exists('openssl_encrypt')) {
return null;
}
// No hash available, skip this field completely.
if (!function_exists('hash_hmac')) {
return null;
}
// Cypher not available, skip this field completely.
if (!in_array(backup::CIPHER, openssl_get_cipher_methods())) {
return null;
}
// Get the decrypt key. Skip if missing.
$key = get_config('backup', 'backup_encryptkey');
if ($key === false) {
return null;
}
// And decode it.
$key = base64_decode($key);
// Arrived here, let's proceed with authentication (provides integrity).
$hmaclen = 32; // SHA256 is 32 bytes.
$ivlen = openssl_cipher_iv_length(backup::CIPHER);
list($hmac, $iv, $text) = array_values(unpack("a{$hmaclen}hmac/a{$ivlen}iv/a*text", base64_decode($value)));
// Verify HMAC matches expectations, skip if not (integrity failed).
if (!hash_equals($hmac, hash_hmac('sha256', $iv . $text, $key, true))) {
return null;
}
// Arrived here, integrity is ok, let's decrypt.
$result = openssl_decrypt($text, backup::CIPHER, $key, OPENSSL_RAW_DATA, $iv);
// For some reason decrypt failed (strange, HMAC check should have deteted it), skip this field completely.
if ($result === false) {
return null;
}
return $result;
}
}
/*
+46
View File
@@ -91,6 +91,52 @@ class backup_step_testcase extends advanced_testcase {
$bc->destroy();
}
/**
* test restore_step class, decrypt method
*/
public function test_restore_step_decrypt() {
$this->resetAfterTest(true);
if (!function_exists('openssl_encrypt')) {
$this->markTestSkipped('OpenSSL extension is not loaded.');
} else if (!function_exists('hash_hmac')) {
$this->markTestSkipped('Hash extension is not loaded.');
} else if (!in_array(backup::CIPHER, openssl_get_cipher_methods())) {
$this->markTestSkipped('Expected cipher not available: ' . backup::CIPHER);
}
$bt = new mock_restore_task_basepath('taskname');
$bs = new mock_restore_structure_step('steptest', null, $bt);
$this->assertTrue(method_exists($bs, 'decrypt'));
// Let's prepare a string for being decrypted.
$secret = 'This is a secret message that nobody else will be able to read but me 💩 ';
$key = hash('md5', 'Moodle rocks and this is not secure key, who cares, it is a test');
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(backup::CIPHER));
$message = $iv . openssl_encrypt($secret, backup::CIPHER, $key, OPENSSL_RAW_DATA, $iv);
$hmac = hash_hmac('sha256', $message, $key, true);
$crypt = base64_encode($hmac . $message);
// Running it without a key configured, returns null.
$this->assertNull($bs->decrypt($crypt));
// Store the key into config.
set_config('backup_encryptkey', base64_encode($key), 'backup');
// Verify decrypt works and returns original.
$this->assertSame($secret, $bs->decrypt($crypt));
// Finally, test the integrity failure detection is working.
// (this can be caused by changed hmac, key or message, in
// this case we are just forcing it via changed hmac).
$hmac = md5($message);
$crypt = base64_encode($hmac . $message);
$this->assertNull($bs->decrypt($crypt));
}
/**
* test backup_structure_step class
*/
@@ -50,7 +50,7 @@ class block_glossary_random extends block_base {
if (empty($this->config->title)) {
$this->title = get_string('pluginname','block_glossary_random');
} else {
$this->title = $this->config->title;
$this->title = format_string($this->config->title, true, ['context' => $this->context]);
}
if (empty($this->config->glossary)) {
+5 -1
View File
@@ -37,7 +37,11 @@ class block_html extends block_base {
}
function specialization() {
$this->title = isset($this->config->title) ? format_string($this->config->title) : format_string(get_string('newhtmlblock', 'block_html'));
if (isset($this->config->title)) {
$this->title = $this->title = format_string($this->config->title, true, ['context' => $this->context]);
} else {
$this->title = get_string('newhtmlblock', 'block_html');
}
}
function instance_allow_multiple() {
+1 -1
View File
@@ -872,7 +872,7 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
$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() < $startdatetime->getTimestamp()) {
if ($expecteddate->getTimestamp() < $startdate->getTimestamp()) {
$expecteddate->add($interval);
$expecteddate->modify('first Monday of this month');
}
+2
View File
@@ -23,6 +23,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once("$CFG->libdir/externallib.php");
class core_cohort_external extends external_api {
+2
View File
@@ -24,6 +24,8 @@
* @since Moodle 2.9
*/
defined('MOODLE_INTERNAL') || die();
require_once("$CFG->libdir/externallib.php");
require_once("$CFG->dirroot/comment/lib.php");
+2 -1
View File
@@ -1349,7 +1349,8 @@ class api {
JOIN {user} u
ON u.id = uc.userid
WHERE (uc.status = :waitingforreview
OR (uc.status = :inreview AND uc.reviewerid = :reviewerid))";
OR (uc.status = :inreview AND uc.reviewerid = :reviewerid))
AND u.deleted = 0";
$ordersql = " ORDER BY c.shortname ASC";
$params = array(
'inreview' => user_competency::STATUS_IN_REVIEW,
+15 -1
View File
@@ -4564,6 +4564,9 @@ class core_competency_api_testcase extends advanced_testcase {
}
public function test_list_user_competencies_to_review() {
global $CFG;
require_once($CFG->dirroot . '/user/lib.php');
$dg = $this->getDataGenerator();
$this->resetAfterTest();
$ccg = $dg->get_plugin_generator('core_competency');
@@ -4580,10 +4583,12 @@ class core_competency_api_testcase extends advanced_testcase {
$u1 = $dg->create_user();
$u2 = $dg->create_user();
$u3 = $dg->create_user();
$f1 = $ccg->create_framework();
$c1 = $ccg->create_competency(['competencyframeworkid' => $f1->get_id()]);
$c2 = $ccg->create_competency(['competencyframeworkid' => $f1->get_id()]);
$c3 = $ccg->create_competency(['competencyframeworkid' => $f1->get_id()]);
$c4 = $ccg->create_competency(['competencyframeworkid' => $f1->get_id()]);
$uc1a = $ccg->create_user_competency(['userid' => $u1->id, 'competencyid' => $c1->get_id(),
'status' => user_competency::STATUS_IDLE]);
$uc1b = $ccg->create_user_competency(['userid' => $u1->id, 'competencyid' => $c2->get_id(),
@@ -4596,14 +4601,23 @@ class core_competency_api_testcase extends advanced_testcase {
'status' => user_competency::STATUS_IDLE]);
$uc2c = $ccg->create_user_competency(['userid' => $u2->id, 'competencyid' => $c3->get_id(),
'status' => user_competency::STATUS_IN_REVIEW]);
$uc3a = $ccg->create_user_competency(['userid' => $u3->id, 'competencyid' => $c4->get_id(),
'status' => user_competency::STATUS_WAITING_FOR_REVIEW]);
// The reviewer can review all plans waiting for review, or in review where they are the reviewer.
$this->setUser($reviewer);
$result = api::list_user_competencies_to_review();
$this->assertEquals(3, $result['count']);
$this->assertEquals(4, $result['count']);
$this->assertEquals($uc2a->get_id(), $result['competencies'][0]->usercompetency->get_id());
$this->assertEquals($uc1b->get_id(), $result['competencies'][1]->usercompetency->get_id());
$this->assertEquals($uc1c->get_id(), $result['competencies'][2]->usercompetency->get_id());
$this->assertEquals($uc3a->get_id(), $result['competencies'][3]->usercompetency->get_id());
// Now, let's delete user 3.
// It should not be listed on user competencies to review any more.
user_delete_user($u3);
$result = api::list_user_competencies_to_review();
$this->assertEquals(3, $result['count']);
// The reviewer cannot view the plans when they do not have the permission in the user's context.
role_assign($roleprohibit, $reviewer->id, context_user::instance($u2->id)->id);
+2
View File
@@ -259,6 +259,8 @@ $CFG->admin = 'admin';
// $CFG->session_memcached_prefix = 'memc.sess.key.';
// $CFG->session_memcached_acquire_lock_timeout = 120;
// $CFG->session_memcached_lock_expire = 7200; // Ignored if PECL memcached is below version 2.2.0
// $CFG->session_memcached_lock_retry_sleep = 150; // Spin-lock retry sleeptime (msec). Only effective
// // for tuning php-memcached 3.0.x (PHP 7)
//
// Redis session handler (requires redis server and redis extension):
// $CFG->session_handler_class = '\core\session\redis';
+3 -1
View File
@@ -256,8 +256,9 @@ class core_course_external extends external_api {
if (!empty($cm->showdescription) or $cm->modname == 'label') {
// We want to use the external format. However from reading get_formatted_content(), $cm->content format is always FORMAT_HTML.
$options = array('noclean' => true);
list($module['description'], $descriptionformat) = external_format_text($cm->content,
FORMAT_HTML, $modcontext->id, $cm->modname, 'intro', $cm->id);
FORMAT_HTML, $modcontext->id, $cm->modname, 'intro', $cm->id, $options);
}
//url of the module
@@ -3072,6 +3073,7 @@ class core_course_external extends external_api {
*/
public static function check_updates($courseid, $tocheck, $filter = array()) {
global $CFG, $DB;
require_once($CFG->dirroot . "/course/lib.php");
$params = self::validate_parameters(
self::check_updates_parameters(),
+2
View File
@@ -24,6 +24,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once("$CFG->libdir/externallib.php");
require_once("$CFG->libdir/filelib.php");
+12 -1
View File
@@ -138,7 +138,8 @@ MathJax.Hub.Config({
// setting. Since it is preferably to always load the secure resource.
$httpurl = get_config('filter_mathjaxloader', 'httpurl');
if ($httpurl !== 'http://cdn.mathjax.org/mathjax/2.6-latest/MathJax.js') {
if ($httpurl !== 'http://cdn.mathjax.org/mathjax/2.6-latest/MathJax.js' &&
$httpurl !== 'http://cdn.mathjax.org/mathjax/2.6.1/MathJax.js') {
// If the http setting has been changed, we make the admin choose the https setting because
// it indicates some sort of custom setup. This will be supported by the release notes.
unset_config('httpsurl', 'filter_mathjaxloader');
@@ -196,5 +197,15 @@ MathJax.Hub.Config({
upgrade_plugin_savepoint(true, 2016120502, 'filter', 'mathjaxloader');
}
if ($oldversion < 2016120503) {
$httpsurl = get_config('filter_mathjaxloader', 'httpsurl');
if (empty($httpsurl)) {
// URL is empty, most likely because of bad upgrade path. See MDL-59780.
set_config('httpsurl', 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js', 'filter_mathjaxloader');
}
upgrade_plugin_savepoint(true, 2016120503, 'filter', 'mathjaxloader');
}
return true;
}
+1 -1
View File
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2016120502;
$plugin->version = 2016120503;
$plugin->requires = 2016112900; // Requires this Moodle version.
$plugin->component= 'filter_mathjaxloader';
+2 -2
View File
@@ -489,7 +489,7 @@ class grading_manager {
* Returns the given method's controller in the gradable area
*
* @param string $method the method name, eg 'rubric' (must be available)
* @return grading_controller
* @return gradingform_controller
*/
public function get_controller($method) {
global $CFG, $DB;
@@ -534,7 +534,7 @@ class grading_manager {
/**
* Returns the controller for the active method if it is available
*
* @return null|grading_controller
* @return null|gradingform_controller
*/
public function get_active_controller() {
if ($gradingmethod = $this->get_active_method()) {
+2
View File
@@ -24,6 +24,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once("$CFG->libdir/externallib.php");
/**
+1 -1
View File
@@ -36,7 +36,7 @@ $string['chooselanguagehead'] = 'Sprache wählen';
$string['chooselanguagesub'] = 'Wählen Sie eine Sprache, die Sie während der Installation verwenden wollen. Die ausgewählte Sprache wird nach der Installation als Standardsprache der Instanz benutzt, aber Sie dürfen die Sprache jederzeit ändern.';
$string['clialreadyconfigured'] = 'Die Datei config.php existiert bereits. Bitte benutzen Sie admin/cli/install_database.php, wenn Sie diese Site installieren möchten.';
$string['clialreadyinstalled'] = 'Die Datei config.php existiert bereits. Bitte benutzen Sie admin/cli/install_database.php, wenn Sie diese Site aktualisieren möchten.';
$string['cliinstallheader'] = 'Installation von Moodle {$a} über die Kommandozeile';
$string['cliinstallheader'] = 'Installation von Moodle {$a} über die Befehlszeile';
$string['databasehost'] = 'Datenbank-Server';
$string['databasename'] = 'Datenbank-Name';
$string['databasetypehead'] = 'Datenbank-Treiber wählen';
+3 -3
View File
@@ -88,9 +88,9 @@ $string['pathsunsecuredataroot'] = 'Andmete juurkataloogi asukoht pole turvaline
$string['pathswrongadmindir'] = 'Halduskataloogi pole olemas';
$string['phpextension'] = '{$a} PHP-laiendus';
$string['phpversion'] = 'PHP versioon';
$string['phpversionhelp'] = '<p>Moodle vajab vähemalt PHP versiooni 4.1.0</p>
<p>Sinu jooksev versioon on {$a}</p>
<p>Sa pead oma PHP-d uuendama või kolima hosti, kus on uuem PHP versioon!</p>';
$string['phpversionhelp'] = '<p>Moodle vajab vähemalt PHP versiooni 5.6.5 või 7.1 (versioonil 7.0.x on mõned mootoripiirangud).</p>
<p>Teie praegune versioon on {$a}.</p>
<p>Peate uuendama oma PHP või kolima hosti, kus on uuem PHP versioon.</p>';
$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
$string['welcomep20'] = 'Teile kuvatakse see leht, kuna olete edukalt oma arvutisse installinud ja
käivitanud paketi <strong>{$a->packname} {$a->packversion}</strong>. Õnnitleme!';
+2 -2
View File
@@ -30,8 +30,8 @@
defined('MOODLE_INTERNAL') || die();
$string['cannotcreatedboninstall'] = '<p>Ezin da datu-basea sortu.<p>
<p>Zehaztutako datu-basea ez da existitzen eta adierazitako erabiltzaileak ez du baimenik datu-basea sortzeko.<p>
$string['cannotcreatedboninstall'] = '<p>Ezin da datu-basea sortu.</p>
<p>Zehaztutako datu-basea ez da existitzen eta adierazitako erabiltzaileak ez du baimenik datu-basea sortzeko.</p>
<p>Guneko kudeatzaileak datu-basearen konfigurazioa egiaztatu behar du.</p>';
$string['cannotcreatelangdir'] = 'Ezin da hizkuntza-direktorioa sortu';
$string['cannotcreatetempdir'] = 'Ezin da temp direktorioa sortu';
+1
View File
@@ -31,6 +31,7 @@
defined('MOODLE_INTERNAL') || die();
$string['language'] = 'Jezik';
$string['moodlelogo'] = 'Moodle logo';
$string['next'] = 'Nastavi';
$string['previous'] = 'Prethodni';
$string['reload'] = 'Učitaj ponovno';
+2 -2
View File
@@ -35,7 +35,7 @@ $string['availablelangs'] = '利用可能な言語パック';
$string['chooselanguagehead'] = '言語を選択してください。';
$string['chooselanguagesub'] = 'インストールにのみ使用する言語を選択してください。この言語はサイトのデフォルト言語としても使用されます。後でサイト言語を変更することができます。';
$string['clialreadyconfigured'] = '設定ファイルconfig.phpはすでに登録されています。このサイトをインストールする場合、admin/cli/install_database.phpを使用してください。';
$string['clialreadyinstalled'] = '設定ファイルconfig.phpはすでに登録されています。このサイトをアップグレードする場合、admin/cli/upgrade.phpを使用してください。';
$string['clialreadyinstalled'] = '設定ファイルconfig.phpはすでに登録されています。このサイトをアップグレードする場合、admin/cli/upgrade.phpを使用してください。';
$string['cliinstallheader'] = 'Moodle {$a} コマンドラインインストールプログラム';
$string['databasehost'] = 'データベースホスト :';
$string['databasename'] = 'データベース名 :';
@@ -57,7 +57,7 @@ $string['memorylimithelp'] = '<p>現在、サーバのPHPメモリ制限が {$a}
<ol>
<li>あなたがリコンパイル可能な場合、PHPを<i>--enable-memory-limit</i>オプションでコンパイルしてください。これにより、Moodle自身がメモリ制限を設定することが可能になります。</li>
<li>あなたがphp.iniファイルにアクセスできる場合、<b>memory_limit</b>設定を40Mのように変更することができます。php.iniファイルにアクセスできない場合、管理者に変更を依頼してください。</li>
<li>いくつかのPHPサーバでは下記の行を含む.htaccessファイルをMoodleディレクトリに作成することができます:
<li>いくつかのPHPサーバでは下記の行を含む.htaccessファイルをMoodleディレクトリに作成することができます:
<blockquote><div>php_value memory_limit 40M</div></blockquote>
<p>しかし、この設定が<b>すべての</b>PHPページの動作を妨げる場合もあります。ページ閲覧中にエラーが表示される場合、.htaccessファイルを削除してください。</p></li>
</ol>';
+1
View File
@@ -40,3 +40,4 @@ $string['cliunknowoption'] = 'Neatpažintos parinktys: {$a} naudokite --žinyno
$string['cliyesnoprompt'] = 'įveskite t (taip) arba n (ne)';
$string['environmentrequireinstall'] = 'turi būti įdiegta ir įjungta';
$string['environmentrequireversion'] = 'būtina naudoti versiją {$a->needed}, o jūs naudojate {$a->current}';
$string['upgradekeyset'] = 'Naujovinimo raktas (palikite tuščią, jei nenorite nustatyti)';
+3 -1
View File
@@ -63,7 +63,9 @@ $string['pathsunsecuredataroot'] = 'Šakninio duomenų katalogo kelias nesaugus'
$string['pathswrongadmindir'] = 'Nėra administratoriaus katalogo';
$string['phpextension'] = '{$a} PHP plėtinys';
$string['phpversion'] = 'PHP versija';
$string['phpversionhelp'] = '<p>„Moodle“ reikalauja, kad PHP versija būtų bent 4.3.0 arba 5.1.0 (5.0.x versijoje yra daug problemų).</p> <p>Dabar naudojate versiją {$a}</p> <p>Turite atnaujinti PHP versiją arba perkelti į pagrindinį kompiuterį, kuriame veikia naujesnė PHP versija!<br /> (Jei naudojate 5.0.x versiją, taip pat galite paleisti senesnę 4.4.x versiją)</p>';
$string['phpversionhelp'] = '<p>„Moodle“ reikalauja, kad PHP versija būtų ne žemesnė 5.6.5 arba 7.1 (7.0.x versijoje yra tam tikrų trūkumų).</p>
<p>Dabar naudojate versiją {$a}</p>
<p>Turite atnaujinti PHP versiją arba perkelti į pagrindinį kompiuterį, kuriame veikia naujesnė PHP versija.</p>';
$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
$string['welcomep20'] = 'Matote šį puslapį, nes į kompiuterį sėkmingai įdiegėte ir paleidote <strong>{$a->packname} {$a->packversion}</strong> paketą. Sveikiname!';
$string['welcomep30'] = 'Šiame <strong>{$a->installername}</strong> leidime yra taikomosios programos, skirtos aplinkai, kurioje veiks <strong>Moodle</strong>, sukurti:';
-1
View File
@@ -30,6 +30,5 @@
defined('MOODLE_INTERNAL') || die();
$string['parentlanguage'] = '';
$string['thisdirection'] = 'ltr';
$string['thislanguage'] = 'Lietuvių';
+34
View File
@@ -0,0 +1,34 @@
<?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['thisdirection'] = 'ltr';
$string['thislanguage'] = 'Māori (Te Reo)';
+3
View File
@@ -37,6 +37,9 @@ $string['cliincorrectvalueerror'] = 'Грешка, погрешна вредно
$string['cliincorrectvalueretry'] = 'Неточни вредност, ве молиме обидете се повторно';
$string['clitypevalue'] = 'впишете вредност';
$string['clitypevaluedefault'] = 'впишете вредност, притиснете Enter за да го користите стандардната вредност ({$a})';
$string['cliunknowoption'] = 'Непрепознаена опција:
{$a}
Ве молиме употребете --help опција.';
$string['cliyesnoprompt'] = 'впишете y (значи да) или n (значи не)';
$string['environmentrequireinstall'] = 'потребно е да се инсталира/овозможи';
$string['environmentrequireversion'] = 'верзијата {$a->needed} е потребна, а вие извршувате {$a->current}';
+3 -3
View File
@@ -35,11 +35,11 @@ $string['cliansweryes'] = 'y';
$string['cliincorrectvalueerror'] = 'Error, valor incorrècta « {$a->value} » pel paramètre « {$a->option} »';
$string['cliincorrectvalueretry'] = 'Valor incorrècta, ensajar tornamai';
$string['clitypevalue'] = 'tipe valor';
$string['clitypevaluedefault'] = 'tipe valor, tapez Entrée per utilizar la valor per defaut ({$a})';
$string['clitypevaluedefault'] = 'tipe valor, picatz Entrada per utilizar la valor per defaut ({$a})';
$string['cliunknowoption'] = 'Options non reconegudas :
{$a}.
Utilisez l\'option --help.';
Utilizatz l\'opcion --help.';
$string['cliyesnoprompt'] = 'Picatz y (per òc) o n (per non)';
$string['environmentrequireinstall'] = 'doit èsser installat e activat';
$string['environmentrequireinstall'] = 'deu èsser installat e activat';
$string['environmentrequireversion'] = 'la version {$a->needed} es requesida ; utilizatz actualament la version {$a->current}';
$string['upgradekeyset'] = 'Metre a jorn la clau (daissar void per la definir pas)';
+6
View File
@@ -72,5 +72,11 @@ $string['welcomep20'] = 'Vedeți această pagină deoarece ați instalat și lan
$string['welcomep30'] = 'Lansarea <strong>{$a->installername}</strong> include aplicațiile
pentru a crea un mediu în care <strong>Moodle</strong> va funcționa, și anume:';
$string['welcomep40'] = 'Pachetul include și <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
$string['welcomep50'] = 'Utilizarea tuturor aplicațiilor din acest pachet este determinată de respectivele lor
licențe. Pachetul complet <strong>{$a->installername}</strong> este
<a href="http://www.opensource.org/docs/definition_plain.html">open source</a> și este distribuit sub licența <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>.';
$string['welcomep60'] = 'Următoarele pagini vă oferă pași ușor de urmat pentru a
configura și seta <strong>Moodle</strong> în computerul dumneavoastră. Puteți accepta setările implicite
sau, opțional, să le modificați pentru a corespunde nevoilor dumneavoastră.';
$string['welcomep70'] = 'Click pe butonul "Next" de mai jos pentru a continua setarea <strong>Moodle</strong>.';
$string['wwwroot'] = 'Adresă Web';
+1
View File
@@ -31,3 +31,4 @@
defined('MOODLE_INTERNAL') || die();
$string['databasename'] = 'Databasens namn';
$string['welcomep50'] = 'Användningen av alla applikationer i detta paket regleras av sina respektive licenser. Det fullständiga paketet <strong>{$a->installername}</strong> är <a href="http://www.opensource.org/docs/definition_plain.html">Öppen källkod</a> och distribueras under <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a> licensen.';
+2 -1
View File
@@ -137,7 +137,7 @@ $string['configallowblockstodock'] = 'If enabled and supported by the selected t
$string['configallowcategorythemes'] = 'If you enable this, then themes can be set at the category level. This will affect all child categories and courses unless they have specifically set their own theme. WARNING: Enabling category themes may affect performance.';
$string['configallowcoursethemes'] = 'If you enable this, then courses will be allowed to set their own themes. Course themes override all other theme choices (site, user, or session themes)';
$string['configallowedemaildomains'] = 'List email domains that are allowed to be disclosed in the "From" section of outgoing email. The default of "Empty" will use the No-reply address for all outgoing email. The use of wildcards is allowed e.g. *.example.com will allow emails sent from any subdomain of example.com, but not example.com itself. This will require separate entry.';
$string['configallowemailaddresses'] = 'If you want to restrict all new email addresses to particular domains, then list them here separated by spaces. All other domains will be rejected. To allow subdomains add the domain with a preceding \'.\'. eg <strong>ourcollege.edu.au .gov.au</strong>';
$string['configallowemailaddresses'] = 'To restrict new email addresses to particular domains, list them here separated by spaces. All other domains will be rejected. To allow subdomains, add the domain with a preceding \'.\'. To allow a root domain together with its subdomains, add the domain twice - once with a preceding \'.\' and once without e.g. .ourcollege.edu.au ourcollege.edu.au.';
$string['configallowguestmymoodle'] = 'If enabled guests can access Dashboard, otherwise guests are redirected to the site front page.';
$string['configallowobjectembed'] = 'As a default security measure, normal users are not allowed to embed multimedia (like Flash) within texts using explicit EMBED and OBJECT tags in their HTML (although it can still be done safely using the mediaplugins filter). If you wish to allow these tags then enable this option.';
$string['configallowoverride'] = 'You can allow people with the roles on the left side to override some of the column roles';
@@ -1148,6 +1148,7 @@ $string['unsupporteddbstorageengine'] = 'The database storage engine being used
$string['unsupporteddbtablerowformat'] = 'Your database has tables using Antelope as the file format. You are recommended to convert the tables to the Barracuda file format. See the documentation <a href="https://docs.moodle.org/en/cli">Administration via command line</a> for details of a tool for converting InnoDB tables to Barracuda.';
$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['unsuspenduser'] = 'Activate user account';
$string['updateaccounts'] = 'Update existing accounts';
$string['updatecomponent'] = 'Update component';
+2
View File
@@ -448,6 +448,8 @@ $string['notlocalisederrormessage'] = '{$a}';
$string['notmemberofgroup'] = 'You are not a member of this course group';
$string['notownerofkey'] = 'You are not owner of this key';
$string['nousers'] = 'No such user!';
$string['oauth1accesstoken'] = 'OAuth 1.0 error: We did not obtain the access token.';
$string['oauth1requesttoken'] = 'OAuth 1.0 error: We did not obtain the request token - the service provider may be temporarily down.';
$string['onlyadmins'] = 'Only administrators can do that';
$string['onlyeditingteachers'] = 'Only editing teachers can do that';
$string['onlyeditown'] = 'You can only edit your own information';
+1 -1
View File
@@ -59,7 +59,7 @@ $string['duplicate_usernames'] = 'We failed to create an index on the columns "m
$string['enabled_for_all'] = '(This service has been enabled for all hosts).';
$string['enterausername'] = 'Please enter a username, or a list of usernames separated by commas.';
$string['error7020'] = 'This error normally occurs if the remote site has created a record for you with the wrong wwwroot, for example, http://yoursite.com instead of http://www.yoursite.com. You should contact the administrator of the remote site with your wwwroot (as specified in config.php) asking her to update her record for your host.';
$string['error7022'] = 'The message you sent to the remote site was encrypted properly, but not signed. This is very unexpected; you should probably file a bug if this occurs (giving as much information as possible about the application versions in question, etc.';
$string['error7022'] = 'The message you sent to the remote site was encrypted properly, but not signed. This is very unexpected; you should probably file a bug if this occurs (giving as much information as possible about the application versions in question etc).';
$string['error7023'] = 'The remote site has tried to decrypt your message with all the keys it has on record for your site. They have all failed. You might be able to fix this problem by manually re-keying with the remote site. This is unlikely to occur unless you\'ve been out of communication with the remote site for a few months.';
$string['error7024'] = 'You send an unencrypted message to the remote site, but the remote site doesn\'t accept unencrypted communication from your site. This is very unexpected; you should probably file a bug if this occurs (giving as much information as possible about the application versions in question, etc.';
$string['error7026'] = 'The key that your message was signed with differs from the key that the remote host has on file for your server. Further, the remote host attempted to fetch your current key and failed to do so. Please manually re-key with the remote host and try again.';
+4 -2
View File
@@ -614,6 +614,8 @@ $string['emaildisplayyes'] = 'Allow everyone to see my email address';
$string['emailenable'] = 'This email address is enabled';
$string['emailenableclick'] = 'Click here to re-enable all email being sent to this address';
$string['emailexists'] = 'This email address is already registered.';
$string['emailexistssignuphint'] = 'Perhaps you created an account in the past? {$a}';
$string['emailexistshintlink'] = 'Recover forgotten username or password';
$string['emailformat'] = 'Email format';
$string['emailcharset'] = 'Email charset';
$string['emailmustbereal'] = 'Note: your email address must be a real one';
@@ -705,7 +707,7 @@ $string['emptydragdropregion'] = 'empty region';
$string['enable'] = 'Enable';
$string['encryptedcode'] = 'Encrypted code';
$string['enddate'] = 'Course end date';
$string['enddate_help'] = 'The course end date is only used for reports. Users can still enter the course after the end date.';
$string['enddate_help'] = 'The course end date is used for determining whether a course should be included in a user\'s list of courses in the navigation. When the end date is past, the course is no longer listed. The course end date may also be used by custom reports. Users can still enter the course after the end date; in other words the date does not restrict access.';
$string['english'] = 'English';
$string['enrolmentmethods'] = 'Enrolment methods';
$string['entercourse'] = 'Click to enter this course';
@@ -970,7 +972,7 @@ $string['choosereportfilter'] = 'Choose a filter for the report';
$string['choosetheme'] = 'Choose theme';
$string['chooseuser'] = 'Choose a user';
$string['courseduration'] = 'Course duration';
$string['courseduration_desc'] = 'The course duration is used to calculate the default course end date. The course end date is only used for reports. Users can still enter the course after the end date.';
$string['courseduration_desc'] = 'The course duration is used to calculate the default course end date. The course end date is used for determining whether a course should be included in a user\'s list of courses. It may also be used by custom reports. Users can still enter the course after the end date.';
$string['eventcontentviewed'] = 'Content viewed';
$string['icqnumber'] = 'ICQ number';
$string['icon'] = 'Icon';
+1 -1
View File
@@ -349,7 +349,7 @@ $string['restore:restoretargetimport'] = 'Restore from files targeted as import'
$string['restore:rolldates'] = 'Allowed to roll activity configuration dates on restore';
$string['restore:uploadfile'] = 'Upload files to backup areas';
$string['restore:userinfo'] = 'Restore user data';
$string['restore:viewautomatedfilearea'] = 'View automated backup area';
$string['restore:viewautomatedfilearea'] = 'Restore courses from automated backups';
$string['risks'] = 'Risks';
$string['roleallowheader'] = 'Allow role:';
$string['roleallowinfo'] = 'Select a role to be added to the list of allowed roles in context "{$a->context}", capability "{$a->cap}":';
+25 -12
View File
@@ -2743,20 +2743,28 @@ function get_component_string($component, $contextlevel) {
/**
* Gets the list of roles assigned to this context and up (parents)
* from the list of roles that are visible on user profile page
* and participants page.
* from the aggregation of:
* a) the list of roles that are visible on user profile page and participants page (profileroles setting) and;
* b) if applicable, those roles that are assigned in the context.
*
* @param context $context
* @return array
*/
function get_profile_roles(context $context) {
global $CFG, $DB;
if (empty($CFG->profileroles)) {
return array();
// If the current user can assign roles, then they can see all roles on the profile and participants page,
// provided the roles are assigned to at least 1 user in the context. If not, only the policy-defined roles.
if (has_capability('moodle/role:assign', $context)) {
$rolesinscope = array_keys(get_all_roles($context));
} else {
$rolesinscope = empty($CFG->profileroles) ? [] : array_map('trim', explode(',', $CFG->profileroles));
}
list($rallowed, $params) = $DB->get_in_or_equal(explode(',', $CFG->profileroles), SQL_PARAMS_NAMED, 'a');
if (empty($rolesinscope)) {
return [];
}
list($rallowed, $params) = $DB->get_in_or_equal($rolesinscope, SQL_PARAMS_NAMED, 'a');
list($contextlist, $cparams) = $DB->get_in_or_equal($context->get_parent_context_ids(true), SQL_PARAMS_NAMED, 'p');
$params = array_merge($params, $cparams);
@@ -2815,18 +2823,23 @@ function get_roles_used_in_context(context $context) {
*/
function get_user_roles_in_course($userid, $courseid) {
global $CFG, $DB;
if (empty($CFG->profileroles)) {
return '';
}
if ($courseid == SITEID) {
$context = context_system::instance();
} else {
$context = context_course::instance($courseid);
}
// If the current user can assign roles, then they can see all roles on the profile and participants page,
// provided the roles are assigned to at least 1 user in the context. If not, only the policy-defined roles.
if (has_capability('moodle/role:assign', $context)) {
$rolesinscope = array_keys(get_all_roles($context));
} else {
$rolesinscope = empty($CFG->profileroles) ? [] : array_map('trim', explode(',', $CFG->profileroles));
}
if (empty($rolesinscope)) {
return '';
}
list($rallowed, $params) = $DB->get_in_or_equal(explode(',', $CFG->profileroles), SQL_PARAMS_NAMED, 'a');
list($rallowed, $params) = $DB->get_in_or_equal($rolesinscope, SQL_PARAMS_NAMED, 'a');
list($contextlist, $cparams) = $DB->get_in_or_equal($context->get_parent_context_ids(true), SQL_PARAMS_NAMED, 'p');
$params = array_merge($params, $cparams);
+6 -16
View File
@@ -3645,16 +3645,11 @@ class admin_setting_configmixedhostiplist extends admin_setting_configtextarea {
$entries = explode("\n", $data);
foreach ($entries as $key => $entry) {
$entry = trim($entry);
// This regex matches any string which:
// a) contains at least one non-ascii unicode character AND
// b) starts with a-zA-Z0-9 or any non-ascii unicode character AND
// c) ends with a-zA-Z0-9 or any non-ascii unicode character
// d) contains a-zA-Z0-9, hyphen, dot or any non-ascii unicode characters in the middle.
if (preg_match('/^(?=[^\x00-\x7f])([^\x00-\x7f]|[a-zA-Z0-9])([^\x00-\x7f]|[a-zA-Z0-9-.])*([^\x00-\x7f]|[a-zA-Z0-9])$/',
$entry)) {
// This regex matches any string that has non-ascii character.
if (preg_match('/[^\x00-\x7f]/', $entry)) {
// If we can convert the unicode string to an idn, do so.
// Otherwise, leave the original unicode string alone and let the validation function handle it (it will fail).
$val = idn_to_ascii($entry);
$val = idn_to_ascii($entry, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
$entries[$key] = $val ? $val : $entry;
}
}
@@ -3672,7 +3667,7 @@ class admin_setting_configmixedhostiplist extends admin_setting_configtextarea {
foreach ($entries as $key => $entry) {
$entry = trim($entry);
if (strpos($entry, 'xn--') !== false) {
$entries[$key] = idn_to_utf8($entry);
$entries[$key] = idn_to_utf8($entry, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
}
}
return implode("\n", $entries);
@@ -8445,16 +8440,11 @@ class admin_setting_enablemobileservice extends admin_setting_configcheckbox {
* @return string XHTML
*/
public function output_html($data, $query='') {
global $CFG, $OUTPUT;
global $OUTPUT;
$html = parent::output_html($data, $query);
if ((string)$data === $this->yes) {
require_once($CFG->dirroot . "/lib/filelib.php");
$curl = new curl();
$httpswwwroot = str_replace('http:', 'https:', $CFG->wwwroot); //force https url
$curl->head($httpswwwroot . "/login/index.php");
$info = $curl->get_info();
if (empty($info['http_code']) or ($info['http_code'] >= 400)) {
if (!is_https()) {
$html .= $OUTPUT->notification(get_string('nohttpsformobilewarning', 'admin'));
}
}
File diff suppressed because one or more lines are too long
+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;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").addClass("form-control"),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)).addClass("custom-select"),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){var g=[e.attr("data-itemid"),e.attr("data-component"),e.attr("data-itemtype")].join("-");M.util.js_pending(g),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,h){var i=a(f);c.replaceNode(e,i,h),i.find("[data-inplaceeditablelink]").focus(),i.trigger({type:"updated",ajaxreturn:b,oldvalue:d}),M.util.js_complete(g)})},fail:function(b){var c=a.Event("updatefailed",{exception:b,newvalue:f});l(e),M.util.js_complete(g),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").addClass("form-control"),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)).addClass("custom-select"),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
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/modal_events","core/modal","core/modal_save_cancel","core/modal_confirm","core/modal_cancel","core/templates","core/notification","core/custom_interaction_events"],function(a,b,c,d,e,f,g,h,i){var j={DEFAULT:"core/modal",SAVE_CANCEL:"core/modal_save_cancel",CONFIRM:"core/modal_confirm",CANCEL:"core/modal_cancel"},k={DEFAULT:c,SAVE_CANCEL:d,CONFIRM:e,CANCEL:f},l={DEFAULT:"DEFAULT",SAVE_CANCEL:"SAVE_CANCEL",CONFIRM:"CONFIRM",CANCEL:"CANCEL"},m=function(a,c){"undefined"!=typeof c&&(i.define(c,[i.events.activate]),c.on(i.events.activate,function(b,c){a.then(function(a){return a.show(),a}),c.originalEvent.preventDefault()}),a.then(function(a){return a.getRoot().on(b.hidden,function(){c.focus()}),a}))},n=function(b,c){c=a(c);var d=k[b],e=new d(c);return e},o=function(b,c){var d=j[b],e=g.render(d,{}).then(function(c){var d=a(c);return n(b,d)}).fail(h.exception);return m(e,c),e},p=function(a,b){var c=a.type||l.DEFAULT,d=!!a.large;return l[c]||(c=l.DEFAULT),o(c,b).then(function(b){return"undefined"!=typeof a.title&&b.setTitle(a.title),"undefined"!=typeof a.body&&b.setBody(a.body),"undefined"!=typeof a.footer&&b.setFooter(a.footer),d&&b.setLarge(),b})};return{create:p,types:l}});
define(["jquery","core/modal_events","core/modal","core/modal_save_cancel","core/modal_confirm","core/modal_cancel","core/templates","core/notification","core/custom_interaction_events"],function(a,b,c,d,e,f,g,h,i){var j={DEFAULT:"core/modal",SAVE_CANCEL:"core/modal_save_cancel",CONFIRM:"core/modal_confirm",CANCEL:"core/modal_cancel"},k={DEFAULT:c,SAVE_CANCEL:d,CONFIRM:e,CANCEL:f},l={DEFAULT:"DEFAULT",SAVE_CANCEL:"SAVE_CANCEL",CONFIRM:"CONFIRM",CANCEL:"CANCEL"},m=function(a,c){if("undefined"!=typeof c){var d=null;i.define(c,[i.events.activate]),c.on(i.events.activate,function(b,c){d=b.currentTarget,a.then(function(a){return a.show(),a}),c.originalEvent.preventDefault()}),a.then(function(a){return a.getRoot().on(b.hidden,function(){null!==d&&d.focus()}),a})}},n=function(b,c){c=a(c);var d=k[b],e=new d(c);return e},o=function(b,c){var d=j[b],e=g.render(d,{}).then(function(c){var d=a(c);return n(b,d)}).fail(h.exception);return m(e,c),e},p=function(a,b){var c=a.type||l.DEFAULT,d=!!a.large;return l[c]||(c=l.DEFAULT),o(c,b).then(function(b){return"undefined"!=typeof a.title&&b.setTitle(a.title),"undefined"!=typeof a.body&&b.setBody(a.body),"undefined"!=typeof a.footer&&b.setFooter(a.footer),d&&b.setLarge(),b})};return{create:p,types:l}});
+10 -4
View File
@@ -37,6 +37,8 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
UP: 38
};
var uniqueId = $.now();
/**
* Make an item in the selection list "active".
*
@@ -774,11 +776,15 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
// Find or generate some ids.
var state = {
selectId: originalSelect.attr('id'),
inputId: 'form_autocomplete_input-' + $.now(),
suggestionsId: 'form_autocomplete_suggestions-' + $.now(),
selectionId: 'form_autocomplete_selection-' + $.now(),
downArrowId: 'form_autocomplete_downarrow-' + $.now()
inputId: 'form_autocomplete_input-' + uniqueId,
suggestionsId: 'form_autocomplete_suggestions-' + uniqueId,
selectionId: 'form_autocomplete_selection-' + uniqueId,
downArrowId: 'form_autocomplete_downarrow-' + uniqueId
};
// Increment the unique counter so we don't get duplicates ever.
uniqueId++;
options.multiple = originalSelect.attr('multiple');
var originalLabel = $('[for=' + state.selectId + ']');
+9
View File
@@ -60,6 +60,13 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str'
};
var updateValue = function(mainelement, value) {
var pendingId = [
mainelement.attr('data-itemid'),
mainelement.attr('data-component'),
mainelement.attr('data-itemtype'),
].join('-');
M.util.js_pending(pendingId);
addSpinner(mainelement);
ajax
.call([{
@@ -77,6 +84,7 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str'
templates.replaceNode(mainelement, newelement, js);
newelement.find('[data-inplaceeditablelink]').focus();
newelement.trigger({type: 'updated', ajaxreturn: data, oldvalue: oldvalue});
M.util.js_complete(pendingId);
});
},
fail: function(ex) {
@@ -85,6 +93,7 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str'
newvalue: value
});
removeSpinner(mainelement);
M.util.js_complete(pendingId);
mainelement.trigger(e);
if (!e.isDefaultPrevented()) {
notification.exception(ex);
+105 -17
View File
@@ -50,6 +50,12 @@ define(['jquery', 'core/templates', 'core/notification', 'core/key_codes',
*/
var backdropPromise;
/**
* A counter that gets incremented for each modal created. This can be
* used to generate unique values for the modals.
*/
var modalCounter = 0;
/**
* Constructor for the Modal.
*
@@ -66,6 +72,7 @@ define(['jquery', 'core/templates', 'core/notification', 'core/key_codes',
this.isAttached = false;
this.bodyJS = null;
this.footerJS = null;
this.modalCount = modalCounter++;
if (!this.root.is(SELECTORS.CONTAINER)) {
Notification.exception({message: 'Element is not a modal container'});
@@ -212,6 +219,16 @@ define(['jquery', 'core/templates', 'core/notification', 'core/key_codes',
return this.footer;
};
/**
* Get the unique modal count.
*
* @method getModalCount
* @return {int}
*/
Modal.prototype.getModalCount = function() {
return this.modalCount;
};
/**
* Set the modal title element.
*
@@ -249,25 +266,96 @@ define(['jquery', 'core/templates', 'core/notification', 'core/key_codes',
// Just set the value if it's a string.
body.html(value);
} else {
var jsPendingId = 'amd-modal-js-pending-id-' + this.getModalCount();
M.util.js_pending(jsPendingId);
// Otherwise we assume it's a promise to be resolved with
// html and javascript.
Templates.render(TEMPLATES.LOADING, {}).done(function(html) {
body.html(html);
var contentPromise = null;
body.css('overflow', 'hidden');
value.done(function(html, js) {
if (value.state() == 'pending') {
// We're still waiting for the body promise to resolve so
// let's show a loading icon.
body.animate({height: '100px'}, 150);
body.html('');
contentPromise = Templates.render(TEMPLATES.LOADING, {})
.then(function(html) {
var loadingIcon = $(html).hide();
body.html(loadingIcon);
loadingIcon.fadeIn(150);
// We only want the loading icon to fade out
// when the content for the body has finished
// loading.
return $.when(loadingIcon.promise(), value);
})
.then(function(loadingIcon) {
// Once the content has finished loading and
// the loading icon has been shown then we can
// fade the icon away to reveal the content.
return loadingIcon.fadeOut(100).promise();
})
.then(function() {
return value;
});
} else {
// The content is already loaded so let's just display
// it to the user. No need for a loading icon.
contentPromise = value;
}
// Now we can actually display the content.
contentPromise.then(function(html, js) {
var result = null;
if (this.isVisible()) {
// If the modal is visible then we should display
// the content gracefully for the user.
body.css('opacity', 0);
var currentHeight = body.innerHeight();
body.html(html);
// We need to clear any height values we've set here
// in order to measure the height of the content being
// added. This then allows us to animate the height
// transition.
body.css('height', '');
var newHeight = body.innerHeight();
body.css('height', currentHeight + 'px');
result = body.animate(
{height: newHeight + 'px', opacity: 1},
{duration: 150, queue: false}
).promise();
} else {
// Since the modal isn't visible we can just immediately
// set the content. No need to animate it.
body.html(html);
}
if (js) {
if (this.isAttached) {
// If we're in the DOM then run the JS immediately.
Templates.runTemplateJS(js);
} else {
// Otherwise cache it to be run when we're attached.
this.bodyJS = js;
}
if (js) {
if (this.isAttached) {
// If we're in the DOM then run the JS immediately.
Templates.runTemplateJS(js);
} else {
// Otherwise cache it to be run when we're attached.
this.bodyJS = js;
}
}.bind(this));
}.bind(this));
}
return result;
}.bind(this))
.fail(Notification.exception)
.always(function() {
// When we're done displaying all of the content we need
// to clear the custom values we've set here.
body.css('height', '');
body.css('overflow', '');
body.css('opacity', '');
M.util.js_complete(jsPendingId);
return;
})
.fail(Notification.exception);
}
};
@@ -320,7 +408,7 @@ define(['jquery', 'core/templates', 'core/notification', 'core/key_codes',
return;
}
this.getRoot().addClass('large');
this.getModal().addClass('modal-lg');
};
/**
@@ -330,7 +418,7 @@ define(['jquery', 'core/templates', 'core/notification', 'core/key_codes',
* @return {bool}
*/
Modal.prototype.isLarge = function() {
return this.getRoot().hasClass('large');
return this.getModal().hasClass('modal-lg');
};
/**
@@ -343,7 +431,7 @@ define(['jquery', 'core/templates', 'core/notification', 'core/key_codes',
return;
}
this.getRoot().removeClass('large');
this.getModal().removeClass('modal-lg');
};
/**
@@ -353,7 +441,7 @@ define(['jquery', 'core/templates', 'core/notification', 'core/key_codes',
* @return {bool}
*/
Modal.prototype.isSmall = function() {
return !this.getRoot().hasClass('large');
return !this.getModal().hasClass('modal-lg');
};
/**
+7 -1
View File
@@ -60,8 +60,11 @@ define(['jquery', 'core/modal_events', 'core/modal', 'core/modal_save_cancel', '
*/
var setUpTrigger = function(modalPromise, triggerElement) {
if (typeof triggerElement != 'undefined') {
// The element that actually shows the modal.
var actualTriggerElement = null;
CustomEvents.define(triggerElement, [CustomEvents.events.activate]);
triggerElement.on(CustomEvents.events.activate, function(e, data) {
actualTriggerElement = e.currentTarget;
modalPromise.then(function(modal) {
modal.show();
@@ -72,7 +75,10 @@ define(['jquery', 'core/modal_events', 'core/modal', 'core/modal_save_cancel', '
modalPromise.then(function(modal) {
modal.getRoot().on(ModalEvents.hidden, function() {
triggerElement.focus();
// Focus on the trigger element that actually launched the modal.
if (actualTriggerElement !== null) {
actualTriggerElement.focus();
}
});
return modal;
+3 -1
View File
@@ -845,7 +845,9 @@ function signup_validate_data($data, $files) {
$errors['email'] = get_string('invalidemail');
} else if ($DB->record_exists('user', array('email' => $data['email']))) {
$errors['email'] = get_string('emailexists').' <a href="forgot_password.php">'.get_string('newpassword').'?</a>';
$errors['email'] = get_string('emailexists') . ' ' .
get_string('emailexistssignuphint', 'moodle',
html_writer::link(new moodle_url('/login/forgot_password.php'), get_string('emailexistshintlink')));
}
if (empty($data['email2'])) {
$errors['email2'] = get_string('missingemail');
@@ -128,6 +128,8 @@ XPATH
]) = %locator%] |
.//div[contains(concat(' ', normalize-space(@class), ' '), ' yui-dialog ') and
normalize-space(descendant::div[@class='hd']) = %locator%]
|
.//div[@data-region='modal' and descendant::*[@data-region='title'] = %locator%]
XPATH
, 'list_item' => <<<XPATH
.//li[contains(normalize-space(.), %locator%) and not(.//li[contains(normalize-space(.), %locator%)])]
+17 -1
View File
@@ -70,7 +70,23 @@ class user_login_failed extends base {
public function get_description() {
// Note that username could be any random user input.
$username = s($this->other['username']);
return "Login failed for the username '{$username}' for the reason with id '{$this->other['reason']}'.";
$reasonid = $this->other['reason'];
$loginfailed = 'Login failed for user';
switch ($reasonid){
case 1:
return $loginfailed." '{$username}'. User does not exist (error ID '{$reasonid}').";
case 2:
return $loginfailed." '{$username}'. User is suspended (error ID '{$reasonid}').";
case 3:
return $loginfailed." '{$username}'. Most likely the password did not match (error ID '{$reasonid}').";
case 4:
return $loginfailed." '{$username}'. User is locked out (error ID '{$reasonid}').";
case 5:
return $loginfailed." '{$username}'. User is not authorised (error ID '{$reasonid}').";
default:
return $loginfailed." '{$username}', error ID '{$reasonid}'.";
}
}
/**
+35 -3
View File
@@ -36,18 +36,29 @@ defined('MOODLE_INTERNAL') || die();
class memcached extends handler {
/** @var string $savepath save_path string */
protected $savepath;
/** @var array $servers list of servers parsed from save_path */
protected $servers;
/** @var string $prefix session key prefix */
protected $prefix;
/** @var int $acquiretimeout how long to wait for session lock */
protected $acquiretimeout = 120;
/**
* @var int $lockexpire how long to wait before expiring the lock so that other requests
* may continue execution, ignored if PECL memcached is below version 2.2.0.
*/
protected $lockexpire = 7200;
/**
* @var integer $lockretrysleep Used for memcached 3.x (PHP7), the amount of time to
* sleep between attempts to acquire the session lock. Mimics the deprecated config
* memcached.sess_lock_wait.
*/
protected $lockretrysleep = 150;
/**
* Create new instance of handler.
*/
@@ -79,6 +90,10 @@ class memcached extends handler {
if (!empty($CFG->session_memcached_lock_expire)) {
$this->lockexpire = (int)$CFG->session_memcached_lock_expire;
}
if (!empty($CFG->session_memcached_lock_retry_sleep)) {
$this->lockretrysleep = (int)$CFG->session_memcached_lock_retry_sleep;
}
}
/**
@@ -134,15 +149,32 @@ class memcached extends handler {
ini_set('session.save_path', $this->savepath);
ini_set('memcached.sess_prefix', $this->prefix);
ini_set('memcached.sess_locking', '1'); // Locking is required!
ini_set('memcached.sess_lock_expire', $this->lockexpire);
// Try to configure lock and expire timeouts - ignored if memcached is before version 2.2.0.
if (version_compare($version, '3.0.0-dev') >= 0) {
ini_set('memcached.sess_lock_wait_max', $this->acquiretimeout * 1000);
// With memcached 3.x (PHP 7) we configure the max retries to make and the time to sleep between each retry.
// There are two sleep config values, an initial and a max value.
// After each attempt the memcached module adjusts the sleep value to be the lesser of the configured max
// value, or 2X the previous value.
// With default memcached.ini configs (5, 1s, 2s) the result is only 5 attempts to lock over 9 sec.
// To mimic the behavior of the 2.2.x module so we get more attempts and much more frequently, config both
// sleep values to the old default value of 150 msec (making it constant) and calculate number of retries
// using the existing Moodle config $CFG->session_memcached_acquire_lock_timeout.
// Doing this so admins configure session lock attempt timeout in familiar terms, and more straight-forward
// to detect if lock attempt timeout has occurred in start().
// If _min and _max values are not equal, the actual lock acquire timeout will not be the expected
// configured value in $CFG->session_memcached_acquire_lock_timeout; this will cause session data loss when
// failure to acquire the lock is not detected.
ini_set('memcached.sess_lock_wait_min', $this->lockretrysleep);
ini_set('memcached.sess_lock_wait_max', $this->lockretrysleep);
ini_set('memcached.sess_lock_retries', (int)(($this->acquiretimeout * 1000) / $this->lockretrysleep) + 1);
} else {
// With memcached 2.2.x we configure max time to attempt lock, and accept default value (in memcached.ini)
// for sleep time between each attempt (usually 150 msec), then memcached calculates the max number of
// retries to make.
ini_set('memcached.sess_lock_max_wait', $this->acquiretimeout);
}
ini_set('memcached.sess_lock_expire', $this->lockexpire);
}
/**
+30 -1
View File
@@ -2576,7 +2576,12 @@ function xmldb_main_upgrade($oldversion) {
['hub', '%' . $DB->sql_like_escape('_' . $cleanoldhuburl)]);
foreach ($entries as $entry) {
$newname = substr($entry->name, 0, -strlen($cleanoldhuburl)) . $cleannewhuburl;
$DB->update_record('config_plugins', ['id' => $entry->id, 'name' => $newname]);
try {
$DB->update_record('config_plugins', ['id' => $entry->id, 'name' => $newname]);
} catch (dml_exception $e) {
// Entry with new name already exists, remove the one with an old name.
$DB->delete_records('config_plugins', ['id' => $entry->id]);
}
}
// Update published courses.
@@ -2602,5 +2607,29 @@ function xmldb_main_upgrade($oldversion) {
upgrade_main_savepoint(true, 2016120504.08);
}
if ($oldversion < 2016120505.01) {
// Force all messages to be reindexed.
set_config('core_message_message_sent_lastindexrun', '0', 'core_search');
set_config('core_message_message_received_lastindexrun', '0', 'core_search');
// Main savepoint reached.
upgrade_main_savepoint(true, 2016120505.01);
}
if ($oldversion < 2016120505.04) {
// Remove duplicate registrations.
$newhuburl = "https://moodle.net";
$registrations = $DB->get_records('registration_hubs', ['huburl' => $newhuburl], 'confirmed DESC, id ASC');
if (count($registrations) > 1) {
$reg = array_shift($registrations);
$DB->delete_records_select('registration_hubs', 'huburl = ? AND id <> ?', [$newhuburl, $reg->id]);
}
// Main savepoint reached.
upgrade_main_savepoint(true, 2016120505.04);
}
return true;
}
+9 -1
View File
@@ -176,6 +176,8 @@ class mysqli_native_moodle_database extends moodle_database {
$result = $this->mysqli->query($sql);
$this->query_end($result);
if ($rec = $result->fetch_assoc()) {
// MySQL 8 BC: information_schema.* returns the fields in upper case.
$rec = array_change_key_case($rec, CASE_LOWER);
$engine = $rec['engine'];
}
$result->close();
@@ -248,6 +250,8 @@ class mysqli_native_moodle_database extends moodle_database {
$result = $this->mysqli->query($sql);
$this->query_end($result);
if ($rec = $result->fetch_assoc()) {
// MySQL 8 BC: information_schema.* returns the fields in upper case.
$rec = array_change_key_case($rec, CASE_LOWER);
$collation = $rec['collation_name'];
}
$result->close();
@@ -309,10 +313,12 @@ class mysqli_native_moodle_database extends moodle_database {
$result = $this->mysqli->query($sql);
$this->query_end($result);
if ($rec = $result->fetch_assoc()) {
// MySQL 8 BC: information_schema.* returns the fields in upper case.
$rec = array_change_key_case($rec, CASE_LOWER);
if (isset($table)) {
$rowformat = $rec['row_format'];
} else {
$rowformat = $rec['Value'];
$rowformat = $rec['value'];
}
}
$result->close();
@@ -691,6 +697,8 @@ class mysqli_native_moodle_database extends moodle_database {
if ($result->num_rows > 0) {
// standard table exists
while ($rawcolumn = $result->fetch_assoc()) {
// MySQL 8 BC: information_schema.* returns the fields in upper case.
$rawcolumn = array_change_key_case($rawcolumn, CASE_LOWER);
$info = (object)$this->get_column_info((object)$rawcolumn);
$structure[$info->name] = new database_column_info($info);
}
@@ -956,4 +956,4 @@ Y.namespace('M.atto_media').Button = Y.Base.create('button', Y.M.editor_atto.Edi
});
}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]});
}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin", "moodle-form-shortforms"]});
File diff suppressed because one or more lines are too long
@@ -956,4 +956,4 @@ Y.namespace('M.atto_media').Button = Y.Base.create('button', Y.M.editor_atto.Edi
});
}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]});
}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin", "moodle-form-shortforms"]});
@@ -1,7 +1,8 @@
{
"moodle-atto_media-button": {
"requires": [
"moodle-editor_atto-plugin"
"moodle-editor_atto-plugin",
"moodle-form-shortforms"
]
}
}
+11
View File
@@ -1593,3 +1593,14 @@ function restrict_php_version(&$result, $version) {
function restrict_php_version_71(&$result) {
return restrict_php_version($result, '7.1');
}
/**
* Check if the current PHP version is greater than or equal to
* PHP version 7.2.
*
* @param object $result an environment_results instance
* @return bool result of version check
*/
function restrict_php_version_72(&$result) {
return restrict_php_version($result, '7.2');
}
+253
View File
@@ -0,0 +1,253 @@
<?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/>.
/**
* Provides {@link flickr_client} class.
*
* @package core
* @copyright 2017 David Mudrák <david@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir.'/oauthlib.php');
/**
* Simple Flickr API client implementing the features needed by Moodle
*
* @copyright 2017 David Mudrak <david@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class flickr_client extends oauth_helper {
/**
* Base URL for Flickr OAuth 1.0 API calls.
*/
const OAUTH_ROOT = 'https://www.flickr.com/services/oauth';
/**
* Base URL for Flickr REST API calls.
*/
const REST_ROOT = 'https://api.flickr.com/services/rest';
/**
* Base URL for Flickr Upload API call.
*/
const UPLOAD_ROOT = 'https://up.flickr.com/services/upload/';
/**
* Set up OAuth and initialize the client.
*
* The callback URL specified here will override the one specified in the
* auth flow defined at Flickr Services.
*
* @param string $consumerkey
* @param string $consumersecret
* @param moodle_url|string $callbackurl
*/
public function __construct($consumerkey, $consumersecret, $callbackurl = '') {
parent::__construct([
'api_root' => self::OAUTH_ROOT,
'oauth_consumer_key' => $consumerkey,
'oauth_consumer_secret' => $consumersecret,
'oauth_callback' => $callbackurl,
]);
}
/**
* Temporarily store the request token secret in the session.
*
* The request token secret is returned by the oauth request_token method.
* It needs to be stored in the session before the user is redirected to
* the Flickr to authorize the client. After redirecting back, this secret
* is used for exchanging the request token with the access token.
*
* The identifiers help to avoid collisions between multiple calls to this
* method from different plugins in the same session. They are used as the
* session cache identifiers. Provide an associative array identifying the
* particular method call. At least, the array must contain the 'caller'
* with the caller's component name. Use additional items if needed.
*
* @param array $identifiers Identification of the call
* @param string $secret
*/
public function set_request_token_secret(array $identifiers, $secret) {
if (empty($identifiers) || empty($identifiers['caller'])) {
throw new coding_exception('Invalid call identification');
}
$cache = cache::make_from_params(cache_store::MODE_SESSION, 'core', 'flickrclient', $identifiers);
$cache->set('request_token_secret', $secret);
}
/**
* Returns previously stored request token secret.
*
* See {@link self::set_request_token_secret()} for more details on the
* $identifiers argument.
*
* @param array $identifiers Identification of the call
* @return string|bool False on error, string secret otherwise.
*/
public function get_request_token_secret(array $identifiers) {
if (empty($identifiers) || empty($identifiers['caller'])) {
throw new coding_exception('Invalid call identification');
}
$cache = cache::make_from_params(cache_store::MODE_SESSION, 'core', 'flickrclient', $identifiers);
return $cache->get('request_token_secret');
}
/**
* Call a Flickr API method.
*
* @param string $function API function name like 'flickr.photos.getSizes' or just 'photos.getSizes'
* @param array $params Additional API call arguments.
* @param string $method HTTP method to use (GET or POST).
* @return object|bool Response as returned by the Flickr or false on invalid authentication
*/
public function call($function, array $params = [], $method = 'GET') {
if (strpos($function, 'flickr.') !== 0) {
$function = 'flickr.'.$function;
}
$params['method'] = $function;
$params['format'] = 'json';
$params['nojsoncallback'] = 1;
$rawresponse = $this->request($method, self::REST_ROOT, $params);
$response = json_decode($rawresponse);
if (!is_object($response) || !isset($response->stat)) {
throw new moodle_exception('flickr_api_call_failed', 'core_error', '', $rawresponse);
}
if ($response->stat === 'ok') {
return $response;
} else if ($response->stat === 'fail' && $response->code == 98) {
// Authentication failure, give the caller a chance to re-authenticate.
return false;
} else {
throw new moodle_exception('flickr_api_call_failed', 'core_error', '', $response);
}
return $response;
}
/**
* Return the URL to fetch the given photo from.
*
* Flickr photos are distributed via farm servers staticflickr.com in
* various sizes (resolutions). The method tries to find the source URL of
* the photo in the highest possible resolution. Results are cached so that
* we do not need to query the Flickr API over and over again.
*
* @param string $photoid Flickr photo identifier
* @return string URL
*/
public function get_photo_url($photoid) {
$cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'core', 'flickrclient');
$url = $cache->get('photourl_'.$photoid);
if ($url === false) {
$response = $this->call('photos.getSizes', ['photo_id' => $photoid]);
// Sizes are returned from smallest to greatest.
if (!empty($response->sizes->size) && is_array($response->sizes->size)) {
while ($bestsize = array_pop($response->sizes->size)) {
if (isset($bestsize->source)) {
$url = $bestsize->source;
break;
}
}
}
}
if ($url === false) {
throw new repository_exception('cannotdownload', 'repository');
} else {
$cache->set('photourl_'.$photoid, $url);
}
return $url;
}
/**
* Upload a photo from Moodle file pool to Flickr.
*
* Optional meta information are title, description, tags, is_public,
* is_friend, is_family, safety_level, content_type and hidden.
* See {@link https://www.flickr.com/services/api/upload.api.html}.
*
* Upload can't be asynchronous because then the query would not return the
* photo ID which we need to add the photo to a photoset (album)
* eventually.
*
* @param stored_file $photo stored in Moodle file pool
* @param array $meta optional meta information
* @return int|bool photo id, false on authentication failure
*/
public function upload(stored_file $photo, array $meta = []) {
$args = [
'title' => isset($meta['title']) ? $meta['title'] : null,
'description' => isset($meta['description']) ? $meta['description'] : null,
'tags' => isset($meta['tags']) ? $meta['tags'] : null,
'is_public' => isset($meta['is_public']) ? $meta['is_public'] : 0,
'is_friend' => isset($meta['is_friend']) ? $meta['is_friend'] : 0,
'is_family' => isset($meta['is_family']) ? $meta['is_family'] : 0,
'safety_level' => isset($meta['safety_level']) ? $meta['safety_level'] : 1,
'content_type' => isset($meta['content_type']) ? $meta['content_type'] : 1,
'hidden' => isset($meta['hidden']) ? $meta['hidden'] : 2,
];
$this->sign_secret = $this->consumer_secret.'&'.$this->access_token_secret;
$params = $this->prepare_oauth_parameters(self::UPLOAD_ROOT, ['oauth_token' => $this->access_token] + $args, 'POST');
$params['photo'] = $photo;
$response = $this->http->post(self::UPLOAD_ROOT, $params);
if ($response) {
$xml = simplexml_load_string($response);
if ((string)$xml['stat'] === 'ok') {
return (int)$xml->photoid;
} else if ((string)$xml['stat'] === 'fail' && (int)$xml->err['code'] == 98) {
// Authentication failure.
return false;
} else {
throw new moodle_exception('flickr_upload_failed', 'core_error', '',
['code' => (int)$xml->err['code'], 'message' => (string)$xml->err['msg']]);
}
} else {
throw new moodle_exception('flickr_upload_error', 'core_error', '', null, $response);
}
}
}
+6
View File
@@ -25,6 +25,8 @@
* ChangeLog:
* 1. upload() method uses Moodle stored_file
* 2. upload() method supports all params provided by http://www.flickr.com/services/api/upload.api.html
* 3. auth() method shows debugging warning as this library cannot be used any
* more for calling Flickr API that requires authentication.
*
* @package moodlecore
* @subpackage 3rd-party
@@ -240,6 +242,10 @@ class phpFlickr {
function auth ($perms = "write", $remember_uri = true)
{
debugging('The flickrlib.php cannot be used for authenticated Flickr API calls.
Flickr does not support their legacy auth API any more. Use the new flickrclient.php instead.');
// Redirects to Flickr's authentication piece if there is no valid token.
// If remember_uri is set to false, the callback script (included) will
// redirect to its default page.
+1 -1
View File
@@ -58,7 +58,7 @@ class MoodleQuickForm_editor extends HTML_QuickForm_element implements templatab
/** @var array options provided to initalize filepicker */
protected $_options = array('subdirs' => 0, 'maxbytes' => 0, 'maxfiles' => 0, 'changeformat' => 0,
'areamaxbytes' => FILE_AREA_MAX_BYTES_UNLIMITED, 'context' => null, 'noclean' => 0, 'trusttext' => 0,
'return_types' => 7, 'enable_filemanagement' => true);
'return_types' => 7, 'enable_filemanagement' => true, 'autosave' => true);
// $_options['return_types'] = FILE_INTERNAL | FILE_EXTERNAL | FILE_REFERENCE
/** @var array values for editor */
+13
View File
@@ -448,4 +448,17 @@ class google_oauth extends oauth2_client {
$this->header = array();
$this->response = array();
}
/**
* Make a HTTP request, we override the parents because we do not
* want to send accept headers (this was a change in the parent class and we want to keep the old behaviour).
*
* @param string $url The URL to request
* @param array $options
* @param mixed $acceptheader Not used.
* @return bool
*/
protected function request($url, $options = array(), $acceptheader = 'application/json') {
return parent::request($url, $options, false);
}
}
+4 -3
View File
@@ -2448,8 +2448,8 @@ class global_navigation extends navigation_node {
$reporttab = $usercoursenode->add(get_string('activityreports'));
$reports = get_plugin_list_with_function('report', 'extend_navigation_user', 'lib.php');
foreach ($reports as $reportfunction) {
$reportfunctions = get_plugin_list_with_function('report', 'extend_navigation_user', 'lib.php');
foreach ($reportfunctions as $reportfunction) {
$reportfunction($reporttab, $user, $usercourse);
}
@@ -2715,7 +2715,8 @@ class global_navigation extends navigation_node {
// Just a link to course competency.
$title = get_string('competencies', 'core_competency');
$path = new moodle_url("/admin/tool/lp/coursecompetencies.php", array('courseid' => $course->id));
$coursenode->add($title, $path, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/competencies', ''));
$coursenode->add($title, $path, navigation_node::TYPE_SETTING, null, 'competencies',
new pix_icon('i/competencies', ''));
}
if ($navoptions->grades) {
$url = new moodle_url('/grade/report/index.php', array('id'=>$course->id));
+22 -16
View File
@@ -184,9 +184,6 @@ class oauth_helper {
$oauth_params['oauth_nonce'] = $this->get_nonce();
$oauth_params['oauth_timestamp'] = $this->get_timestamp();
$oauth_params['oauth_consumer_key'] = $this->consumer_key;
if (!empty($this->oauth_callback)) {
$oauth_params['oauth_callback'] = $this->oauth_callback->out(false);
}
$oauth_params['oauth_signature_method'] = 'HMAC-SHA1';
$oauth_params['oauth_signature'] = $this->sign($http_method, $url, $oauth_params, $this->sign_secret);
return $oauth_params;
@@ -221,23 +218,25 @@ class oauth_helper {
*/
public function request_token() {
$this->sign_secret = $this->consumer_secret.'&';
$params = $this->prepare_oauth_parameters($this->request_token_api, array(), 'GET');
if (empty($this->oauth_callback)) {
$params = [];
} else {
$params = ['oauth_callback' => $this->oauth_callback->out(false)];
}
$params = $this->prepare_oauth_parameters($this->request_token_api, $params, 'GET');
$content = $this->http->get($this->request_token_api, $params, $this->http_options);
// Including:
// oauth_token
// oauth_token_secret
$result = $this->parse_result($content);
if (empty($result['oauth_token'])) {
throw new moodle_exception('Error while requesting an oauth token');
}
// build oauth authrize url
if (!empty($this->oauth_callback)) {
// url must be rawurlencode
$result['authorize_url'] = $this->authorize_url . '?oauth_token='.$result['oauth_token'].'&oauth_callback='.rawurlencode($this->oauth_callback->out(false));
} else {
// no callback
$result['authorize_url'] = $this->authorize_url . '?oauth_token='.$result['oauth_token'];
throw new moodle_exception('oauth1requesttoken', 'core_error', '', null, $content);
}
// Build oauth authorize url.
$result['authorize_url'] = $this->authorize_url . '?oauth_token='.$result['oauth_token'];
return $result;
}
@@ -266,6 +265,11 @@ class oauth_helper {
unset($params['oauth_callback']);
$content = $this->http->post($this->access_token_api, $params, $this->http_options);
$keys = $this->parse_result($content);
if (empty($keys['oauth_token']) || empty($keys['oauth_token_secret'])) {
throw new moodle_exception('oauth1accesstoken', 'core_error', '', null, $content);
}
$this->set_access_token($keys['oauth_token'], $keys['oauth_token_secret']);
return $keys;
}
@@ -542,9 +546,10 @@ abstract class oauth2_client extends curl {
*
* @param string $url The URL to request
* @param array $options
* @param mixed $acceptheader mimetype (as string) or false to skip sending an accept header.
* @return bool
*/
protected function request($url, $options = array()) {
protected function request($url, $options = array(), $acceptheader = 'application/json') {
$murl = new moodle_url($url);
if ($this->accesstoken) {
@@ -556,8 +561,9 @@ abstract class oauth2_client extends curl {
}
}
// Force JSON format content in response.
$this->setHeader('Accept: application/json');
if ($acceptheader) {
$this->setHeader('Accept: ' . $acceptheader);
}
return parent::request($murl->out(false), $options);
}
+1 -1
View File
@@ -242,7 +242,7 @@ abstract class base_testcase extends PHPUnit_Framework_TestCase {
}
} // match by exact string
else {
if ($node->getAttribute($name) != $value) {
if ($node->getAttribute($name) !== (string) $value) {
$invalid = true;
}
}
+3
View File
@@ -272,6 +272,9 @@ class phpunit_util extends testing_util {
// Reset the log manager cache.
get_log_manager(true);
// Reset user agent.
core_useragent::instance(true, null);
// verify db writes just in case something goes wrong in reset
if (self::$lastdbwrites != $DB->perf_get_writes()) {
error_log('Unexpected DB writes in phpunit_util::reset_all_data()');
+19
View File
@@ -662,4 +662,23 @@ class core_phpunit_advanced_testcase extends advanced_testcase {
$this->assertSame('en_AU.UTF-8', setlocale(LC_TIME, 0));
}
}
/**
* This test sets a user agent and makes sure that it is cleared when the test is reset.
*/
public function test_it_resets_useragent_after_test() {
$this->resetAfterTest();
$fakeagent = 'New user agent set.';
// Sanity check: it should not be set when test begins.
self::assertFalse(core_useragent::get_user_agent_string(), 'It should not be set at first.');
// Set a fake useragent and check it was set properly.
core_useragent::instance(true, $fakeagent);
self::assertSame($fakeagent, core_useragent::get_user_agent_string(), 'It should be the forced agent.');
// Reset test data and ansure the useragent was cleaned.
self::resetAllData(false);
self::assertFalse(core_useragent::get_user_agent_string(), 'It should not be set again, data was reset.');
}
}
+5 -1
View File
@@ -904,7 +904,11 @@ function initialise_fullme() {
// (That is, the Moodle server uses http, with an external box translating everything to https).
if (empty($CFG->sslproxy)) {
if ($rurl['scheme'] === 'http' and $wwwroot['scheme'] === 'https') {
print_error('sslonlyaccess', 'error');
if (defined('REQUIRE_CORRECT_ACCESS') && REQUIRE_CORRECT_ACCESS) {
print_error('sslonlyaccess', 'error');
} else {
redirect($CFG->wwwroot, get_string('wwwrootmismatch', 'error', $CFG->wwwroot), 3);
}
}
} else {
if ($wwwroot['scheme'] !== 'https') {
+1 -1
View File
@@ -29,7 +29,7 @@
}
}}
{{^disabled}}
<a href="{{url}}" class="{{classes}}"{{#attributes}} {{name}}={{#quote}}{{value}}{{/quote}}{{/attributes}} {{#showtext}}aria-labelledby="actionmenuaction-{{instance}}"{{/showtext}}>{{#icon}}{{>core/pix_icon}}{{/icon}}{{#showtext}}<span class="menu-action-text" id="actionmenuaction-{{instance}}">{{{text}}}</span>{{/showtext}}</a>
<a href="{{url}}" class="{{classes}}" {{#attributes}}{{name}}={{#quote}}{{value}}{{/quote}} {{/attributes}}{{#showtext}}aria-labelledby="actionmenuaction-{{instance}}"{{/showtext}}>{{#icon}}{{>core/pix_icon}}{{/icon}}{{#showtext}}<span class="menu-action-text" id="actionmenuaction-{{instance}}">{{{text}}}</span>{{/showtext}}</a>
{{/disabled}}
{{#disabled}}
<span class="currentlink" role="menuitem">{{#icon}}{{>core/pix_icon}}{{/icon}}{{{text}}}</span>
+1 -1
View File
@@ -57,7 +57,7 @@
<div class="subcontent loginsub">
{{#error}}
<div class="loginerrors">
<div class="loginerrors" role="alert">
<a href="#" id="loginerrormessage" class="accesshide">{{error}}</a>
{{{errorformatted}}}
</div>
+160
View File
@@ -1537,6 +1537,7 @@ class core_accesslib_testcase extends advanced_testcase {
$teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'), '*', MUST_EXIST);
$studentrole = $DB->get_record('role', array('shortname'=>'student'), '*', MUST_EXIST);
$managerrole = $DB->get_record('role', array('shortname' => 'manager'), '*', MUST_EXIST);
$course = $this->getDataGenerator()->create_course();
$coursecontext = context_course::instance($course->id);
$teacherrename = (object)array('roleid'=>$teacherrole->id, 'name'=>'Učitel', 'contextid'=>$coursecontext->id);
@@ -1545,6 +1546,7 @@ class core_accesslib_testcase extends advanced_testcase {
$roleids = explode(',', $CFG->profileroles); // Should include teacher and student in new installs.
$this->assertTrue(in_array($teacherrole->id, $roleids));
$this->assertTrue(in_array($studentrole->id, $roleids));
$this->assertFalse(in_array($managerrole->id, $roleids));
$user1 = $this->getDataGenerator()->create_user();
role_assign($teacherrole->id, $user1->id, $coursecontext->id);
@@ -1552,6 +1554,8 @@ class core_accesslib_testcase extends advanced_testcase {
$user2 = $this->getDataGenerator()->create_user();
role_assign($studentrole->id, $user2->id, $coursecontext->id);
$user3 = $this->getDataGenerator()->create_user();
$user4 = $this->getDataGenerator()->create_user();
role_assign($managerrole->id, $user4->id, $coursecontext->id);
$roles = get_user_roles_in_course($user1->id, $course->id);
$this->assertEquals(1, preg_match_all('/,/', $roles, $matches));
@@ -1563,6 +1567,25 @@ class core_accesslib_testcase extends advanced_testcase {
$roles = get_user_roles_in_course($user3->id, $course->id);
$this->assertSame('', $roles);
// Managers should be able to see a link to their own role type, given they can assign it in the context.
$this->setUser($user4);
$roles = get_user_roles_in_course($user4->id, $course->id);
$this->assertNotEmpty($roles);
$this->assertEquals(1, count(explode(',', $roles)));
$this->assertTrue(strpos($roles, role_get_name($managerrole, $coursecontext)) !== false);
// Managers should see 2 roles if viewing a user who has been enrolled as a student and a teacher in the course.
$roles = get_user_roles_in_course($user1->id, $course->id);
$this->assertEquals(2, count(explode(',', $roles)));
$this->assertTrue(strpos($roles, role_get_name($studentrole, $coursecontext)) !== false);
$this->assertTrue(strpos($roles, role_get_name($teacherrole, $coursecontext)) !== false);
// Students should not see the manager role if viewing a manager's profile.
$this->setUser($user2);
$roles = get_user_roles_in_course($user4->id, $course->id);
$this->assertEmpty($roles); // Should see 0 roles on the manager's profile.
$this->assertFalse(strpos($roles, role_get_name($managerrole, $coursecontext)) !== false);
}
/**
@@ -3134,6 +3157,143 @@ class core_accesslib_testcase extends advanced_testcase {
$this->assertTrue(array_key_exists($student->id, $users));
$this->assertFalse(array_key_exists($guest->id, $users));
}
/**
* Test the get_profile_roles() function.
*/
public function test_get_profile_roles() {
global $DB;
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$coursecontext = context_course::instance($course->id);
// Assign a student role.
$studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
$user1 = $this->getDataGenerator()->create_user();
role_assign($studentrole->id, $user1->id, $coursecontext);
// Assign an editing teacher role.
$teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST);
$user2 = $this->getDataGenerator()->create_user();
role_assign($teacherrole->id, $user2->id, $coursecontext);
// Create a custom role that can be assigned at course level, but don't assign it yet.
create_role('Custom role', 'customrole', 'Custom course role');
$customrole = $DB->get_record('role', array('shortname' => 'customrole'), '*', MUST_EXIST);
set_role_contextlevels($customrole->id, [CONTEXT_COURSE]);
allow_assign($teacherrole->id, $customrole->id); // Allow teacher to assign the role in the course.
// Set the site policy 'profileroles' to show student, teacher and non-editing teacher roles (i.e. not the custom role).
$neteacherrole = $DB->get_record('role', array('shortname' => 'teacher'), '*', MUST_EXIST);
set_config('profileroles', "{$studentrole->id}, {$teacherrole->id}, {$neteacherrole->id}");
// A student in the course (given they can't assign roles) should see those roles which are:
// - listed in the 'profileroles' site policy AND
// - are assigned in the course context (or parent contexts).
// In this case, the non-editing teacher role is not assigned and should not be returned.
$expected = [
$teacherrole->id => (object) [
'id' => $teacherrole->id,
'name' => '',
'shortname' => $teacherrole->shortname,
'sortorder' => $teacherrole->sortorder,
'coursealias' => null
],
$studentrole->id => (object) [
'id' => $studentrole->id,
'name' => '',
'shortname' => $studentrole->shortname,
'sortorder' => $studentrole->sortorder,
'coursealias' => null
]
];
$this->setUser($user1);
$this->assertEquals($expected, get_profile_roles($coursecontext));
// An editing teacher should also see only 2 roles at this stage as only 2 roles are assigned: 'teacher' and 'student'.
$this->setUser($user2);
$this->assertEquals($expected, get_profile_roles($coursecontext));
// Assign a custom role in the course.
$user3 = $this->getDataGenerator()->create_user();
role_assign($customrole->id, $user3->id, $coursecontext);
// Confirm that the teacher can see the custom role now that it's assigned.
$expectedteacher = [
$teacherrole->id => (object) [
'id' => $teacherrole->id,
'name' => '',
'shortname' => $teacherrole->shortname,
'sortorder' => $teacherrole->sortorder,
'coursealias' => null
],
$studentrole->id => (object) [
'id' => $studentrole->id,
'name' => '',
'shortname' => $studentrole->shortname,
'sortorder' => $studentrole->sortorder,
'coursealias' => null
],
$customrole->id => (object) [
'id' => $customrole->id,
'name' => 'Custom role',
'shortname' => $customrole->shortname,
'sortorder' => $customrole->sortorder,
'coursealias' => null
]
];
$this->setUser($user2);
$this->assertEquals($expectedteacher, get_profile_roles($coursecontext));
// And that the student can't, because the role isn't included in the 'profileroles' site policy.
$expectedstudent = [
$teacherrole->id => (object) [
'id' => $teacherrole->id,
'name' => '',
'shortname' => $teacherrole->shortname,
'sortorder' => $teacherrole->sortorder,
'coursealias' => null
],
$studentrole->id => (object) [
'id' => $studentrole->id,
'name' => '',
'shortname' => $studentrole->shortname,
'sortorder' => $studentrole->sortorder,
'coursealias' => null
]
];
$this->setUser($user1);
$this->assertEquals($expectedstudent, get_profile_roles($coursecontext));
// If we have no roles listed in the site policy, the teacher should be able to see the assigned roles.
$expectedteacher = [
$studentrole->id => (object) [
'id' => $studentrole->id,
'name' => '',
'shortname' => $studentrole->shortname,
'sortorder' => $studentrole->sortorder,
'coursealias' => null
],
$customrole->id => (object) [
'id' => $customrole->id,
'name' => 'Custom role',
'shortname' => $customrole->shortname,
'sortorder' => $customrole->sortorder,
'coursealias' => null
],
$teacherrole->id => (object) [
'id' => $teacherrole->id,
'name' => '',
'shortname' => $teacherrole->shortname,
'sortorder' => $teacherrole->sortorder,
'coursealias' => null
],
];
set_config('profileroles', "");
$this->setUser($user2);
$this->assertEquals($expectedteacher, get_profile_roles($coursecontext));
}
}
/**
+54
View File
@@ -323,4 +323,58 @@ class core_admintree_testcase extends advanced_testcase {
$setting->write_setting('/mm/nn');
$this->assertSame('', get_config('abc_cde', 'execpath'));
}
/**
* Test setting for blocked hosts
*
* For testing the admin settings element only. Test for blocked hosts functionality can be found
* in lib/tests/curl_security_helper_test.php
*/
public function test_mixedhostiplist() {
$this->resetAfterTest();
$adminsetting = new admin_setting_configmixedhostiplist('abc_cde/hostiplist', 'some desc', '', '');
// Test valid settings.
$validsimplesettings = [
'localhost',
"localhost\n127.0.0.1",
'192.168.10.1',
'0:0:0:0:0:0:0:1',
'::1',
'fe80::',
'231.54.211.0/20',
'fe80::/64',
'231.3.56.10-20',
'fe80::1111-bbbb',
'*.example.com',
'*.sub.example.com',
];
foreach ($validsimplesettings as $setting) {
$errormessage = $adminsetting->write_setting($setting);
$this->assertEmpty($errormessage, $errormessage);
$this->assertSame($setting, get_config('abc_cde', 'hostiplist'));
$this->assertSame($setting, $adminsetting->get_setting());
}
// Test valid international site names.
$valididnsettings = [
'правительство.рф' => 'xn--80aealotwbjpid2k.xn--p1ai',
'faß.de' => 'xn--fa-hia.de',
'ß.ß' => 'xn--zca.xn--zca',
'*.tharkûn.com' => '*.xn--tharkn-0ya.com',
];
foreach ($valididnsettings as $setting => $encodedsetting) {
$errormessage = $adminsetting->write_setting($setting);
$this->assertEmpty($errormessage, $errormessage);
$this->assertSame($encodedsetting, get_config('abc_cde', 'hostiplist'));
$this->assertSame($setting, $adminsetting->get_setting());
}
// Invalid settings.
$this->assertEquals('These entries are invalid: nonvalid site name', $adminsetting->write_setting('nonvalid site name'));
$this->assertEquals('Empty lines are not valid', $adminsetting->write_setting("localhost\n"));
}
}
+1 -8
View File
@@ -51,14 +51,7 @@ class behat_forms extends behat_base {
* @param string $button
*/
public function press_button($button) {
// Ensures the button is present.
$buttonnode = $this->find_button($button);
// Focus on button to ensure it is in viewport, before pressing it.
if ($this->running_javascript()) {
$buttonnode->focus();
}
$buttonnode->press();
$this->execute('behat_general::i_click_on', [$button, 'button']);
}
/**
+1 -2
View File
@@ -3243,8 +3243,7 @@ class text_progress_trace extends progress_trace {
* @return void Output is echo'd
*/
public function output($message, $depth = 0) {
echo str_repeat(' ', $depth), $message, "\n";
flush();
mtrace(str_repeat(' ', $depth) . $message);
}
}
+2 -2
View File
@@ -130,10 +130,10 @@ class login_signup_form extends moodleform implements renderable, templatable {
$challenge_field = $this->_form->_submitValues['recaptcha_challenge_field'];
$response_field = $this->_form->_submitValues['recaptcha_response_field'];
if (true !== ($result = $recaptcha_element->verify($challenge_field, $response_field))) {
$errors['recaptcha'] = $result;
$errors['recaptcha_element'] = get_string('incorrectpleasetryagain', 'auth');
}
} else {
$errors['recaptcha'] = get_string('missingrecaptchachallengefield');
$errors['recaptcha_element'] = get_string('missingrecaptchachallengefield');
}
}
+2 -2
View File
@@ -47,8 +47,8 @@ class message_received extends base_message {
// We don't want to index messages received from noreply and support users.
$params = array('modifiedfrom' => $modifiedfrom, 'noreplyuser' => \core_user::NOREPLY_USER,
'supportuser' => \core_user::SUPPORT_USER);
return $DB->get_recordset_select('message_read', 'timecreated >= :modifiedfrom AND
useridto != :noreplyuser AND useridto != :supportuser', $params, 'timecreated ASC');
return $DB->get_recordset_select('message_read', 'timeread >= :modifiedfrom AND
useridto != :noreplyuser AND useridto != :supportuser', $params, 'timeread ASC');
}
/**
+2 -2
View File
@@ -46,8 +46,8 @@ class message_sent extends base_message {
// We don't want to index messages sent by noreply and support users.
$params = array('modifiedfrom' => $modifiedfrom, 'noreplyuser' => \core_user::NOREPLY_USER,
'supportuser' => \core_user::SUPPORT_USER);
return $DB->get_recordset_select('message_read', 'timecreated >= :modifiedfrom AND
useridfrom != :noreplyuser AND useridfrom != :supportuser', $params, 'timecreated ASC');
return $DB->get_recordset_select('message_read', 'timeread >= :modifiedfrom AND
useridfrom != :noreplyuser AND useridfrom != :supportuser', $params, 'timeread ASC');
}
/**
+2
View File
@@ -24,6 +24,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once("$CFG->libdir/externallib.php");
require_once($CFG->dirroot . "/message/lib.php");
@@ -35,7 +35,7 @@ $string['configairnotifiermobileappname'] = 'The Mobile app unique identifier (u
$string['deletecheckdevicename'] = 'Delete your device: {$a->name}';
$string['deletedevice'] = 'Delete the device. Note that an app can register the device again. If the device keeps reappearing, disable it.';
$string['devicetoken'] = 'Device token';
$string['errorretrievingkey'] = 'An error occurred while retrieving key. Your Moodle site must be registered with Moodle.org to use this service. You may need to re-register to update your details there.';
$string['errorretrievingkey'] = 'An error occurred while retrieving the access key. Your site must be registered to use this service. If your site is already registered, please try updating your registration.';
$string['keyretrievedsuccessfully'] = 'Key retrieved successfully';
$string['nodevices'] = 'No registered devices. Devices will automatically appear after you install the Moodle Mobile app and add this site.';
$string['nopermissiontomanagedevices'] = 'You don\'t have permission to manage devices.';
@@ -53,33 +53,21 @@
{{$headertext}}{{#str}} messages, message {{/str}}{{/headertext}}
{{$headeractions}}
<div class="newmessage-link">
{{$anchor}}
<a href="{{{urls.writeamessage}}}">{{#str}} newmessage, message {{/str}}
</a>
{{/anchor}}
<a href="{{{urls.writeamessage}}}">{{#str}} newmessage, message {{/str}}
</a>
</div>
{{< core/hover_tooltip }}
{{$anchor}}
<a class="mark-all-read-button"
href="#"
role="button"
title="{{#str}} markallread {{/str}}"
data-action="mark-all-read">
<span class="normal-icon">{{#pix}} t/markasread, core, {{#str}} markallread {{/str}} {{/pix}}</span>
{{> core/loading }}
</a>
{{/anchor}}
{{$tooltip}}{{#str}} markallread {{/str}}{{/tooltip}}
{{/ core/hover_tooltip }}
{{< core/hover_tooltip }}
{{$anchor}}
<a href="{{{urls.preferences}}}"
title="{{#str}} messagepreferences, message {{/str}}">
{{#pix}} i/settings, core, {{#str}} messagepreferences, message {{/str}} {{/pix}}
</a>
{{/anchor}}
{{$tooltip}}{{#str}} messagepreferences, message {{/str}}{{/tooltip}}
{{/ core/hover_tooltip }}
<a class="mark-all-read-button"
href="#"
role="button"
title="{{#str}} markallread {{/str}}"
data-action="mark-all-read">
<span class="normal-icon">{{#pix}} t/markasread, core, {{#str}} markallread {{/str}} {{/pix}}</span>
{{> core/loading }}
</a>
<a href="{{{urls.preferences}}}"
title="{{#str}} messagepreferences, message {{/str}}">
{{#pix}} i/settings, core, {{#str}} messagepreferences, message {{/str}} {{/pix}}
</a>
{{/headeractions}}
{{$content}}
@@ -52,28 +52,18 @@
{{$headertext}}{{#str}} notifications, message {{/str}}{{/headertext}}
{{$headeractions}}
{{< core/hover_tooltip }}
{{$anchor}}
<a class="mark-all-read-button"
href="#"
title="{{#str}} markallread {{/str}}"
data-action="mark-all-read"
role="button">
<span class="normal-icon">{{#pix}} t/markasread, core, {{#str}} markallread {{/str}} {{/pix}}</span>
{{> core/loading }}
</a>
{{/anchor}}
{{$tooltip}}{{#str}} markallread {{/str}}{{/tooltip}}
{{/ core/hover_tooltip }}
{{< core/hover_tooltip }}
{{$anchor}}
<a href="{{{urls.preferences}}}"
title="{{#str}} notificationpreferences, message {{/str}}">
{{#pix}} i/settings, core, {{#str}} notificationpreferences, message {{/str}} {{/pix}}
</a>
{{/anchor}}
{{$tooltip}}{{#str}} notificationpreferences, message {{/str}}{{/tooltip}}
{{/ core/hover_tooltip }}
<a class="mark-all-read-button"
href="#"
title="{{#str}} markallread {{/str}}"
data-action="mark-all-read"
role="button">
<span class="normal-icon">{{#pix}} t/markasread, core, {{#str}} markallread {{/str}} {{/pix}}</span>
{{> core/loading }}
</a>
<a href="{{{urls.preferences}}}"
title="{{#str}} notificationpreferences, message {{/str}}">
{{#pix}} i/settings, core, {{#str}} notificationpreferences, message {{/str}} {{/pix}}
</a>
{{/headeractions}}
{{$content}}
+1 -1
View File
@@ -62,7 +62,7 @@ class mod_assign_external extends external_api {
$message = 'Unknown warning type.';
}
return array('item'=>$detail,
return array('item' => s($detail),
'itemid'=>$assignmentid,
'warningcode'=>$warningcode,
'message'=>$message);
@@ -3241,6 +3241,14 @@ EDITOR.prototype = {
*/
currentannotation: null,
/**
* Track the previous annotation so we can remove selection highlights.
* @property lastannotation
* @type M.assignfeedback_editpdf.annotation
* @protected
*/
lastannotation: null,
/**
* Last selected annotation tool
* @property lastannotationtool
@@ -3871,8 +3879,7 @@ EDITOR.prototype = {
scrollleft = canvas.get('docScrollX'),
point = {x: e.clientX - offset[0] + scrollleft,
y: e.clientY - offset[1] + scrolltop},
selected = false,
lastannotation;
selected = false;
// Ignore right mouse click.
if (e.button === 3) {
@@ -3904,13 +3911,13 @@ EDITOR.prototype = {
});
if (selected) {
lastannotation = this.currentannotation;
this.lastannotation = this.currentannotation;
this.currentannotation = selected;
if (lastannotation && lastannotation !== selected) {
if (this.lastannotation && this.lastannotation !== selected) {
// Redraw the last selected annotation to remove the highlight.
if (lastannotation.drawable) {
lastannotation.drawable.erase();
this.drawables.push(lastannotation.draw());
if (this.lastannotation.drawable) {
this.lastannotation.drawable.erase();
this.drawables.push(this.lastannotation.draw());
}
}
// Redraw the newly selected annotation to show the highlight.
@@ -3918,6 +3925,15 @@ EDITOR.prototype = {
this.currentannotation.drawable.erase();
}
this.drawables.push(this.currentannotation.draw());
} else {
this.lastannotation = this.currentannotation;
this.currentannotation = null;
// Redraw the last selected annotation to remove the highlight.
if (this.lastannotation && this.lastannotation.drawable) {
this.lastannotation.drawable.erase();
this.drawables.push(this.lastannotation.draw());
}
}
}
if (this.currentannotation) {

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