Compare commits

..

239 Commits

Author SHA1 Message Date
Eloy Lafuente (stronk7) 237f4ccada Moodle release 3.10.4 2021-05-08 16:40:42 +02:00
Eloy Lafuente (stronk7) f674b77d34 weekly release 3.10.3+ 2021-05-07 16:54:50 +02:00
Eloy Lafuente (stronk7) 9215f9d294 NOBUG: Fixed SVG browser compatibility 2021-05-07 16:54:50 +02:00
Eloy Lafuente (stronk7) b72be5f142 Merge branch 'install_310_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_310_STABLE 2021-05-07 16:54:49 +02:00
abgreeve 5ed11926a6 Merge branch 'MDL-68747-310' of https://github.com/dcai/moodle into MOODLE_310_STABLE 2021-05-07 11:45:45 +08:00
Mathew May e4274d80a4 MDL-70622 mod_lti: Tighten redirect param typing 2021-05-07 11:45:45 +08:00
Adam Olley 87883bb43c MDL-70622 mod_lti: Prevent xss on lti 1.3 authentication script
Without this, people can craft URLs that other users might use not realising
what they do - and as a XSS vulnerability, it could do any number of things the
clicking-user has access to do on the site.

Change-Id: I82adc71e8706d8929011b4b24523d5b62b8ccea1
2021-05-07 11:45:34 +08:00
Jun Pataleta cd83b3732e Merge branch 'MDL-71395-310-2' of git://github.com/marinaglancy/moodle into MOODLE_310_STABLE 2021-05-07 10:30:39 +08:00
abgreeve c6ec73b12e Merge branch 'MDL-70181_310' of https://github.com/stronk7/moodle into MOODLE_310_STABLE 2021-05-07 10:22:28 +08:00
Víctor Déniz 3c23c78500 Merge branch 'MDL-71303-310' of https://github.com/StudiUM/moodle into MOODLE_310_STABLE 2021-05-06 23:34:33 +01:00
Eloy Lafuente (stronk7) 1b22f24666 Merge branch 'MDL-70049-310_count_submissions' of https://github.com/agrowe/moodle into MOODLE_310_STABLE 2021-05-06 23:27:20 +02:00
Eloy Lafuente (stronk7) 0656fb0d19 Merge branch 'MDL-70772-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-05-06 23:20:13 +02:00
Eloy Lafuente (stronk7) d13532e364 Merge branch 'MDL-71313_310' of https://github.com/timhunt/moodle into MOODLE_310_STABLE 2021-05-06 23:15:06 +02:00
Eloy Lafuente (stronk7) 0e077d9b68 Merge branch 'MDL-71343-m310' of https://github.com/rjnl/moodle into MOODLE_310_STABLE 2021-05-06 23:07:46 +02:00
Sara Arjona 35fbf2b4af MDL-70110 mod_assign: make phpunit test DB order agnostic 2021-05-06 19:38:45 +02:00
Sara Arjona 3938b91363 Merge branch 'MDL-71491-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-05-06 18:42:32 +02:00
Marina Glancy d87d0973f5 MDL-71395 core: fix bug in google lib wrapper
because of changes in PHP8 the '' == 0 is no longer true and the error in the google api wrapper was discovered
2021-05-06 18:39:10 +02:00
Sara Arjona c5298a3d9a Merge branch 'MDL-71420_310' of https://github.com/stronk7/moodle into MOODLE_310_STABLE 2021-05-06 17:58:29 +02:00
Marina Glancy 83dda7ae04 MDL-71395 block_tag_youtube: sometimes exception may have empty message 2021-05-06 17:49:14 +02:00
Víctor Déniz 2561b61d81 Merge branch 'MDL-71402-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-05-06 16:47:02 +01:00
Paul Holden 119c201a10 MDL-71491 repository_flickr: return more file data.
See also 643b0cca.
2021-05-06 16:36:35 +01:00
Sara Arjona 3cdb182a70 Merge branch 'MDL-71268-310' of git://github.com/lucaboesch/moodle into MOODLE_310_STABLE 2021-05-06 17:11:31 +02:00
Paul Holden 5e6e118a2e MDL-71402 availability: fix group restriction button in mod form.
* The button to "Add group/grouping access restriction" under
   common module settings should only be present if corresponding
   availability plugins are enabled; and
 * Prevent the same button behaving as a submit button, which
   intercepted the user hitting return in the form and added a
   restriction without deliberate action taken by the user.
2021-05-06 14:20:32 +01:00
Sara Arjona cd0b5a63fa Merge branch 'MDL-70110-310' of https://github.com/septatrix/moodle into MOODLE_310_STABLE 2021-05-06 13:16:13 +02:00
Víctor Déniz afc3b1dd3d Merge branch 'MDL-71434-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-05-06 11:15:18 +01:00
Sara Arjona d1983c3ce1 Merge branch 'MDL-71390-310' of git://github.com/marinaglancy/moodle into MOODLE_310_STABLE 2021-05-06 08:07:40 +02:00
Adrian Greeve 0094d8e66e Merge branch 'MDL-70786-310' of git://github.com/lucaboesch/moodle into MOODLE_310_STABLE 2021-05-06 10:05:02 +08:00
AMOS bot b34246ca19 Automatically generated installer lang files 2021-05-06 00:07:32 +00:00
Juan Leyva 5e29bd67e6 MDL-71513 mobile: Fix last access visibility 2021-05-05 22:49:07 +01:00
Eloy Lafuente (stronk7) ad7c296dc9 MDL-71420 environment: Lower sodium requirement to recommended 2021-05-05 23:06:18 +02:00
Sara Arjona 9aad1581bc Merge branch 'MDL-71517-310' of https://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-05-05 12:17:43 +02:00
Sara Arjona 56882a76d1 Merge branch 'MDL-71187-310' of git://github.com/lucaboesch/moodle into MOODLE_310_STABLE 2021-05-05 12:14:13 +02:00
Víctor Déniz 14c8b8bd56 Merge branch 'MDL-71460-310' of git://github.com/peterRd/moodle into MOODLE_310_STABLE 2021-05-05 10:43:08 +01:00
Luca Bösch e66bf8a5c1 MDL-71187 quizaccess_seb: Change "Launch Safe Exam Browser" to a href.
In order to allow for correct seb:// or sebs:// calls without browser
warnings of insecure links, it is not possible to send a get request
with an attached cmid parameter to the unknown seb:// or sebs://
URL via a form button.
We've got to use a <a href> link outside a form to circumvent
browsers warning of an insecure link and call Safe Exam Browser
correctly.
2021-05-05 10:54:34 +02:00
Leon Stringer 01aee79df0 MDL-70181 database: Quote database object names
Table names and database name now enclosed in backticks.
admin/cli/mysql_collation.php failed if $CFG->prefix was blank with
MySQL 8.0 because table 'groups' conflicted with a new reserved word.

Note that this quotes both mysql_collation.php and mysql_compressed_rows.php
but only the former was mal-functioning.

The case of mysql_compressed_rows.php is a little bit special because
not all tables are processed, only those having big rows. And the groups
table is not one of them. In any case, better add the quotes there for
any future case.

Also, when testing this patch https://tracker.moodle.org/browse/MDL-71512
was discovered and will need to be fixed to make core 100% compliant
with MySQL 8.0 and MariaDB 10.6 and up.
2021-05-05 10:16:54 +02:00
Peter Dias e3b4f6d3fd MDL-71460 hub: Use checkboxes instead of dropdowns
Change the yes/no dropdowns to a checkbox. Defaults to unchecked.
2021-05-05 10:27:28 +08:00
Víctor Déniz 73d36ebafa Merge branch 'MDL-70864-310-zip_packer_windows' of git://github.com/mudrd8mz/moodle into MOODLE_310_STABLE 2021-05-05 00:03:40 +01:00
Eloy Lafuente (stronk7) d73d9dd99f Merge branch 'MDL-71425-310-enfix' of git://github.com/mudrd8mz/moodle into MOODLE_310_STABLE 2021-05-04 23:39:50 +02:00
Paul Holden 301f78c282 MDL-71359 mod_forum: empty forums shouldn't export anything. 2021-05-04 17:22:47 +02:00
Sara Arjona 373c263482 MDL-71408 h5plib_v124: Add required changes after lib upgrade
- The mbstring extension is required since Moodle 3.9 onwards so
the upgrading steps have been removed because they are not
required any more.
- The pull-request for fixing some minor PHP7.4 problems has been
integrated so this patch is not required.
2021-05-04 17:22:47 +02:00
Sara Arjona ac7cd6c603 MDL-71408 h5plib_v124: Upgrade H5P core library to 1.24.02 2021-05-04 17:22:47 +02:00
Huong Nguyen 62b4ebab51 MDL-70720 Quiz: Improve capability checks when fetching users' best grades 2021-05-04 17:22:47 +02:00
Shamim Rezaie abbda5d025 MDL-69028 repository: Put a rate limit on draft file uploads 2021-05-04 17:22:47 +02:00
Paul Holden 0debb3cac0 MDL-71130 quiz_grading: escape user idnumber on display. 2021-05-04 17:22:47 +02:00
David Mudrák 9f4404e80d MDL-70804 mnet: Use proper DML method to get records from the table
This improves the code and avoids the risk of SQL injection through the
malicious XML-RPC request from the MNet peer.
2021-05-04 17:22:47 +02:00
Sara Arjona d9af87d70a Merge branch 'MDL-71274-310' of git://github.com/aanabit/moodle into MOODLE_310_STABLE 2021-05-04 17:10:48 +02:00
David Mudrák 804f1f5ac7 MDL-71425 lang: Fix reworded strings in tests 2021-05-04 16:56:09 +02:00
Helen Foster 23f0d09ec7 MDL-71425 lang: Import fixed English strings (en_fix) 2021-05-04 16:48:21 +02:00
Paul Holden 641b678d4b MDL-71517 mod_data: remove invalid form custom data access.
On PHP7.4, trying to access array offsets of NULL triggers a notice.
2021-05-04 15:35:46 +01:00
Luca Bösch 5183181f94 MDL-70786 report_loglive: respect fullname setting. 2021-05-04 14:19:17 +02:00
Luca Bösch b74abdbea1 MDL-70786 report_log: respect fullname setting. 2021-05-04 14:19:17 +02:00
Luca Bösch a11c2cb391 MDL-70786 report_completion: respect fullname setting. 2021-05-04 14:19:17 +02:00
Luca Bösch 204748856a MDL-70786 report_competency: respect fullname setting. 2021-05-04 14:19:17 +02:00
Luca Bösch 8962bd76c3 MDL-70786 report_progress: respect fullname setting. 2021-05-04 14:19:17 +02:00
Luca Bösch 8a07e2f53d MDL-71268 graphics: Use new Moodle logo for RSS feeds by Moodle 2021-05-04 14:15:29 +02:00
Sara Arjona 3de329785d weekly release 3.10.3+ 2021-05-04 13:27:55 +02:00
Sara Arjona 63a4a88dd1 Merge branch 'install_310_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_310_STABLE 2021-05-04 13:27:55 +02:00
Adrian Greeve 4f46b8449b Merge branch 'MDL-66673-MOODLE_310_STABLE' of https://github.com/ScottVerbeek/moodle into MOODLE_310_STABLE 2021-05-04 15:47:33 +08:00
AMOS bot 72c300facf Automatically generated installer lang files 2021-05-04 00:07:31 +00:00
Eloy Lafuente (stronk7) c96074aafd Merge branch 'MDL-71463-310' of https://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-05-03 19:01:01 +02:00
David Mudrák 7f507d94d9 MDL-70864 files: Fix zip_packer extracting files with trailing dots
File and folder names cannot end with dots on Windows. So replace the
trailing dots with underscore consistently with how some other zip tools
(such as 7-zip) handle this case.
2021-05-03 18:14:17 +02:00
Marina Glancy 6211bc0be5 MDL-71390 core: raise max_input_vars requirement for Moodle 3.11 2021-05-03 13:25:36 +02:00
Adrian Greeve 6dc0b43072 Merge branch 'MDL-71440-310' of git://github.com/mihailges/moodle into MOODLE_310_STABLE 2021-05-03 16:04:36 +08:00
Mihail Geshoski 502076cde6 MDL-71440 mod_assign: New capability for viewing the submission summary
Creates a new capability mod/assign:viewownsubmissionsummary which will
be required in order to display the submission summary to the user in
the assignment page.
2021-05-03 15:32:21 +08:00
Jake Dallimore 79368aaa6a Merge branch 'MDL-52724-310' of git://github.com/merrill-oakland/moodle into MOODLE_310_STABLE 2021-05-03 13:25:36 +08:00
Víctor Déniz 5431063238 Merge branch 'MDL-69956-310' of https://github.com/dcai/moodle into MOODLE_310_STABLE 2021-05-01 13:43:19 +01:00
Víctor Déniz 36764c36c0 weekly release 3.10.3+ 2021-04-30 12:54:29 +01:00
Rajneel Totaram f902e75bae MDL-71343 core_h5p: Convert all line-endings to UNIX format 2021-04-30 23:45:21 +12:00
Andrew Nicols 8fd5eb7be5 MDL-71343 core_h5p: Add unit test for helper::parse_js_array
Signed-off-by: Rajneel Totaram <rjnlfj@yahoo.com>
2021-04-30 23:40:49 +12:00
Dongsheng Cai 8399b45fd0 MDL-69956 forum: throw exception when advanced grading is not ready 2021-04-30 14:59:36 +10:00
Adrian Greeve dc783d3d5e Merge branch 'MDL-71481-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-30 11:19:46 +08:00
Jun Pataleta aaaf3abc4d Merge branch 'MDL-70947-310' of git://github.com/HuongNV13/moodle into MOODLE_310_STABLE 2021-04-30 10:34:24 +08:00
Sara Arjona 9a36fe6886 Merge branch 'MDL-60331-310_take3' of git://github.com/lucaboesch/moodle into MOODLE_310_STABLE 2021-04-29 17:49:55 +02:00
Paul Holden 1b8ccba1f2 MDL-71463 dml: escape square brackets for SQL Server LIKE operator. 2021-04-29 13:49:28 +01:00
Amaia Anabitarte 723ffea626 MDL-71274 analytics: Don't generate insight for hidden courses
Hidden courses can be used for training
but we do not want to generate insights for them
because students do not have access to hidden courses.
This was fixed in MDL-66806 for "Students at risk" model.
Fixed for "Students who have not accessed the course recently" in this issue.
2021-04-29 11:13:02 +02:00
Paul Holden 0c57ffc2b5 MDL-71481 repository_flickr_public: return more file data.
A HTTP HEAD request is required to get the image filesize.
The remaining data can be obtained from existing calls to
the Flickr API.
2021-04-29 09:49:16 +01:00
Huong Nguyen f3ae9f9d45 MDL-70947 File upload: Upload protection
Interacts badly with double-submit protection, and not all uploads protected
2021-04-29 15:32:12 +07:00
Sara Arjona 3bffbfabb5 Merge branch 'MDL-71016-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-29 09:21:52 +02:00
Jun Pataleta 3afeaed3ff Merge branch 'MDL-70863-310' of git://github.com/jleyva/moodle into MOODLE_310_STABLE 2021-04-29 15:05:15 +08:00
Andrew Nicols c05862dc9a Merge branch 'MDL-56609_310' of https://github.com/stronk7/moodle into MOODLE_310_STABLE 2021-04-29 09:41:59 +08:00
Víctor Déniz 9cd78a8b4f Merge branch 'MDL-71200-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-28 20:53:49 +01:00
Paul Holden 8f630db213 MDL-71016 gradeexport_xml: ensure user/grade idnumbers are encoded. 2021-04-28 19:03:56 +01:00
Luca Bösch 689d10b02b MDL-60331 questions: prevent double escaping question categories. 2021-04-28 17:32:27 +02:00
Sara Arjona 71f40d0018 Merge branch 'MDL-70979-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-28 13:06:18 +02:00
Sara Arjona b9f9758f5e Merge branch 'MDL-71127-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-28 12:58:28 +02:00
Sara Arjona 9e19f3c1f5 Merge branch 'MDL-70763-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-28 12:36:36 +02:00
Septatrix 8f0daf43b7 MDL-70110 assign: add group submission attemptnumber test 2021-04-28 11:50:24 +02:00
Sara Arjona fa72038987 Merge branch 'MDL-71244-310' of git://github.com/lucaboesch/moodle into MOODLE_310_STABLE 2021-04-28 09:17:39 +02:00
Andrew Nicols 6679c41c89 Merge branch 'MDL-71168-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-28 10:50:19 +08:00
Andrew Nicols 1ed97439dd MDL-70909 mod_h5pactivity: Whitespace fix 2021-04-28 10:33:29 +08:00
Andrew Nicols 17625bd5b2 Merge branch 'MDL-70909-310' of git://github.com/ferranrecio/moodle into MOODLE_310_STABLE 2021-04-28 10:26:41 +08:00
Andrew Nicols 475ea093b4 Merge branch 'MDL-71386-310' of git://github.com/NoelDeMartin/moodle into MOODLE_310_STABLE 2021-04-28 10:15:54 +08:00
Eloy Lafuente (stronk7) 40d45ede41 MDL-56609 phpunit: Fix bogus expectation on DST changes day
Current test works ok every day of the year but the day of
DST begin changes (last Sunday of March currently).

That day, 01:00 Europe/London simply doesn't exist, because
the time is moved forward by 60 minutes.

Hence the expectation for the next cron execution is not 1 "normal"
day (24h) but 1 less hour.

Note this only happens for the current test on DST begins, the
opposite change (DST ends), happening the last Sunday of October
is not affected, because, at all effects, 01:00 is a perfectly normal
and existing hour.
2021-04-27 18:31:01 +02:00
Luca Bösch 6651b3f940 MDL-71244 enrol_manual: Add bootstrap classes to buttons 2021-04-27 17:26:24 +02:00
Ferran Recio e1ac84a458 MDL-70909 mod_h5pactivity: fix reports on freeze context 2021-04-27 15:35:39 +02:00
Sara Arjona ff833a08de weekly release 3.10.3+ 2021-04-27 15:14:58 +02:00
Adrian Greeve d426ee3ccc Merge branch 'MDL-71329-310' of https://github.com/Chocolate-lightning/moodle into MOODLE_310_STABLE 2021-04-27 09:35:52 +08:00
Víctor Déniz 813338182c Merge branch 'MDL-65687-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-27 01:13:18 +01:00
Víctor Déniz 5e7f937481 Merge branch 'MDL-71003-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-27 00:37:00 +01:00
Sara Arjona 1bbfbd7444 Merge branch 'MDL-70917-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-26 15:18:12 +02:00
Sara Arjona 0f308b0df1 Merge branch 'MDL-71416-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-26 12:35:50 +02:00
Eloy Lafuente (stronk7) fea40706b1 Merge branch 'MDL-70446-m310' of https://github.com/sammarshallou/moodle into MOODLE_310_STABLE 2021-04-26 10:45:16 +02:00
Paul Holden eb60ece090 MDL-71434 mod_data: add form control class to template textarea. 2021-04-25 18:35:04 +01:00
Tim Schroeder 062dc30ffd MDL-70110 assign: fixed ws get_submissions for groups 2021-04-24 12:11:15 +02:00
Paul Holden a834862ce4 MDL-71416 report_log: user context header should show users name.
Co-Authored-By: Luca Bösch <luca.boesch@bfh.ch>
2021-04-23 20:24:34 +01:00
Sara Arjona e148629f48 weekly release 3.10.3+ 2021-04-23 10:47:03 +02:00
Mathew May 8e750158a0 MDL-71329 tool_moodlenet: Check to see if we get errors before curl 2021-04-23 15:49:55 +08:00
Jun Pataleta 78ea26ad7b Merge branch 'MDL-71171_310' of git://github.com/mdjnelson/moodle into MOODLE_310_STABLE 2021-04-23 12:40:47 +08:00
Mark Nelson b58a1b9e34 MDL-71171 customfield_text: ensure we set defaults properly 2021-04-23 12:37:38 +08:00
Andrew Nicols 298a70eba1 Merge branch 'MOODLE_310_STABLE-MDL-71376' of https://github.com/rjnl/moodle into MOODLE_310_STABLE 2021-04-23 11:53:24 +08:00
Andrew Nicols 0e301e88a5 Merge branch 'MDL-70970-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-23 11:39:04 +08:00
ScottVerbeek 4b9b0839b6 MDL-66673 groups: Stop notice when messaging system is disabled 2021-04-23 08:54:38 +10:00
Ferran Recio d7d94cf30f MDL-70909 behat: context freeze and not freeze steps 2021-04-22 15:51:36 +02:00
Sara Arjona 72b6d0be84 Merge branch 'MDL-71136_310' of https://github.com/TomoTsuyuki/moodle into MOODLE_310_STABLE 2021-04-22 13:56:49 +02:00
Sara Arjona fa2d1ab5d3 Merge branch 'MDL-71400-310' of git://github.com/mihailges/moodle into MOODLE_310_STABLE 2021-04-22 13:16:38 +02:00
Ferran Recio 78aabd1e28 MDL-70909 core: add cannotmatchanyrows to capabilities join 2021-04-22 13:10:37 +02:00
Jun Pataleta 72e7b87b92 Merge branch 'MDL-71170_310' of git://github.com/mdjnelson/moodle into MOODLE_310_STABLE 2021-04-22 18:55:12 +08:00
Noel De Martin 3a83f57043 MDL-71386 behat: Support for 3.9.5+ mobile app 2021-04-22 12:16:01 +02:00
Paul Holden 2a706c3e5c MDL-71200 mod_folder: ensure "Download folder" option is backed up. 2021-04-22 10:29:12 +01:00
Paul Holden faaa25b5cc MDL-70979 search: validate external user search parameters.
Clean return value in unit test for same.
2021-04-22 10:22:57 +01:00
Mihail Geshoski 6b5a1b02fe MDL-71400 assignfeedback_offline: Fix message after worksheet upload 2021-04-22 13:08:52 +08:00
Jun Pataleta 96ddfecda3 Merge branch 'MDL-71156-310' of git://github.com/lameze/moodle into MOODLE_310_STABLE 2021-04-22 11:53:39 +08:00
Simey Lameze 94259f8a7d MDL-71156 core: machinery to recover orphaned calendar events
The machinery to fix orphaned calendar events that were broken by MDL-67494.

The solution consists of:

1) Upgrade step that checks if this site has executed the problematic upgrade steps and
   if positive, it will schedule a new run for calendar_fix_orphaned_events adhoc task.

2) Adhoc task that will self-spawn calling the recovery machinery, running until
   all the orphaned calendar events are fixed. It also sets the maximum runtime of
   60 seconds. It is also possible to override that number by specifing the desired
   number setting the ->calendareventsmaxseconds in your config.php

3) CLI script that will look for all the calendar events which userids
   where broken by a wrong upgrade step, affecting to Moodle 3.9.5
   and up.

   It performs checks to both:
     a) Detect if the site was affected (ran the wrong upgrade step).
     b) Look for orphaned calendar events, categorising them as:
       - standard: site / category / course / group / user events
       - subscription: events created via subscriptions.
       - action: normal action events, created to show common important dates.
       - override: user and group override events, particular, that some activities support.
       - custom: other events, not being any of the above, common or particular.

   By specifying it (--fix) try to recover as many broken events (missing userid) as
   possible. Standard, subscription, action, override events in core are fully supported but
   override or custom events should be fixed by each plugin as far as there isn't any standard
   API (plugin-wise) to launch a rebuild of the calendar events.

4) Unit tests and helper functions to generate calendar events. We have decided to
   keep the tests simple, testing only true and false and not using data generators because
   the code is purely to recover the calendar events and won't turn into an API or something
   and also due to the urgency of this issue.
   The helpers have been created in calendar/tests/helpers.php since there are no data generators
   for calendar.
2021-04-22 10:43:37 +08:00
Andrew Nicols 855e7e9ede Merge branch 'MDL-70412-310' of git://github.com/aanabit/moodle into MOODLE_310_STABLE 2021-04-22 10:07:57 +08:00
Neill Magill e6725b8cbb MDL-64336 assign: Add missing PHP doc 2021-04-21 17:21:19 +02:00
Neill Magill bd80f68c11 MDL-64336 assign: Teachers should be able to see all submissions
Before this change a teacher would be able to see users listed if:

* They have an active enrolment and can submit
* They have an an inactive enrolment for a role that can submit

After this change they will additonally be able to see users listed:

* That have an active enrolment and have submitted
* That have an inactive enrolment and have submitted

This means that if an assignment has it's context frozen all users
that have made some form of submission will still be listed.

It will also apply if the submission capability is removed from a
user.

If a user's enrolment is deleted they will not be listed.

The submission and grading counts have also been updated so
they will reflect the new rules.
2021-04-21 17:15:54 +02:00
Neill Magill dbcfda9641 MDL-64336 assign: Submissions should be visible while frozen
Before this change if a student visited an assignment that is
frozen they would only see the title and description even if
they had made a submission to it.

After the change they will be able to see the status of their
submission and any feedback and grades they have recived.

It will also make the Moodle app recognise that submission
should not happen because the assignment is frozen.

Tests based on ones created by Andrew Nicols
2021-04-21 17:15:45 +02:00
Sara Arjona b62526d0ad Merge branch 'MDL-62244_310_label_view' of https://github.com/sheesania/moodle into MOODLE_310_STABLE 2021-04-20 17:45:06 +02:00
Sara Arjona d9293c77bc weekly release 3.10.3+ 2021-04-20 15:51:19 +02:00
Sara Arjona 6f9415fea0 Merge branch 'install_310_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_310_STABLE 2021-04-20 15:51:18 +02:00
Paul Holden 647020f584 MDL-70970 quizaccess_seb: consistent property array sorting by key.
In PHP8.0 using `ksort` was producing incorrect results by sorting
keys differing only in case in the wrong order. This change makes
sorting consistent between PHP versions.

Co-Authored-By: Tim Hunt <T.J.Hunt@open.ac.uk>
2021-04-20 14:36:19 +01:00
Rajneel Totaram afc20e7caa MDL-71376 mod_quiz: fix undefined object reference 2021-04-20 20:13:40 +12:00
Jun Pataleta 6d82a01438 Merge branch 'MDL-71364_310' of https://github.com/stronk7/moodle into MOODLE_310_STABLE 2021-04-20 09:23:43 +08:00
AMOS bot 3e47cdda94 Automatically generated installer lang files 2021-04-20 00:07:27 +00:00
Víctor Déniz 7ccaf08d5a Merge branch 'MDL-71087-310' of https://github.com/NashTechOpenUniversity/moodle into MOODLE_310_STABLE 2021-04-19 23:45:02 +01:00
Eloy Lafuente (stronk7) 5d309ef2a8 Merge branch 'MDL-69256-310' of git://github.com/andrewnicols/moodle into MOODLE_310_STABLE 2021-04-20 00:05:05 +02:00
Víctor Déniz ce023afec9 Merge branch 'MOODLE_310_STABLE_fix_gradeimport_csv' of https://github.com/intrajp/moodle into MOODLE_310_STABLE 2021-04-19 22:49:09 +01:00
Dongsheng Cai fdb9a664f6 MDL-68747 mod_quiz: force LTR for quiz grading overview chart 2021-04-19 21:06:37 +10:00
Sara Arjona 79d705df64 Merge branch 'MDL-71365_310' of https://github.com/stronk7/moodle into MOODLE_310_STABLE 2021-04-19 10:18:39 +02:00
Paul Holden 73e9259c10 MDL-71127 mod_quiz: fix thrown exception for invalid question columns. 2021-04-19 09:07:13 +01:00
Paul Holden 785cf4fb22 MDL-71168 report_participation: fix select all users checkbox. 2021-04-19 09:05:13 +01:00
Sara Arjona c30923d77d Merge branch 'MDL-66475-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-19 09:49:23 +02:00
Sara Arjona ea388d74ab Merge branch 'MDL-65553-310' of git://github.com/aanabit/moodle into MOODLE_310_STABLE 2021-04-19 08:53:45 +02:00
AMOS bot 61d1af0818 Automatically generated installer lang files 2021-04-18 00:07:25 +00:00
Eloy Lafuente (stronk7) 93960101e9 MDL-71365 grunt: fix ignores missing LF @ EOF 2021-04-18 00:44:06 +02:00
Eloy Lafuente (stronk7) 26e8b4a0fa MDL-71364 behat: fix randomness causes by "now" advancing
Some recent tests do set a date time element
to ##now## or tomorrow and, immediately after that
the look if, effectively, ##now## and #tomorrow#
have been set (with minutes resolution).

Problem is that, between the field is set and the field
is verified, it can happen that the time advances to
next minute (from H:M:59 to H:M+1:00) and then the
assertion fails.

To avoid this, we could have lowered the resolution to be
hours... but that doesn't solve the problem just makes it
to happen less often.

So, instead of that... we are setting the 2 now and tomorrow
cases to be "today noon" and "tomorrow noon" (12:00:00) so
we ensure they won't be ever in the risk of jumping of minute.
2021-04-17 12:33:32 +02:00
Eloy Lafuente (stronk7) a1523774bc Merge branch 'MDL-70099-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-17 09:40:37 +02:00
Sara Arjona 7c1feb97b2 weekly release 3.10.3+ 2021-04-16 17:03:33 +02:00
Sara Arjona 26e00f4640 Merge branch 'install_310_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_310_STABLE 2021-04-16 17:03:32 +02:00
Andrew Nicols bf4038a971 Merge branch 'MOODLE_310_MDL-71233' of https://github.com/golenkovm/moodle into MOODLE_310_STABLE 2021-04-16 12:08:51 +08:00
Andrew Nicols 10c4a67760 Merge branch 'MDL-60490-missing_close_div-310' of https://github.com/leonstr/moodle into MOODLE_310_STABLE 2021-04-16 11:54:13 +08:00
Andrew Nicols def3f4a074 Merge branch 'MDL-69415-310' of git://github.com/sarjona/moodle into MOODLE_310_STABLE 2021-04-16 11:27:06 +08:00
Amaia Anabitarte 71613b1055 MDL-70412 groups: Improving create_group data generator
Increasing the size of the name for generated groups
to ensure we don't have problems with ordering.
2021-04-15 16:57:23 +02:00
Amaia Anabitarte db374d6a80 MDL-65553 core_analytics: Don't allow to flag predictions several times
Even if a prediction is hidden from the report once is flagged,
it can be flagged several times if the user visits detailed view via URL.
We remove the checkbox to select a prediction and flag it
once it has already been flagged.
2021-04-15 16:39:09 +02:00
Jake Dallimore 6958a078a6 Merge branch 'MDL-71338-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-15 14:42:44 +08:00
Jake Dallimore 5566bfe436 Merge branch 'MDL-71119-310' of git://github.com/sarjona/moodle into MOODLE_310_STABLE 2021-04-15 08:32:29 +08:00
AMOS bot 40cdfc58fc Automatically generated installer lang files 2021-04-15 00:07:34 +00:00
Paul Holden 416b25fc77 MDL-71338 tool_usertours: correct Content-Type on tour export.
Replace existing code with standard file serving mechanism, in
turn correcting the previously incorrect Content-Type header.
2021-04-14 21:12:02 +01:00
Eloy Lafuente (stronk7) ae88411798 Merge branch 'MDL-70616-310-fixed' of https://github.com/izendegi/moodle into MOODLE_310_STABLE 2021-04-14 12:45:23 +02:00
Iñigo Zendegi 909c977e00 MDL-70616 gradingform_rubric: Filters not applied to rubric name 2021-04-14 11:51:11 +02:00
Sara Arjona 3306411314 MDL-71119 core_badges: Add more information to errors
Some errors raised when calling external services were ignored.
Displaying this information helps to debug and find the real reasons
why some action, like connecting to an external backpack, can't be
done.
2021-04-14 11:04:06 +02:00
Sara Arjona 4203a0389e MDL-71119 core_badges: Use basicauth and remove urlencode
Basic authorization header is required to get token. Besides, client
id and secret shouldn't call urlencode.
2021-04-14 11:01:27 +02:00
Sara Arjona 2d308243f4 MDL-71119 core_badges: Initialise scopes param in backpack-connect.php
The scopes parameter should be passed when creating the OAuth2 badges
client. As it is an optional parameter, when it's empty, it will
be initilised with the supported scopes for the backpack issuer.

It will happen, for instance, when a call is done to oauth2callback.php
because, as defined in RFC6749, OAuth2 authorization response only
supports code and state.
2021-04-14 11:01:27 +02:00
Paul Holden 6a7baaced0 MDL-70772 mod_forum: check for valid usernode before making active. 2021-04-14 09:20:20 +01:00
Andrew Nicols 0c611e0a13 Merge branch 'MDL-71154_310' of https://github.com/stronk7/moodle into MOODLE_310_STABLE 2021-04-14 12:11:21 +08:00
AMOS bot 905511e816 Automatically generated installer lang files 2021-04-14 00:07:28 +00:00
Eloy Lafuente (stronk7) d883536e6f MDL-71154 ci: Prevent upstream branches and tags to be built
Both for travis and GHA:

- master and MOODLE_XXX_STABLE branches
- any vX.Y.Z tag

won't lead to a build anymore.
2021-04-13 16:55:50 +02:00
Eloy Lafuente (stronk7) 653d6f0229 weekly release 3.10.3+ 2021-04-13 10:26:39 +02:00
Eloy Lafuente (stronk7) 4ab41d6090 Merge branch 'install_310_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_310_STABLE 2021-04-13 10:26:38 +02:00
Eloy Lafuente (stronk7) c50d68cfd9 Merge branch 'MDL-71059-310' of git://github.com/abias/moodle into MOODLE_310_STABLE 2021-04-13 00:42:34 +02:00
Tim Hunt 33d6929e1f MDL-71313 repositories: warn if get_instances context is wrong type 2021-04-12 20:35:02 +01:00
Sara Arjona f4a604e4e2 Merge branch 'MDL-68716-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-12 17:24:46 +02:00
Sara Arjona 0ecc30eb85 Merge branch 'MDL-71264_310' of https://github.com/stronk7/moodle into MOODLE_310_STABLE 2021-04-12 16:40:16 +02:00
Sara Arjona 4de37cf603 Merge branch 'MDL-70595-310' of git://github.com/mickhawkins/moodle into MOODLE_310_STABLE 2021-04-12 16:01:40 +02:00
Sara Arjona dda7890857 Merge branch 'MDL-71107-10' of git://github.com/aanabit/moodle into MOODLE_310_STABLE 2021-04-12 12:41:16 +02:00
Eloy Lafuente (stronk7) b470f7b246 Merge branch 'MDL-69102-310' of https://github.com/martygilbert/moodle into MOODLE_310_STABLE 2021-04-12 00:02:05 +02:00
Eloy Lafuente (stronk7) f5087ef548 MDL-69102 phpunit: Add test to cover ALL cohort criteria
That way we can check that the expectations are
working ok for every database. Previously only the
ANY case was being tested.

Also, convert them to course badges and check, via
review_all_criteria() that the SQL structures returned
by award_criteria_cohort->get_completed_criteria_sql()
doesn't fail and return the expected counters.
2021-04-10 12:38:46 -04:00
Issam Taboubi 7e146f752a MDL-71303 core: HTML not escaped in block skip link 2021-04-09 17:31:27 -04:00
AMOS bot ece30526dd Automatically generated installer lang files 2021-04-09 00:07:31 +00:00
Eric Merrill a3fa31fa21 MDL-52724 editor_atto: Scrub atto html for invalid ol, ul, and li tags
Try to correct broken ul/ol/li tags, as they have an outsized impact
on course layout. Uses basic regex and loops to track open and closed
tags.

Also adds a deep clean option to the HTML cleaner, that runs less
frequent, more intensive cleanings. This is because normally _cleanHTML
gets called after each keystroke, which could cause problems with
large content on weak systems.

Behat changes are a fix for setting multiline strings in Atto, and
creating a multiline match step.
2021-04-08 15:30:50 -04:00
Eloy Lafuente (stronk7) 06b3ac6ca1 Merge branch 'MDL-70802-310' of git://github.com/andrewnicols/moodle into MOODLE_310_STABLE 2021-04-08 18:37:39 +02:00
Víctor Déniz 4c8c9a4c4b Merge branch 'MDL-71116-310' of git://github.com/sarjona/moodle into MOODLE_310_STABLE 2021-04-08 01:05:55 +01:00
Amaia Anabitarte 538c8eddb5 MDL-71107 core_contentbank: Behat test. Authoring when copying a course 2021-04-07 10:03:37 +02:00
Amaia Anabitarte fafed9dc90 MDL-71107 core_contentbank: Fill content author when copying a course
'usercreated' and 'usermodified' fields can not be always mapped.
We are filling those fields with 'old' users when working on the same
site, or with current user when working on a different instance.
2021-04-07 10:03:37 +02:00
Alex Rowe 1611b30b1c MDL-70049 assign: count_submissions_need_grading call when can't grade 2021-04-07 08:57:05 +10:00
Eloy Lafuente (stronk7) 69455d835c Merge branch 'MDL-70959-310' of git://github.com/junpataleta/moodle into MOODLE_310_STABLE 2021-04-06 22:29:07 +02:00
Eloy Lafuente (stronk7) c33060d008 Merge branch 'MDL-68635-310' of https://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-06 22:23:42 +02:00
Víctor Déniz 10f934e300 Merge branch 'MDL-71128-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-04-06 19:51:02 +01:00
Michael Hawkins 9d63efed82 MDL-70595 core: Updated security.txt expiry 2021-04-06 13:13:45 +08:00
AMOS bot da5111e321 Automatically generated installer lang files 2021-04-06 00:07:37 +00:00
Paul Holden ebfe1d5945 MDL-70099 enrol: increase accuracy of current enrolments by date.
By rounding the current time it was possible that the most recently
created user enrolments (e.g. self enrolments) were being excluded.

This would manifest itself in a user being enrolled on a course,
but it not appearing under "My courses" navigation or on their own
Dashboard until the rounded time had caught up with the current
time.
2021-04-05 19:32:15 +01:00
Paul Holden 359cc7e787 MDL-71003 user: fix alignment of autocomplete participant filters. 2021-04-04 23:21:25 +01:00
Paul Holden 981784000d MDL-70917 tool_behat: fix profile/replace option comparison.
The `isset` call always returned true for the 'replace' option,
because even if not specified it receives a non-null value. The
`strpos` call now does a strict equality check rather than
greater-than-or-equal (which always returns true).
2021-04-04 23:18:37 +01:00
Paul Holden 542a7490f2 MDL-70763 core: export preferences for correct user.
Ensure we are using the ID of the given user rather than falling
back to that of the current user during privacy export.
2021-04-04 23:15:43 +01:00
Paul Holden e44ae4df58 MDL-70763 quiz_overview: export preferences for correct user. 2021-04-04 23:15:43 +01:00
Paul Holden e89432fb19 MDL-70763 gradereport_grader: export preferences for correct user. 2021-04-04 23:15:43 +01:00
Paul Holden 3e30dffa31 MDL-66475 task: fix random timing failures in logger cleanup test. 2021-04-04 23:12:38 +01:00
AMOS bot e084f4c0b4 Automatically generated installer lang files 2021-04-04 00:07:33 +00:00
Eloy Lafuente (stronk7) 215851c4c0 MDL-71264 behat: Change date(time) element update order
This includes 2 change to the order date(time) elements are filled,
each one addressing one type of problem, where current order is
problematic and can lead to unexpected dates.

1) Changing date, when current month only has X days and target
   month has more than X days. Example, being 1 April, change
   the date to 31 May.
     This is solved by changing the order of introduction
     from current D => M => Y to Y => M => D.
2) Changing date, when target month only has X days and current
   month has more that X days. Example, being 31 March, change
   the date to 28 Feb.
     This is solved by always setting the D to 1, before the
     Y => M => D sequence commented @ 1) begins.
2021-04-03 18:10:04 +02:00
Eloy Lafuente (stronk7) f751383a15 MDL-71264 behat: New feature covering all day/month/year date changes
Because of the order that dates and datetimes are filled by behat
sometimes there are some intermediate results that are impossible
and then the form (javascript) automatically reacts and fixes the
date, ultimate leading to a different date that the one we wanted
to set with Behat.

This is noticeable when switching between months (with some day
being the last day of the month) and the 2 months have a different
number of days. For example April date => March date (or the opposite).

This test covers all the critical changes (day, month and year),
back and forth. All times are Perth/Australia.
2021-04-03 10:59:45 +02:00
AMOS bot ab1207e8eb Automatically generated installer lang files 2021-04-02 00:07:25 +00:00
Marty Gilbert 5ef3241ae3 MDL-69102 badge: Fixes broken WHERE clause
When buildilng the 'WHERE' clause, the SQL generated
a query that selected any user who was a member of the
**last** group, not all of the groups.

I believe the query has to be re-worked so that it only
returns users who are in ALL of the groups. This can
be done by a GROUP BY and HAVING.
2021-04-01 14:51:21 -04:00
Alison Blomenberg eebc6ba6a8 MDL-62244 Resource: label view redirects to label, not course 2021-04-01 11:54:48 -06:00
Leon Stringer 6cd746cb4d MDL-60490 tool_lp: Missing div close
Mustache template had opening <div> with missing </div>.
2021-04-01 12:18:13 +01:00
sam marshall 6877043d8c MDL-70446 search_solr: File indexing can fail due to multipart upload
Due to Solr bug SOLR-15039, uploading files for indexing can fail if
it uses multipart upload. This changes it to use direct binary upload.

Unfortunately, the direct binary version in PHP curl only supports a
string, so we have to load the file into memory. I added extra code to
restrict the size of files indexed to (memory limit - 100MB), which is
usually 284MB unless configured differently because cron runs under
MEMORY_EXTRA.
2021-04-01 11:40:36 +01:00
AMOS bot 2c249dbee1 Automatically generated installer lang files 2021-04-01 00:07:27 +00:00
Juan Leyva 6c14348b41 MDL-70863 mod_forum: Allow NULL in timecreated 2021-03-31 17:49:58 +02:00
Víctor Déniz c7b4cf91f8 weekly release 3.10.3+ 2021-03-30 15:37:42 +01:00
Víctor Déniz 3bc49b14bf Merge branch 'install_310_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_310_STABLE 2021-03-30 15:37:41 +01:00
Paul Holden f4e28ca6c2 MDL-65687 message: increase confirmation dialog zindex.
Make sure that confirmation dialogs (such as block/unblock user,
delete conversation) are shown with prominence in the messaging
drawer.
2021-03-30 10:50:48 +01:00
Tomo Tsuyuki ed1ce9cf9b MDL-71136 backup: Fix moodle_exception path. 2021-03-30 10:56:09 +11:00
Mikhail Golenkov 31530a2730 MDL-71233 backup: Fix Moodle version for MDL-69418 2021-03-30 10:45:14 +11:00
Paul Holden 82babe08ea MDL-68635 tool_cohortroles: observe user initial table filter. 2021-03-29 14:12:17 +01:00
Paul Holden 76e39a9c2a MDL-68716 mod_forum: extra column sorting options in privacy export.
Accounts for extra sort options that were added in bc23cbaf.
2021-03-29 14:05:37 +01:00
Eloy Lafuente (stronk7) f41360dd50 Merge branch 'MDL-70963-310' of git://github.com/sarjona/moodle into MOODLE_310_STABLE 2021-03-29 12:39:56 +02:00
Andrew Nicols 838190a43a Merge branch 'MDL-71004_310' of https://github.com/stronk7/moodle into MOODLE_310_STABLE 2021-03-29 11:54:27 +08:00
AMOS bot e2b34c37bd Automatically generated installer lang files 2021-03-29 00:07:26 +00:00
AMOS bot 250afa688f Automatically generated installer lang files 2021-03-28 00:07:23 +00:00
Víctor Déniz 325915ef34 Merge branch 'MDL-70537-m310' of https://github.com/sammarshallou/moodle into MOODLE_310_STABLE 2021-03-26 20:15:29 +00:00
Sara Arjona fec16e68c9 MDL-70963 core_badges: Use expected JSON format for OBv2.1
This patch adds some changes to guarantee that OpenBadges 2.1 (OBv2.1)
will return always the same JSON format that OBv2.0 (because the only
difference between both versions it's the BadgeConnect API).
2021-03-26 09:02:18 +01:00
Shintaro Fujiwara c906a33e1e MDL-69304 gradeimport_csv: Validate if the user id is numerical. 2021-03-26 10:31:40 +09:00
Víctor Déniz e8a5efe835 Merge branch 'MDL-71194-310' of git://github.com/NoelDeMartin/moodle into MOODLE_310_STABLE 2021-03-25 15:15:09 +00:00
Noel De Martin aa07315267 MDL-71194 behat: Fix app tests 2021-03-25 13:51:01 +01:00
Andrew Nicols d4de6e594d Merge branch 'MDL-70980-310' of git://github.com/ferranrecio/moodle into MOODLE_310_STABLE 2021-03-25 08:07:41 +08:00
AMOS bot 14138237ee Automatically generated installer lang files 2021-03-25 00:07:27 +00:00
Eloy Lafuente (stronk7) 0e74a6c0c5 MDL-71004 git: Ignore moodle-plugin-ci.phar in any directory 2021-03-24 20:10:34 +01:00
Andrew Nicols 06c9de6b05 MDL-70802 javascript: Normalise component consistently in templates 2021-03-24 11:18:33 +08:00
Andrew Nicols a8d18f88a1 MDL-69256 tests: Fix random slow test failures in completion cron 2021-03-23 08:08:29 +08:00
Mark Nelson a87f5b6e8c MDL-71170 customfield_text: use correct error string 2021-03-22 21:56:48 +08:00
Sara Arjona 9e52a6a0e1 MDL-69415 core_h5p: prepend H5P libraries in autoloader
Core and mod_hvp are using the same namespace for some H5P
libraries. This is causing some random errors.
In order to get the expected behaviour in Moodle core, this patch
prepends H5P libraries in order to guarantee they are loaded first.
Plugins using same libraries will need to use a different namespace
if they overlap and a different version of these libraries should
be used.
2021-03-22 12:41:02 +01:00
Ferran Recio e21872130d MDL-70980 mod_h5pactivity: fix review mode 2021-03-22 10:58:00 +01:00
Thinh Pham 3567998cfd MDL-71087 File picker: Focus lost after 'Create folder' 2021-03-22 14:30:43 +07:00
Sara Arjona 0820e24c18 MDL-71116 core_badges: Backpack URLs with more than 50 chars
Backpack URLs (web and API) can have up to 255. However, the form
for creating/editing them, doesn't allow URLs with more than 50
characters. This patch align limitation to DB value (255).
2021-03-19 15:09:07 +01:00
Jun Pataleta 35f368a1b4 MDL-70959 completion: Fix completion_info::get_data() unit tests
* Fixed inverted $sameuser test data.
* Fixed caching expectation check. Caching only relies on whether the
user accessing the completion data is the same user or not.
* Fixed checking for the caching of other modules. Should have been
checking cm ID and not instance ID.
* Additional test case when whole course parameter is passed as
true, but the requesting user is different from the target user.
2021-03-19 11:50:14 +08:00
sam marshall 31aedd4c1c MDL-70537 Availability: Avoid recursive calls to $cm->name
These recursive calls didn't work in PHP 7.3 and below, but in PHP
7.4 they also cause a fatal error which means if you have invalid
availability data, the whole page might die.
2021-03-18 15:56:28 +00:00
Paul Holden 147a25d87f MDL-71128 mod_quiz: escape question idnumber on display. 2021-03-16 20:28:48 +00:00
Jun Pataleta 7eb9ddc5ae MDL-70959 completion: Fix unit tests for get_data()
The unit tests for completion_info::get_data() does not make a lot of
sense with mocking being incorrectly used and the actual functionality
is not being properly tested. I have rewritten the test to use actual
cm_info instances and data providers for better coverage.
2021-03-12 13:34:58 +08:00
Jun Pataleta 3afc0edaf9 MDL-70959 completion: Documentation improvements
* Fix typo in $cm parameter's type in PHPDoc
* Improve the comment to better explain the logic why fetching the
completion data for the whole course can only be done when caching is
used.
Even if $wholecourse is set to true, there's no point in fetching the
completion data for all the course modules unless we're caching the
results.
2021-03-12 13:34:55 +08:00
Alexander Bias e1fcbc9d3d MDL-71059 repository_contentbank: set default returntype
The content bank was designed for making easier to reuse content.
So "Link to the file" should be the default option when using the
contentbank repository, in order to let teachers modify their
content in the content bank and update automatically it everywhere
is used.
2021-03-05 11:34:38 +01:00
255 changed files with 5744 additions and 888 deletions
+1 -1
View File
@@ -92,4 +92,4 @@ theme/boost/amd/src/bootstrap/tab.js
theme/boost/amd/src/bootstrap/toast.js
theme/boost/amd/src/bootstrap/tooltip.js
theme/boost/amd/src/bootstrap/util.js
theme/boost/scss/fontawesome/
theme/boost/scss/fontawesome/
+7 -1
View File
@@ -1,6 +1,12 @@
name: Core
on: [push]
on:
push:
branches-ignore:
- master
- MOODLE_[0-9]+_STABLE
tags-ignore:
- v[0-9]+.[0-9]+.[0-9]+*
env:
php: 7.4
+1
View File
@@ -46,3 +46,4 @@ composer.phar
atlassian-ide-plugin.xml
/node_modules/
/.vscode/
moodle-plugin-ci.phar
+1 -1
View File
@@ -93,4 +93,4 @@ theme/boost/amd/src/bootstrap/tab.js
theme/boost/amd/src/bootstrap/toast.js
theme/boost/amd/src/bootstrap/tooltip.js
theme/boost/amd/src/bootstrap/util.js
theme/boost/scss/fontawesome/
theme/boost/scss/fontawesome/
+6
View File
@@ -19,6 +19,12 @@ services:
addons:
postgresql: "9.6"
branches:
except:
- master
- /MOODLE_[0-9]+_STABLE/
- /^v[0-9]+\.[0-9]+\.[0-9]+.*/
jobs:
# Enable fast finish.
# This will fail the build if a single job fails (except those in allow_failures).
+2 -2
View File
@@ -424,7 +424,7 @@ module.exports = function(grunt) {
'*/**/yui/src/*/meta/',
'*/**/build/',
].concat(thirdPartyPaths);
grunt.file.write('.eslintignore', eslintIgnores.join('\n'));
grunt.file.write('.eslintignore', eslintIgnores.join('\n') + '\n');
// Generate .stylelintignore.
const stylelintIgnores = [
@@ -433,7 +433,7 @@ module.exports = function(grunt) {
'theme/boost/style/moodle.css',
'theme/classic/style/moodle.css',
].concat(thirdPartyPaths);
grunt.file.write('.stylelintignore', stylelintIgnores.join('\n'));
grunt.file.write('.stylelintignore', stylelintIgnores.join('\n') + '\n');
};
/**
+138
View File
@@ -0,0 +1,138 @@
<?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/>.
/**
* Fix orphaned calendar events that were broken by MDL-67494.
*
* This script will look for all the calendar events which userids
* where broken by a wrong upgrade step, affecting to Moodle 3.9.5
* and up.
*
* It performs checks to both:
* a) Detect if the site was affected (ran the wrong upgrade step).
* b) Look for orphaned calendar events, categorising them as:
* - standard: site / category / course / group / user events
* - subscription: events created via subscriptions.
* - action: normal action events, created to show common important dates.
* - override: user and group override events, particular, that some activities support.
* - custom: other events, not being any of the above, common or particular.
* By specifying it (--fix) try to recover as many broken events (missing userid) as
* possible. Standard, subscription, action, override events in core are fully supported but
* override or custom events should be fixed by each plugin as far as there isn't any standard
* API (plugin-wise) to launch a rebuild of the calendar events.
*
* @package core
* @copyright 2021 onwards Simey Lameze <simey@moodle.com>
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('CLI_SCRIPT', true);
require_once(__DIR__ . '/../../config.php');
require_once($CFG->libdir . "/clilib.php");
require_once($CFG->libdir . '/db/upgradelib.php');
// Supported options.
$long = ['fix' => false, 'help' => false];
$short = ['f' => 'fix', 'h' => 'help'];
// CLI options.
[$options, $unrecognized] = cli_get_params($long, $short);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
if ($options['help']) {
$help = <<<EOT
Fix orphaned calendar events.
This script detects calendar events that have had their
userid lost. By default it will perform various checks
and report them, showing the site status in an easy way.
Also, optionally (--fix), it wil try to recover as many
lost userids as possible from different sources. Note that
this script aims to process well-know events in core,
leaving custom events in 3rd part plugins mostly unmodified
because there isn't any consistent way to regenerate them.
For more details: https://tracker.moodle.org/browse/MDL-71156
Options:
-h, --help Print out this help.
-f, --fix Fix the orphaned calendar events in the DB.
If not specified only check and report problems to STDERR.
Usage:
- Only report: \$ sudo -u www-data /usr/bin/php admin/cli/fix_orphaned_calendar_events.php
- Report and fix: \$ sudo -u www-data /usr/bin/php admin/cli/fix_orphaned_calendar_events.php -f
EOT;
cli_writeln($help);
die;
}
// Check various usual pre-requisites.
if (empty($CFG->version)) {
cli_error('Database is not yet installed.');
}
$admin = get_admin();
if (!$admin) {
cli_error('Error: No admin account was found.');
}
if (moodle_needs_upgrading()) {
cli_error('Moodle upgrade pending, script execution suspended.');
}
// Do everything as admin by default.
\core\session\manager::set_user($admin);
// Report current site status.
cli_heading('Checking the site status');
$needsfix = upgrade_calendar_site_status();
// Report current calendar events status.
cli_heading('Checking the calendar events status');
$info = upgrade_calendar_events_status();
$hasbadevents = $info['total']->bad > 0 || $info['total']->bad != $info['other']->bad;
$needsfix = $needsfix || $hasbadevents;
// If, selected, fix as many calendar events as possible.
if ($options['fix']) {
// If the report has told us that the fix was not needed... ask for confirmation!
if (!$needsfix) {
cli_writeln("This site DOES NOT NEED to run the calendar events fix.");
$input = cli_input('Are you completely sure that you want to run the fix? (y/N)', 'N', ['y', 'Y', 'n', 'N']);
if (strtolower($input) != 'y') {
exit(0);
}
cli_writeln("");
}
cli_heading('Fixing as many as possible calendar events');
upgrade_calendar_events_fix_remaining($info);
// Report current (after fix) calendar events status.
cli_heading('Checking the calendar events status (after fix)');
upgrade_calendar_events_status();
} else if ($needsfix) {
// Fix option was not provided but problem events have been found. Notify the user and provide info how to fix these events.
cli_writeln("This site NEEDS to run the calendar events fix!");
cli_writeln("To fix the calendar events, re-run this script with the --fix option.");
}
+8 -8
View File
@@ -119,7 +119,7 @@ if (!empty($options['collation'])) {
if ($dbcollation->value !== $collation || $dbcharset->value !== $charset) {
// Try to convert the DB.
echo "Converting database to '$collation' for $CFG->wwwroot:\n";
$sql = "ALTER DATABASE $CFG->dbname DEFAULT CHARACTER SET $charset DEFAULT COLLATE = $collation";
$sql = "ALTER DATABASE `$CFG->dbname` DEFAULT CHARACTER SET $charset DEFAULT COLLATE = $collation";
try {
$DB->change_database_structure($sql);
} catch (exception $e) {
@@ -146,7 +146,7 @@ if (!empty($options['collation'])) {
} else {
try {
$DB->change_database_structure("ALTER TABLE $table->name CONVERT TO CHARACTER SET $charset COLLATE $collation");
$DB->change_database_structure("ALTER TABLE `$table->name` CONVERT TO CHARACTER SET $charset COLLATE $collation");
echo "CONVERTED\n";
$converted++;
} catch (ddl_exception $e) {
@@ -163,7 +163,7 @@ if (!empty($options['collation'])) {
}
}
$sql = "SHOW FULL COLUMNS FROM $table->name WHERE collation IS NOT NULL";
$sql = "SHOW FULL COLUMNS FROM `$table->name` WHERE collation IS NOT NULL";
$rs2 = $DB->get_recordset_sql($sql);
foreach ($rs2 as $column) {
$column = (object)array_change_key_case((array)$column, CASE_LOWER);
@@ -181,7 +181,7 @@ if (!empty($options['collation'])) {
$notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL';
$default = (!is_null($column->default) and $column->default !== '') ? "DEFAULT '$column->default'" : '';
// primary, unique and inc are not supported for texts
$sql = "ALTER TABLE $table->name
$sql = "ALTER TABLE `$table->name`
MODIFY COLUMN $column->field $column->type
CHARACTER SET $charset
COLLATE $collation $notnull $default";
@@ -192,11 +192,11 @@ if (!empty($options['collation'])) {
$default = !is_null($column->default) ? "DEFAULT '$column->default'" : '';
if ($rowformat != '') {
$sql = "ALTER TABLE $table->name $rowformat";
$sql = "ALTER TABLE `$table->name` $rowformat";
$DB->change_database_structure($sql);
}
$sql = "ALTER TABLE $table->name
$sql = "ALTER TABLE `$table->name`
MODIFY COLUMN $column->field $column->type
CHARACTER SET $charset
COLLATE $collation $notnull $default";
@@ -315,8 +315,8 @@ function mysql_set_row_format($tablename, $charset, $collation, $engine) {
if ($rs->row_format == 'Compact' || $rs->row_format == 'Redundant') {
$rowformat = $DB->get_row_format_sql($engine, $collation);
// Try to convert to compressed format and then try updating the collation again.
$DB->change_database_structure("ALTER TABLE $tablename $rowformat");
$DB->change_database_structure("ALTER TABLE $tablename CONVERT TO CHARACTER SET $charset COLLATE $collation");
$DB->change_database_structure("ALTER TABLE `$tablename` $rowformat");
$DB->change_database_structure("ALTER TABLE `$tablename` CONVERT TO CHARACTER SET $charset COLLATE $collation");
} else {
// Row format may not be the problem. Can not diagnose problem. Send fail reply.
return false;
+2 -2
View File
@@ -158,7 +158,7 @@ if (!empty($options['info'])) {
}
foreach ($fixtables as $table) {
$DB->change_database_structure("ALTER TABLE {$prefix}$table ROW_FORMAT=Compressed");
$DB->change_database_structure("ALTER TABLE `{$prefix}$table` ROW_FORMAT=Compressed");
echo str_pad($prefix . $table, 32, ' ', STR_PAD_RIGHT) . " ... Compressed\n";
}
@@ -189,7 +189,7 @@ if (!empty($options['info'])) {
echo "SET GLOBAL innodb_file_per_table=1;\n";
echo "SET GLOBAL innodb_file_format=Barracuda;\n";
foreach ($fixtables as $table) {
echo "ALTER TABLE {$prefix}$table ROW_FORMAT=Compressed;\n";
echo "ALTER TABLE `{$prefix}$table` ROW_FORMAT=Compressed;\n";
}
echo "\n";
exit(0);
+3 -1
View File
@@ -3447,7 +3447,7 @@
</PHP_EXTENSION>
<PHP_EXTENSION name="hash" level="required"/>
<PHP_EXTENSION name="fileinfo" level="required"/>
<PHP_EXTENSION name="sodium" level="required"/>
<PHP_EXTENSION name="sodium" level="optional"/>
</PHP_EXTENSIONS>
<PHP_SETTINGS>
<PHP_SETTING name="memory_limit" value="96M" level="required">
@@ -3527,6 +3527,8 @@
<ON_CHECK message="sixtyfourbitswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
</COMPATIBILITY_MATRIX>
+5 -4
View File
@@ -45,7 +45,7 @@ list($options, $unrecognised) = cli_get_params(
array(
'stop-on-failure' => 0,
'verbose' => false,
'replace' => false,
'replace' => '',
'help' => false,
'tags' => '',
'profile' => '',
@@ -70,7 +70,7 @@ $help = "
Behat utilities to run behat tests in parallel
Usage:
php run.php [--BEHAT_OPTION=\"value\"] [--feature=\"value\"] [--replace] [--fromrun=value --torun=value] [--help]
php run.php [--BEHAT_OPTION=\"value\"] [--feature=\"value\"] [--replace=\"{run}\"] [--fromrun=value --torun=value] [--help]
Options:
--BEHAT_OPTION Any combination of behat option specified in http://behat.readthedocs.org/en/v2.5/guides/6.cli.html
@@ -144,9 +144,10 @@ $extraopts = $unrecognised;
if ($options['profile']) {
$profile = $options['profile'];
// If profile passed is not set, then exit.
// If profile passed is not set, then exit (note we skip if the 'replace' option is found within the 'profile' value).
if (!isset($CFG->behat_config[$profile]) && !isset($CFG->behat_profiles[$profile]) &&
!(isset($options['replace']) && (strpos($options['profile'], $options['replace']) >= 0 ))) {
!($options['replace'] && (strpos($profile, (string) $options['replace']) !== false))) {
echo "Invalid profile passed: " . $profile . PHP_EOL;
exit(1);
}
@@ -189,7 +189,12 @@ class cohort_role_assignments_table extends table_sql {
FROM {tool_cohortroles} uca
JOIN {user} u ON u.id = uca.userid
JOIN {cohort} c ON c.id = uca.cohortid";
$params = array();
// Check if any additional filtering is required.
[$sqlwhere, $params] = $this->get_sql_where();
if ($sqlwhere) {
$sql .= " WHERE {$sqlwhere}";
}
// Add order by if needed.
if (!$count && $sqlsort = $this->get_sql_sort()) {
+2 -2
View File
@@ -86,8 +86,8 @@ if ($removeid) {
$title = get_string('existingcohortroles', 'tool_cohortroles');
echo $output->heading($title);
$url = new moodle_url('/admin/tool/cohortroles/index.php');
$table = new tool_cohortroles\output\cohort_role_assignments_table(uniqid(), $url);
$table = new tool_cohortroles\output\cohort_role_assignments_table('cohort-role-assignments', $pageurl);
echo $table->out(50, true);
echo $output->spacer();
@@ -37,67 +37,68 @@
This template does not have an example context because it includes ajax functionality.
}}
<div data-region="user-competency-full-info" data-node="user-competency" data-competencyid="{{usercompetency.competencyid}}" data-userid="{{usercompetency.userid}}" data-region-id="{{uniqid}}">
<div data-region="competency-summary">
{{#competency}}
{{> tool_lp/competency_summary }}
{{/competency}}
<dl>
{{#usercompetency}}
<dt>{{#str}}reviewstatus, tool_lp{{/str}}</dt>
<dd data-region="user-competency-status">{{statusname}}
<div data-region="competency-summary">
{{#competency}}
{{> tool_lp/competency_summary }}
{{/competency}}
<dl>
{{#usercompetency}}
<dt>{{#str}}reviewstatus, tool_lp{{/str}}</dt>
<dd data-region="user-competency-status">{{statusname}}
{{#isstatusinreview}}
- {{reviewer.fullname}}
{{/isstatusinreview}}
{{#isstatusinreview}}
- {{reviewer.fullname}}
{{/isstatusinreview}}
{{#isrequestreviewallowed}}<button class="btn btn-secondary" data-action="request-review">{{#str}}requestreview, tool_lp{{/str}}</button>{{/isrequestreviewallowed}}
{{#iscancelreviewrequestallowed}}<button class="btn btn-secondary" data-action="cancel-review-request">{{#str}}cancelreviewrequest, tool_lp{{/str}}</button>{{/iscancelreviewrequestallowed}}
{{#isstartreviewallowed}}<button class="btn btn-secondary" data-action="start-review">{{#str}}startreview, tool_lp{{/str}}</button>{{/isstartreviewallowed}}
{{#isstopreviewallowed}}<button class="btn btn-secondary" data-action="stop-review">{{#str}}stopreview, tool_lp{{/str}}</button>{{/isstopreviewallowed}}
</dd>
<dt>{{#str}}proficient, tool_lp{{/str}}</dt>
<dd>
<span class="badge {{#proficiency}}badge-success{{/proficiency}}{{^proficiency}}badge-danger{{/proficiency}} float-left">
{{proficiencyname}}
</span>
</dd>
<dt>{{#str}}rating, tool_lp{{/str}}</dt>
<dd>{{gradename}}
{{#cangrade}}
<button class="btn btn-secondary" id="rate_{{uniqid}}">{{#str}}rate, tool_lp{{/str}}</button>
{{/cangrade}}
</dd>
{{#js}}
require(['jquery', 'tool_lp/grade_user_competency_inline', 'tool_lp/user_competency_info', 'tool_lp/user_competency_workflow'], function($, mod, info, UserCompWorkflow) {
{{#isrequestreviewallowed}}<button class="btn btn-secondary" data-action="request-review">{{#str}}requestreview, tool_lp{{/str}}</button>{{/isrequestreviewallowed}}
{{#iscancelreviewrequestallowed}}<button class="btn btn-secondary" data-action="cancel-review-request">{{#str}}cancelreviewrequest, tool_lp{{/str}}</button>{{/iscancelreviewrequestallowed}}
{{#isstartreviewallowed}}<button class="btn btn-secondary" data-action="start-review">{{#str}}startreview, tool_lp{{/str}}</button>{{/isstartreviewallowed}}
{{#isstopreviewallowed}}<button class="btn btn-secondary" data-action="stop-review">{{#str}}stopreview, tool_lp{{/str}}</button>{{/isstopreviewallowed}}
</dd>
<dt>{{#str}}proficient, tool_lp{{/str}}</dt>
<dd>
<span class="badge {{#proficiency}}badge-success{{/proficiency}}{{^proficiency}}badge-danger{{/proficiency}} float-left">
{{proficiencyname}}
</span>
</dd>
<dt>{{#str}}rating, tool_lp{{/str}}</dt>
<dd>{{gradename}}
{{#cangrade}}
<button class="btn btn-secondary" id="rate_{{uniqid}}">{{#str}}rate, tool_lp{{/str}}</button>
{{/cangrade}}
</dd>
{{#js}}
require(['jquery', 'tool_lp/grade_user_competency_inline', 'tool_lp/user_competency_info', 'tool_lp/user_competency_workflow'], function($, mod, info, UserCompWorkflow) {
var competencyElement = $('[data-region-id="{{uniqid}}"]');
var infoReloader = new info(competencyElement, '{{competency.competency.id}}', '{{user.id}}');
var competencyElement = $('[data-region-id="{{uniqid}}"]');
var infoReloader = new info(competencyElement, '{{competency.competency.id}}', '{{user.id}}');
var ucw = new UserCompWorkflow();
ucw.registerEvents('[data-region="user-competency-status"]');
ucw.on('status-changed', infoReloader.reload.bind(infoReloader));
ucw.on('error-occured', infoReloader.reload.bind(infoReloader));
var ucw = new UserCompWorkflow();
ucw.registerEvents('[data-region="user-competency-status"]');
ucw.on('status-changed', infoReloader.reload.bind(infoReloader));
ucw.on('error-occured', infoReloader.reload.bind(infoReloader));
var inlineGrader = new mod('#rate_{{uniqid}}', '{{competency.scaleid}}', '{{competency.competency.id}}', '{{user.id}}', '{{plan.id}}', '', '{{#str}}chooserating, tool_lp{{/str}}');
inlineGrader.on('competencyupdated', infoReloader.reload.bind(infoReloader));
});
{{/js}}
{{/usercompetency}}
</dl>
{{#commentarea}}
{{#canpostorhascomments}}
{{>tool_lp/comment_area}}
{{/canpostorhascomments}}
{{/commentarea}}
<dl data-region="evidence-listing">
<dt>{{#str}}evidence, tool_lp{{/str}}</dt>
<dd>
{{#evidence}}
{{> tool_lp/evidence_summary }}
{{/evidence}}
{{^evidence}}
<p>{{#str}}noevidence, tool_lp{{/str}}</p>
{{/evidence}}
</dd>
</dl>
var inlineGrader = new mod('#rate_{{uniqid}}', '{{competency.scaleid}}', '{{competency.competency.id}}', '{{user.id}}', '{{plan.id}}', '', '{{#str}}chooserating, tool_lp{{/str}}');
inlineGrader.on('competencyupdated', infoReloader.reload.bind(infoReloader));
});
{{/js}}
{{/usercompetency}}
</dl>
{{#commentarea}}
{{#canpostorhascomments}}
{{>tool_lp/comment_area}}
{{/canpostorhascomments}}
{{/commentarea}}
<dl data-region="evidence-listing">
<dt>{{#str}}evidence, tool_lp{{/str}}</dt>
<dd>
{{#evidence}}
{{> tool_lp/evidence_summary }}
{{/evidence}}
{{^evidence}}
<p>{{#str}}noevidence, tool_lp{{/str}}</p>
{{/evidence}}
</dd>
</dl>
</div>
</div>
+24 -22
View File
@@ -170,32 +170,34 @@ function tool_mobile_myprofile_navigation(\core_user\output\myprofile\tree $tree
}
// Check if the user is using the app, encouraging him to use it otherwise.
$usertoken = tool_mobile_get_token($user->id);
$mobilestrconnected = null;
$mobilelastaccess = null;
if ($iscurrentuser || is_siteadmin()) {
$usertoken = tool_mobile_get_token($user->id);
$mobilestrconnected = null;
$mobilelastaccess = null;
if ($usertoken) {
$mobilestrconnected = get_string('lastsiteaccess');
if ($usertoken->lastaccess) {
$mobilelastaccess = userdate($usertoken->lastaccess) . "&nbsp; (" . format_time(time() - $usertoken->lastaccess) . ")";
// Logout link.
$validtoken = empty($usertoken->validuntil) || time() < $usertoken->validuntil;
if ($iscurrentuser && $validtoken) {
$url = new moodle_url('/'.$CFG->admin.'/tool/mobile/logout.php', ['sesskey' => sesskey()]);
$logoutlink = html_writer::link($url, get_string('logout'));
$mobilelastaccess .= "&nbsp; ($logoutlink)";
if ($usertoken) {
$mobilestrconnected = get_string('lastsiteaccess');
if ($usertoken->lastaccess) {
$mobilelastaccess = userdate($usertoken->lastaccess) . "&nbsp; (" . format_time(time() - $usertoken->lastaccess) . ")";
// Logout link.
$validtoken = empty($usertoken->validuntil) || time() < $usertoken->validuntil;
if ($iscurrentuser && $validtoken) {
$url = new moodle_url('/'.$CFG->admin.'/tool/mobile/logout.php', ['sesskey' => sesskey()]);
$logoutlink = html_writer::link($url, get_string('logout'));
$mobilelastaccess .= "&nbsp; ($logoutlink)";
}
} else {
// We should not reach this point.
$mobilelastaccess = get_string("never");
}
} else {
// We should not reach this point.
$mobilelastaccess = get_string("never");
} else if ($url = tool_mobile_create_app_download_url()) {
$mobilestrconnected = get_string('mobileappenabled', 'tool_mobile', $url->out());
}
} else if ($url = tool_mobile_create_app_download_url()) {
$mobilestrconnected = get_string('mobileappenabled', 'tool_mobile', $url->out());
}
if ($mobilestrconnected) {
$newnodes[] = new core_user\output\myprofile\node('mobile', 'mobileappnode', $mobilestrconnected, null, null,
$mobilelastaccess);
if ($mobilestrconnected) {
$newnodes[] = new core_user\output\myprofile\node('mobile', 'mobileappnode', $mobilestrconnected, null, null,
$mobilelastaccess);
}
}
// Add nodes, if any.
@@ -310,11 +310,10 @@ class profile_manager {
'CURLOPT_HEADER' => 0,
];
$content = $curl->get($url, null, $options);
$errno = $curl->get_errno();
$info = $curl->get_info();
// The base cURL seems fine, let's press on.
if (!$errno) {
if (!$curl->get_errno() && !$curl->error) {
// WebFinger gave us a 404 back so the user has no droids here.
if ($info['http_code'] >= 400) {
if ($info['http_code'] === 404) {
+1 -11
View File
@@ -438,17 +438,7 @@ class manager {
$filename = 'tour_export_' . $tour->get_id() . '_' . time() . '.json';
// Force download.
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
header('Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0');
header('Expires: ' . gmdate('D, d M Y H:i:s', 0) . 'GMT');
header('Pragma: no-cache');
header('Accept-Ranges: none');
header('Content-disposition: attachment; filename=' . $filename);
header('Content-length: ' . strlen($exportstring));
header('Content-type: text/calendar; charset=utf-8');
echo $exportstring;
die;
send_file($exportstring, $filename, 0, 0, true, true);
}
/**
+27
View File
@@ -178,6 +178,33 @@ class prediction {
\core\event\prediction_action_started::create($eventdata)->trigger();
}
/**
* Get the executed actions.
*
* Actions could be filtered by actionname.
*
* @param array $actionnamefilter Limit the results obtained to this list of action names.
* @param int $userid the user id. Current user by default.
* @return array of actions.
*/
public function get_executed_actions(array $actionnamefilter = null, int $userid = 0): array {
global $USER, $DB;
$conditions[] = "predictionid = :predictionid";
$params['predictionid'] = $this->get_prediction_data()->id;
if (!$userid) {
$userid = $USER->id;
}
$conditions[] = "userid = :userid";
$params['userid'] = $userid;
if ($actionnamefilter) {
list($actionsql, $actionparams) = $DB->get_in_or_equal($actionnamefilter, SQL_PARAMS_NAMED);
$conditions[] = "actionname $actionsql";
$params = $params + $actionparams;
}
return $DB->get_records_select('analytics_prediction_actions', implode(' AND ', $conditions), $params);
}
/**
* format_calculations
*
@@ -112,6 +112,86 @@ class analytics_prediction_actions_testcase extends advanced_testcase {
$this->assertEquals(2, $DB->count_records('analytics_prediction_actions'));
}
/**
* Data provider for test_get_executed_actions.
*
* @return array
*/
public function execute_actions_provider(): array {
return [
'Empty actions with no filter' => [
[],
[],
0
],
'Empty actions with filter' => [
[],
[\core_analytics\prediction::ACTION_FIXED],
0
],
'Multiple actions with no filter' => [
[
\core_analytics\prediction::ACTION_FIXED,
\core_analytics\prediction::ACTION_FIXED,
\core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED
],
[],
3
],
'Multiple actions applying filter' => [
[
\core_analytics\prediction::ACTION_FIXED,
\core_analytics\prediction::ACTION_FIXED,
\core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED
],
[\core_analytics\prediction::ACTION_FIXED],
2
],
'Multiple actions not applying filter' => [
[
\core_analytics\prediction::ACTION_FIXED,
\core_analytics\prediction::ACTION_FIXED,
\core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED
],
[\core_analytics\prediction::ACTION_NOT_APPLICABLE],
0
],
'Multiple actions with multiple filter' => [
[
\core_analytics\prediction::ACTION_FIXED,
\core_analytics\prediction::ACTION_FIXED,
\core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED
],
[\core_analytics\prediction::ACTION_FIXED, \core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED],
3
],
];
}
/**
* Tests for get_executed_actions() function.
*
* @dataProvider execute_actions_provider
* @param array $actionstoexecute An array of actions to execute
* @param array $actionnamefilter Actions to filter
* @param int $returned Number of actions returned
*
* @covers \core_analytics\prediction::get_executed_actions
*/
public function test_get_executed_actions(array $actionstoexecute, array $actionnamefilter, int $returned) {
$this->setUser($this->teacher2);
list($ignored, $predictions) = $this->model->get_predictions($this->context, true);
$prediction = reset($predictions);
$target = $this->model->get_target();
foreach($actionstoexecute as $action) {
$prediction->action_executed($action, $target);
}
$filteredactions = $prediction->get_executed_actions($actionnamefilter);
$this->assertCount($returned, $filteredactions);
}
/**
* test_get_predictions
*/
+5
View File
@@ -1,6 +1,11 @@
This files describes API changes in analytics sub system,
information provided here is intended especially for developers.
=== 3.10.4 ===
* A new function get_executed_actions() has been added to \core_analytics\prediction class
to get all (or filtered by action name) executed actions of a prediction
=== 3.8 ===
* "Time-splitting method" have been replaced by "Analysis interval" for the language strings that are
+1 -1
View File
@@ -45,7 +45,7 @@ $string['auth_dbname'] = 'Name of the database itself. Leave empty if using an O
$string['auth_dbname_key'] = 'DB name';
$string['auth_dbpass'] = 'Password matching the above username';
$string['auth_dbpass_key'] = 'Password';
$string['auth_dbpasstype'] = '<p>Specify the format that the password field is using.</p> <p>Use \'internal\' if you want the external database to manage usernames and email addresses, but Moodle to manage passwords. If you use \'internal\', you <i>must</i> provide a populated email address field in the external database, and you must execute both admin/cron.php and auth/db/cli/sync_users.php regularly. Moodle will send an email to new users with a temporary password.</p>';
$string['auth_dbpasstype'] = '<p>Specify the format that the password field is using.</p> <p>Use \'internal\' if you want the external database to manage usernames and email addresses, but Moodle to manage passwords. If you use \'internal\', you must provide a populated email address field in the external database, and you must enable the \auth_db\task\sync_users scheduled task. Moodle will send an email to new users with a temporary password.</p>';
$string['auth_dbpasstype_key'] = 'Password format';
$string['auth_dbreviveduser'] = 'Revived user {$a->name} id {$a->id}';
$string['auth_dbrevivedusererror'] = 'Error reviving user {$a}';
+1 -1
View File
@@ -75,7 +75,7 @@ $string['auth_ldap_passwdexpire_settings'] = 'LDAP password expiry settings';
$string['auth_ldap_preventpassindb'] = 'Select yes to prevent passwords from being stored in Moodle\'s DB.';
$string['auth_ldap_preventpassindb_key'] = 'Prevent password caching';
$string['auth_ldap_rolecontext'] = '{$a->localname} context';
$string['auth_ldap_rolecontext_help'] = 'LDAP context used to select for <i>{$a->localname}</i> mapping. Separate multiple groups with \';\'. Usually something like "cn={$a->shortname},ou=staff,o=myorg".';
$string['auth_ldap_rolecontext_help'] = 'LDAP context used to select for <i>{$a->localname}</i> mapping. Separate multiple groups with \';\'. Usually something like "cn={$a->shortname},ou=first-ou-with-role-groups,o=myorg; cn={$a->shortname},ou=second-ou-with-role-groups,o=myorg".';
$string['auth_ldap_search_sub'] = 'Search users from subcontexts.';
$string['auth_ldap_search_sub_key'] = 'Search subcontexts';
$string['auth_ldap_server_settings'] = 'LDAP server settings';
+1 -3
View File
@@ -710,9 +710,7 @@ class auth_plugin_mnet extends auth_plugin_base {
foreach($superArray as $subArray) {
$subArray = array_values($subArray);
$instring = "('".implode("', '",$subArray)."')";
$query = "select id, session_id, username from {mnet_session} where username in $instring";
$results = $DB->get_records_sql($query);
$results = $DB->get_records_list('mnet_session', 'username', $subArray, '', 'id, session_id, username');
if ($results == false) {
// We seem to have a username that breaks our query:
+6 -6
View File
@@ -290,9 +290,9 @@ abstract class info {
*/
protected function warn_about_invalid_availability(\coding_exception $e) {
$name = $this->get_thing_name();
// If it occurs while building modinfo based on somebody calling $cm->name,
// we can't get $cm->name, and this line will cause a warning.
$htmlname = @$this->format_info($name, $this->course);
$htmlname = $this->format_info($name, $this->course);
// Because we call format_info here, likely in the middle of building dynamic data for the
// activity, there could be a chance that the name might not be available.
if ($htmlname === '') {
// So instead use the numbers (cmid) from the tag.
$htmlname = preg_replace('~[^0-9]~', '', $name);
@@ -739,11 +739,11 @@ abstract class info {
$info = preg_replace_callback('~<AVAILABILITY_CMNAME_([0-9]+)/>~',
function($matches) use($modinfo, $context) {
$cm = $modinfo->get_cm($matches[1]);
if ($cm->has_view() and $cm->uservisible) {
if ($cm->has_view() and $cm->get_user_visible()) {
// Help student by providing a link to the module which is preventing availability.
return \html_writer::link($cm->url, format_string($cm->name, true, array('context' => $context)));
return \html_writer::link($cm->get_url(), format_string($cm->get_name(), true, ['context' => $context]));
} else {
return format_string($cm->name, true, array('context' => $context));
return format_string($cm->get_name(), true, ['context' => $context]);
}
}, $info);
+29
View File
@@ -511,4 +511,33 @@ class info_testcase extends advanced_testcase {
sort($result);
$this->assertEquals($expected, $result);
}
/**
* Tests the info_module class when involved in a recursive call to $cm->name.
*/
public function test_info_recursive_name_call() {
global $DB;
$this->resetAfterTest();
// Create a course and page.
$generator = $this->getDataGenerator();
$course = $generator->create_course();
$page1 = $generator->create_module('page', ['course' => $course->id, 'name' => 'Page1']);
// Set invalid availability.
$DB->set_field('course_modules', 'availability', 'not valid', ['id' => $page1->cmid]);
// Get the cm_info object.
$this->setAdminUser();
$modinfo = get_fast_modinfo($course);
$cm1 = $modinfo->get_cm($page1->cmid);
// At this point we will generate dynamic data for $cm1, which will cause the debugging
// call below.
$this->assertEquals('Page1', $cm1->name);
$this->assertDebuggingCalled('Error processing availability data for ' .
'&lsquo;Page1&rsquo;: Invalid availability text');
}
}
@@ -198,8 +198,11 @@ M.core_availability.form = {
// If the groupmode and grouping id aren't set, disable it.
var groupmode = Y.one('#id_groupmode');
var groupingid = Y.one('#id_groupingid');
if ((!groupmode || Number(groupmode.get('value')) === 0) &&
(!groupingid || Number(groupingid.get('value')) === 0)) {
var groupavailability = Number(this.restrictByGroup.getData('groupavailability')) === 1;
var groupingavailability = Number(this.restrictByGroup.getData('groupingavailability')) === 1;
if ((!groupmode || Number(groupmode.get('value')) === 0 || !groupavailability) &&
(!groupingid || Number(groupingid.get('value')) === 0 || !groupingavailability)) {
this.restrictByGroup.set('disabled', true);
return;
}
@@ -220,22 +223,28 @@ M.core_availability.form = {
e.preventDefault();
// Add the condition.
var groupmode = Y.one('#id_groupmode');
var groupingid = Y.one('#id_groupingid');
var groupavailability = Number(this.restrictByGroup.getData('groupavailability')) === 1;
var groupingavailability = Number(this.restrictByGroup.getData('groupingavailability')) === 1;
var newChild;
if (groupingid && Number(groupingid.get('value')) !== 0) {
if (groupingid && Number(groupingid.get('value')) !== 0 && groupingavailability) {
// Add a grouping restriction if one is specified.
newChild = new M.core_availability.Item(
{type: 'grouping', id: Number(groupingid.get('value'))}, true);
} else {
} else if (groupmode && groupavailability) {
// Otherwise just add a group restriction.
newChild = new M.core_availability.Item({type: 'group'}, true);
}
// Refresh HTML.
this.rootList.addChild(newChild);
this.update();
this.rootList.renumber();
this.rootList.updateHtml();
if (newChild !== null) {
this.rootList.addChild(newChild);
this.update();
this.rootList.renumber();
this.rootList.updateHtml();
}
}
};
File diff suppressed because one or more lines are too long
@@ -198,8 +198,11 @@ M.core_availability.form = {
// If the groupmode and grouping id aren't set, disable it.
var groupmode = Y.one('#id_groupmode');
var groupingid = Y.one('#id_groupingid');
if ((!groupmode || Number(groupmode.get('value')) === 0) &&
(!groupingid || Number(groupingid.get('value')) === 0)) {
var groupavailability = Number(this.restrictByGroup.getData('groupavailability')) === 1;
var groupingavailability = Number(this.restrictByGroup.getData('groupingavailability')) === 1;
if ((!groupmode || Number(groupmode.get('value')) === 0 || !groupavailability) &&
(!groupingid || Number(groupingid.get('value')) === 0 || !groupingavailability)) {
this.restrictByGroup.set('disabled', true);
return;
}
@@ -220,22 +223,28 @@ M.core_availability.form = {
e.preventDefault();
// Add the condition.
var groupmode = Y.one('#id_groupmode');
var groupingid = Y.one('#id_groupingid');
var groupavailability = Number(this.restrictByGroup.getData('groupavailability')) === 1;
var groupingavailability = Number(this.restrictByGroup.getData('groupingavailability')) === 1;
var newChild;
if (groupingid && Number(groupingid.get('value')) !== 0) {
if (groupingid && Number(groupingid.get('value')) !== 0 && groupingavailability) {
// Add a grouping restriction if one is specified.
newChild = new M.core_availability.Item(
{type: 'grouping', id: Number(groupingid.get('value'))}, true);
} else {
} else if (groupmode && groupavailability) {
// Otherwise just add a group restriction.
newChild = new M.core_availability.Item({type: 'group'}, true);
}
// Refresh HTML.
this.rootList.addChild(newChild);
this.update();
this.rootList.renumber();
this.rootList.updateHtml();
if (newChild !== null) {
this.rootList.addChild(newChild);
this.update();
this.rootList.renumber();
this.rootList.updateHtml();
}
}
};
+17 -8
View File
@@ -196,8 +196,11 @@ M.core_availability.form = {
// If the groupmode and grouping id aren't set, disable it.
var groupmode = Y.one('#id_groupmode');
var groupingid = Y.one('#id_groupingid');
if ((!groupmode || Number(groupmode.get('value')) === 0) &&
(!groupingid || Number(groupingid.get('value')) === 0)) {
var groupavailability = Number(this.restrictByGroup.getData('groupavailability')) === 1;
var groupingavailability = Number(this.restrictByGroup.getData('groupingavailability')) === 1;
if ((!groupmode || Number(groupmode.get('value')) === 0 || !groupavailability) &&
(!groupingid || Number(groupingid.get('value')) === 0 || !groupingavailability)) {
this.restrictByGroup.set('disabled', true);
return;
}
@@ -218,22 +221,28 @@ M.core_availability.form = {
e.preventDefault();
// Add the condition.
var groupmode = Y.one('#id_groupmode');
var groupingid = Y.one('#id_groupingid');
var groupavailability = Number(this.restrictByGroup.getData('groupavailability')) === 1;
var groupingavailability = Number(this.restrictByGroup.getData('groupingavailability')) === 1;
var newChild;
if (groupingid && Number(groupingid.get('value')) !== 0) {
if (groupingid && Number(groupingid.get('value')) !== 0 && groupingavailability) {
// Add a grouping restriction if one is specified.
newChild = new M.core_availability.Item(
{type: 'grouping', id: Number(groupingid.get('value'))}, true);
} else {
} else if (groupmode && groupavailability) {
// Otherwise just add a group restriction.
newChild = new M.core_availability.Item({type: 'group'}, true);
}
// Refresh HTML.
this.rootList.addChild(newChild);
this.update();
this.rootList.renumber();
this.rootList.updateHtml();
if (newChild !== null) {
this.rootList.addChild(newChild);
this.update();
this.rootList.renumber();
this.rootList.updateHtml();
}
}
};
+23 -2
View File
@@ -4055,9 +4055,30 @@ class restore_contentbankcontent_structure_step extends restore_structure_step {
$exists = $DB->record_exists('contentbank_content', $params);
if (!$exists) {
$params['configdata'] = $data->configdata;
$params['usercreated'] = $this->get_mappingid('user', $data->usercreated);
$params['usermodified'] = $this->get_mappingid('user', $data->usermodified);
$params['timemodified'] = time();
// Trying to map users. Users cannot always be mapped, e.g. when copying.
$params['usercreated'] = $this->get_mappingid('user', $data->usercreated);
if (!$params['usercreated']) {
// Leave the content creator unchanged when we are restoring the same site.
// Otherwise use current user id.
if ($this->task->is_samesite()) {
$params['usercreated'] = $data->usercreated;
} else {
$params['usercreated'] = $this->task->get_userid();
}
}
$params['usermodified'] = $this->get_mappingid('user', $data->usermodified);
if (!$params['usermodified']) {
// Leave the content modifier unchanged when we are restoring the same site.
// Otherwise use current user id.
if ($this->task->is_samesite()) {
$params['usermodified'] = $data->usermodified;
} else {
$params['usermodified'] = $this->task->get_userid();
}
}
$newitemid = $DB->insert_record('contentbank_content', $params);
$this->set_mapping('contentbank_content', $oldid, $newitemid, true);
}
+67
View File
@@ -278,6 +278,73 @@ class core_backup_automated_backup_testcase extends advanced_testcase {
$this->assertTrue($skipped);
$this->expectOutputRegex("/Skipping $course->fullname \(Not modified since previous backup\)/");
}
/**
* Test the task completes when coureid is missing.
*/
public function test_task_complete_when_courseid_is_missing() {
global $DB;
$admin = get_admin();
$classobject = $this->backupcronautomatedhelper->return_this();
// Create this backup course.
$backupcourse = new stdClass;
$backupcourse->courseid = $this->course->id;
$backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_NOTYETRUN;
$DB->insert_record('backup_courses', $backupcourse);
$backupcourse = $DB->get_record('backup_courses', ['courseid' => $this->course->id]);
// Create a backup task.
$method = new ReflectionMethod('\backup_cron_automated_helper', 'push_course_backup_adhoc_task');
$method->setAccessible(true); // Allow accessing of private method.
$method->invokeArgs($classobject, [$backupcourse, $admin]);
// Delete course for this test.
delete_course($this->course->id, false);
$task = core\task\manager::get_next_adhoc_task(time());
ob_start();
$task->execute();
$output = ob_get_clean();
$this->assertStringContainsString('Invalid course id: ' . $this->course->id . ', task aborted.', $output);
core\task\manager::adhoc_task_complete($task);
}
/**
* Test the task completes when backup course is missing.
*/
public function test_task_complete_when_backup_course_is_missing() {
global $DB;
$admin = get_admin();
$classobject = $this->backupcronautomatedhelper->return_this();
// Create this backup course.
$backupcourse = new stdClass;
$backupcourse->courseid = $this->course->id;
$backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_NOTYETRUN;
$DB->insert_record('backup_courses', $backupcourse);
$backupcourse = $DB->get_record('backup_courses', ['courseid' => $this->course->id]);
// Create a backup task.
$method = new ReflectionMethod('\backup_cron_automated_helper', 'push_course_backup_adhoc_task');
$method->setAccessible(true); // Allow accessing of private method.
$method->invokeArgs($classobject, [$backupcourse, $admin]);
// Delete backup course for this test.
$DB->delete_records('backup_courses', ['courseid' => $this->course->id]);
$task = core\task\manager::get_next_adhoc_task(time());
ob_start();
$task->execute();
$output = ob_get_clean();
$this->assertStringContainsString('Automated backup for course: ' . $this->course->fullname . ' encounters an error.',
$output);
core\task\manager::adhoc_task_complete($task);
}
}
/**
+1 -1
View File
@@ -1,7 +1,7 @@
This files describes API changes in /backup/*,
information provided here is intended especially for developers.
=== 4.0 ===
=== 3.10 ===
* Local plugins can now hook into a backup and restore process of grade items by
using define_grade_item_plugin_structure method (See MDL-69418).
+1 -1
View File
@@ -52,7 +52,7 @@ if (!is_null($action)) {
} else { // Revoked badge.
header("HTTP/1.0 410 Gone");
$assertion = array();
if ($obversion == OPEN_BADGES_V2) {
if ($obversion >= OPEN_BADGES_V2) {
$assertionurl = new moodle_url('/badges/assertion.php', array('b' => $hash));
$assertion['id'] = $assertionurl->out();
}
+4
View File
@@ -43,6 +43,10 @@ if ($persistedissuer) {
$returnurl = new moodle_url('/badges/backpack-connect.php',
['action' => 'authorization', 'sesskey' => sesskey(), 'backpackid' => $backpackid]);
// If scope is not passed as parameter, use the issuer supported scopes.
if (empty($scope)) {
$scope = $issuer->get('scopessupported');
}
$client = new core_badges\oauth2\client($issuer, $returnurl, $scope, $externalbackpack);
if ($client) {
if (!$client->is_logged_in()) {
+2 -2
View File
@@ -128,7 +128,7 @@ class core_badges_assertion {
$email = empty($this->_data->backpackemail) ? $this->_data->email : $this->_data->backpackemail;
$assertionurl = new moodle_url('/badges/assertion.php', array('b' => $hash, 'obversion' => $this->_obversion));
if ($this->_obversion == OPEN_BADGES_V2) {
if ($this->_obversion >= OPEN_BADGES_V2) {
$classurl = new moodle_url('/badges/badge_json.php', array('id' => $this->get_badge_id()));
} else {
$classurl = new moodle_url('/badges/assertion.php', array('b' => $hash, 'action' => 1));
@@ -325,7 +325,7 @@ class core_badges_assertion {
*/
protected function embed_data_badge_version2 (&$json, $type = OPEN_BADGES_V2_TYPE_ASSERTION) {
// Specification Version 2.0.
if ($this->_obversion == OPEN_BADGES_V2) {
if ($this->_obversion >= OPEN_BADGES_V2) {
$badge = new badge($this->_data->id);
if (empty($this->_data->courseid)) {
$context = context_system::instance();
+2 -2
View File
@@ -56,12 +56,12 @@ class external_backpack extends \moodleform {
$mform->addElement('text', 'backpackapiurl', get_string('backpackapiurl', 'core_badges'));
$mform->setType('backpackapiurl', PARAM_URL);
$mform->addRule('backpackapiurl', null, 'required', null, 'client');
$mform->addRule('backpackapiurl', get_string('maximumchars', '', 255), 'maxlength', 50, 'client');
$mform->addRule('backpackapiurl', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
$mform->addElement('text', 'backpackweburl', get_string('backpackweburl', 'core_badges'));
$mform->setType('backpackweburl', PARAM_URL);
$mform->addRule('backpackweburl', null, 'required', null, 'client');
$mform->addRule('backpackweburl', get_string('maximumchars', '', 255), 'maxlength', 50, 'client');
$mform->addRule('backpackweburl', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
$apiversions = badges_get_badge_api_versions();
$mform->addElement('select', 'apiversion', get_string('apiversion', 'core_badges'), $apiversions);
+6 -3
View File
@@ -222,6 +222,7 @@ class client extends \core\oauth2\client {
$callbackurl = self::callback_url();
if ($granttype == 'authorization_code') {
$this->basicauth = true;
$params = array('code' => $code,
'grant_type' => $granttype,
'redirect_uri' => $callbackurl->out(false),
@@ -236,7 +237,7 @@ class client extends \core\oauth2\client {
);
}
if ($this->basicauth) {
$idsecret = urlencode($this->clientid) . ':' . urlencode($this->clientsecret);
$idsecret = $this->clientid . ':' . $this->clientsecret;
$this->setHeader('Authorization: Basic ' . base64_encode($idsecret));
} else {
$params['client_id'] = $this->clientid;
@@ -244,11 +245,13 @@ class client extends \core\oauth2\client {
}
// Requests can either use http GET or POST.
$response = $this->post($this->token_url(), $this->build_post_data($params));
$r = json_decode($response);
if ($this->info['http_code'] !== 200) {
throw new moodle_exception('Could not upgrade oauth token');
$debuginfo = !empty($this->error) ? $this->error : $response;
throw new moodle_exception('oauth2refreshtokenerror', 'core_error', '', $this->info['http_code'], $debuginfo);
}
$r = json_decode($response);
if (is_null($r)) {
throw new moodle_exception("Could not decode JSON token response");
}
+13 -3
View File
@@ -240,13 +240,23 @@ class award_criteria_cohort extends award_criteria {
return array($join, $where, $params);
} else {
// User is a member of ALL of the specified cohorts.
$join = " LEFT JOIN {cohort_members} cm ON cm.userid = u.id";
$join = ' LEFT JOIN {cohort_members} cm ON cm.userid = u.id';
$where = ' AND (';
$i = 0;
foreach ($this->params as $param) {
$i++;
$where = ' AND cm.cohortid = :cohortid'.$i;
if ($i == 0) {
$where .= 'cm.cohortid = :cohortid'.$i;
} else {
$where .= ' OR cm.cohortid = :cohortid'.$i;
}
$params['cohortid'.$i] = $param['cohort'];
$i++;
}
$where .= ')
GROUP BY u.id, bi.badgeid
HAVING COUNT(cm.cohortid) = :cohortcount';
$params['cohortcount'] = $i;
return array($join, $where, $params);
}
}
+110 -8
View File
@@ -624,35 +624,127 @@ class core_badges_badgeslib_testcase extends advanced_testcase {
}
/**
* Test badges observer when cohort_member_added event is fired.
* Test badges observer when cohort_member_added event is fired and user required to belong to any cohort.
*
* @covers award_criteria_cohort
*/
public function test_badges_observer_cohort_criteria_review() {
public function test_badges_observer_any_cohort_criteria_review() {
global $CFG;
require_once("$CFG->dirroot/cohort/lib.php");
$cohort = $this->getDataGenerator()->create_cohort();
$cohort1 = $this->getDataGenerator()->create_cohort();
$cohort2 = $this->getDataGenerator()->create_cohort();
$this->preventResetByRollback(); // Messaging is not compatible with transactions.
$badge = new badge($this->badgeid);
$this->assertFalse($badge->is_issued($this->user->id));
$this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql().
// Set up the badge criteria.
$criteriaoverall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id));
$criteriaoverall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY));
$criteriaoverall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_COHORT, 'badgeid' => $badge->id));
$criteriaoverall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY, 'cohort_cohorts' => array('0' => $cohort->id)));
// Make the badge active.
$criteriaoverall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY,
'cohort_cohorts' => array('0' => $cohort1->id, '1' => $cohort2->id)));
$badge->set_status(BADGE_STATUS_ACTIVE);
// Reload it to contain criteria.
$badge = new badge($this->badgeid);
$this->assertFalse($badge->is_issued($this->user->id));
$this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql().
// Add the user to the cohort.
cohort_add_member($cohort->id, $this->user->id);
cohort_add_member($cohort2->id, $this->user->id);
$this->assertDebuggingCalled();
// Verify that the badge was awarded.
$this->assertDebuggingCalled();
$this->assertTrue($badge->is_issued($this->user->id));
// As the badge has been awarded to user because core_badges_observer been called when the member has been added to the
// cohort, there are no other users that can award this badge.
$this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql().
}
/**
* Test badges observer when cohort_member_added event is fired and user required to belong to multiple (all) cohorts.
*
* @covers award_criteria_cohort
*/
public function test_badges_observer_all_cohort_criteria_review() {
global $CFG;
require_once("$CFG->dirroot/cohort/lib.php");
$cohort1 = $this->getDataGenerator()->create_cohort();
$cohort2 = $this->getDataGenerator()->create_cohort();
$cohort3 = $this->getDataGenerator()->create_cohort();
// Add user2 to cohort1 and cohort3.
$user2 = $this->getDataGenerator()->create_user();
cohort_add_member($cohort3->id, $user2->id);
cohort_add_member($cohort1->id, $user2->id);
// Add user3 to cohort1, cohort2 and cohort3.
$user3 = $this->getDataGenerator()->create_user();
cohort_add_member($cohort1->id, $user3->id);
cohort_add_member($cohort2->id, $user3->id);
cohort_add_member($cohort3->id, $user3->id);
$this->preventResetByRollback(); // Messaging is not compatible with transactions.
// Cohort criteria are used in site badges.
$badge = new badge($this->badgeid);
$this->assertFalse($badge->is_issued($this->user->id));
$this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql().
// Set up the badge criteria.
$criteriaoverall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id));
$criteriaoverall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY));
$criteriaoverall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_COHORT, 'badgeid' => $badge->id));
$criteriaoverall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL,
'cohort_cohorts' => array('0' => $cohort1->id, '1' => $cohort2->id, '2' => $cohort3->id)));
$badge->set_status(BADGE_STATUS_ACTIVE);
// Reload it to contain criteria.
$badge = new badge($this->badgeid);
// Verify that the badge was not awarded yet (ALL cohorts are needed and review_all_criteria has to be called).
$this->assertFalse($badge->is_issued($this->user->id));
$this->assertFalse($badge->is_issued($user2->id));
$this->assertFalse($badge->is_issued($user3->id));
// Verify that after calling review_all_criteria, users with the criteria (user3) award the badge instantly.
$this->assertSame(1, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql().
$this->assertFalse($badge->is_issued($this->user->id));
$this->assertFalse($badge->is_issued($user2->id));
$this->assertTrue($badge->is_issued($user3->id));
$this->assertDebuggingCalled();
// Add the user to the cohort1.
cohort_add_member($cohort1->id, $this->user->id);
// Verify that the badge was not awarded yet (ALL cohorts are needed).
$this->assertFalse($badge->is_issued($this->user->id));
$this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql().
// Add the user to the cohort3.
cohort_add_member($cohort3->id, $this->user->id);
// Verify that the badge was not awarded yet (ALL cohorts are needed).
$this->assertFalse($badge->is_issued($this->user->id));
$this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql().
// Add user to cohort2.
cohort_add_member($cohort2->id, $this->user->id);
$this->assertDebuggingCalled();
// Verify that the badge was awarded (ALL cohorts).
$this->assertTrue($badge->is_issued($this->user->id));
// As the badge has been awarded to user because core_badges_observer been called when the member has been added to the
// cohort, there are no other users that can award this badge.
$this->assertSame(0, $badge->review_all_criteria()); // Verify award_criteria_cohort->get_completed_criteria_sql().
}
/**
@@ -698,6 +790,16 @@ class core_badges_badgeslib_testcase extends advanced_testcase {
$this->assertStringMatchesFormat($testassertion2->badge, json_encode($assertion2->get_badge_assertion()));
$this->assertStringMatchesFormat($testassertion2->class, json_encode($assertion2->get_badge_class()));
$this->assertStringMatchesFormat($testassertion2->issuer, json_encode($assertion2->get_issuer()));
// Test Openbadge specification version 2.1. It has the same format as OBv2.0.
// Get assertion version 2.1.
$award = reset($awards);
$assertion2 = new core_badges_assertion($award->uniquehash, OPEN_BADGES_V2P1);
// Make sure JSON strings have the same structure.
$this->assertStringMatchesFormat($testassertion2->badge, json_encode($assertion2->get_badge_assertion()));
$this->assertStringMatchesFormat($testassertion2->class, json_encode($assertion2->get_badge_class()));
$this->assertStringMatchesFormat($testassertion2->issuer, json_encode($assertion2->get_issuer()));
}
/**
@@ -23,7 +23,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['otherusers'] = 'Other Users ({$a})';
$string['otherusers'] = 'Other users ({$a})';
$string['onlinestatushiding_desc'] = 'If enabled, users have the option to hide their online status from other users.';
$string['configtimetosee'] = 'Number of minutes determining the period of inactivity after which a user is no longer considered to be online.';
$string['onlinestatushiding'] = 'Online status hiding';
@@ -37,7 +37,7 @@ Feature: The online users block allow you to see who is currently online on fron
When I log in as "student1"
And I am on site homepage
Then I should not see "Admin User" in the "Online users" "block"
And I should see "Other Users (1)" in the "Online users" "block"
And I should see "Other users (1)" in the "Online users" "block"
And I should see "Student 1" in the "Online users" "block"
And I should see "Student 2" in the "Online users" "block"
And I should see "3 online users" in the "Online users" "block"
@@ -79,7 +79,7 @@ Feature: The online users block allow you to see who is currently online on fron
And I am on site homepage
Then I should see "2 online user" in the "Online users" "block"
And I should not see "Admin" in the "Online users" "block"
And I should see "Other Users (1)" in the "Online users" "block"
And I should see "Other users (1)" in the "Online users" "block"
And I should see "Student 2" in the "Online users" "block"
And I should not see "Student 1" in the "Online users" "block"
And I log out
@@ -94,7 +94,7 @@ Feature: The online users block allow you to see who is currently online on fron
And I am on site homepage
Then I should see "3 online users" in the "Online users" "block"
And I should not see "Admin" in the "Online users" "block"
And I should see "Other Users (1)" in the "Online users" "block"
And I should see "Other users (1)" in the "Online users" "block"
And I should see "Student 2" in the "Online users" "block"
And I should see "Student 1" in the "Online users" "block"
@@ -138,7 +138,7 @@ Feature: The online users block allow you to see who is currently online on fron
And I am on site homepage
And I should see "2 online user" in the "Online users" "block"
And I should not see "Admin" in the "Online users" "block"
And I should see "Other Users (1)" in the "Online users" "block"
And I should see "Other users (1)" in the "Online users" "block"
And I should see "Student 2" in the "Online users" "block"
And I should not see "Student 1" in the "Online users" "block"
And I log out
@@ -148,6 +148,6 @@ Feature: The online users block allow you to see who is currently online on fron
When I am on site homepage
Then I should see "3 online users" in the "Online users" "block"
And I should not see "Admin" in the "Online users" "block"
And I should see "Other Users (1)" in the "Online users" "block"
And I should see "Other users (1)" in the "Online users" "block"
And I should see "Student 2" in the "Online users" "block"
And I should see "Student 1" in the "Online users" "block"
+3 -1
View File
@@ -42,19 +42,21 @@ class block_tag_youtube_edit_form extends block_edit_form {
// Category setting.
$categorychoices = ['0' => get_string('anycategory', 'block_tag_youtube')];
$hascategoryerror = false;
$categoryerror = '';
try {
// Get all video categories through an API call and add them to the category list.
$categorychoices += $this->block->get_categories();
} catch (Exception $e) {
$hascategoryerror = true;
$categoryerror = $e->getMessage();
}
$mform->addElement('select', 'config_category', get_string('category', 'block_tag_youtube'),
$categorychoices);
$mform->setDefault('config_category', 0);
if ($categoryerror) {
if ($hascategoryerror) {
$notification = $OUTPUT->notification(get_string('categoryerror', 'block_tag_youtube', $categoryerror),
'error');
$mform->addElement('static', 'config_category_error', '', $notification);
+96
View File
@@ -66,6 +66,102 @@ function create_event($properties) {
return $event->create($record);
}
/**
* Helper function to create a x number of events for each event type.
*
* @param int $quantity The quantity of events to be created.
* @return array List of created events.
*/
function create_standard_events(int $quantity): array {
$types = ['site', 'category', 'course', 'group', 'user'];
$events = [];
foreach ($types as $eventtype) {
// Create five events of each event type.
for ($i = 0; $i < $quantity; $i++) {
$events[] = create_event(['eventtype' => $eventtype]);
}
}
return $events;
}
/**
* Helper function to create an action event.
*
* @param array $data The event data.
* @return bool|calendar_event
*/
function create_action_event(array $data) {
global $CFG;
require_once($CFG->dirroot . '/calendar/lib.php');
if (!isset($data['modulename']) || !isset($data['instance'])) {
throw new coding_exception('Module and instance should be specified when creating an action event.');
}
$isuseroverride = isset($data->priority) && $data->priority == CALENDAR_EVENT_USER_OVERRIDE_PRIORITY;
if ($isuseroverride) {
if (!in_array($data['modulename'], ['assign', 'lesson', 'quiz'])) {
throw new coding_exception('Only assign, lesson and quiz modules supports overrides');
}
}
$event = array_merge($data, [
'eventtype' => isset($data['eventtype']) ? $data['eventtype'] : 'open',
'courseid' => isset($data['courseid']) ? $data['courseid'] : 0,
'instance' => $data['instance'],
'modulename' => $data['modulename'],
'type' => CALENDAR_EVENT_TYPE_ACTION,
]);
return create_event($event);
}
/**
* Helper function to create an user override calendar event.
*
* @param string $modulename The modulename.
* @param int $instanceid The instance id.
* @param int $userid The user id.
* @return calendar_event|false
*/
function create_user_override_event(string $modulename, int $instanceid, int $userid) {
if (!isset($userid)) {
throw new coding_exception('Must specify userid when creating a user override.');
}
return create_action_event([
'modulename' => $modulename,
'instance' => $instanceid,
'userid' => $userid,
'priority' => CALENDAR_EVENT_USER_OVERRIDE_PRIORITY,
]);
}
/**
* Helper function to create an group override calendar event.
*
* @param string $modulename The modulename.
* @param int $instanceid The instance id.
* @param int $courseid The course id.
* @param int $groupid The group id.
* @return calendar_event|false
*/
function create_group_override_event(string $modulename, int $instanceid, int $courseid, int $groupid) {
if (!isset($groupid)) {
throw new coding_exception('Must specify groupid when creating a group override.');
}
return create_action_event([
'groupid' => $groupid,
'courseid' => $courseid,
'modulename' => $modulename,
'instance' => $instanceid,
]);
}
/**
* A test factory that will create action events.
*
@@ -159,3 +159,37 @@ Feature: Content bank use editor feature
And I click on "Content bank" "link"
And I follow "filltheblanks.h5p"
Then "Edit" "link" should not exist in the "region-main" "region"
Scenario: Teachers keep their content authoring in copied courses
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "contentbank content" exist:
| contextlevel | reference | contenttype | user | contentname | filepath |
| Course | C1 | contenttype_h5p | admin | filltheblanks.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| Course | C1 | contenttype_h5p | teacher1 | ipsums.h5p | /h5p/tests/fixtures/ipsums.h5p |
And I am on "Course 1" course homepage
And I navigate to "Copy course" in current page administration
And I set the following fields to these values:
| Course full name | Copy |
| Course short name | Copy |
| Teacher | 1 |
When I press "Copy and view"
And I trigger cron
And I am on homepage
And I log out
And I log in as "teacher1"
And I am on "Copy" course homepage
And I expand "Site pages" node
And I click on "Content bank" "link"
And I follow "ipsums.h5p"
Then "Edit" "link" should exist in the "region-main" "region"
And I click on "Content bank" "link"
And I follow "filltheblanks.h5p"
Then "Edit" "link" should not exist in the "region-main" "region"
@@ -103,6 +103,10 @@ class no_recent_accesses extends course_enrolments {
return get_string('nocoursestudents', 'course');
}
if (!$fortraining && !$course->get_course_data()->visible) {
return get_string('hiddenfromstudents');
}
if ($course->get_end() && $course->get_end() < $course->get_start()) {
return get_string('errorendbeforestart', 'course');
}
+24 -25
View File
@@ -57,8 +57,6 @@ M.course_dndupload = {
// The selector identifying the list of modules within a section (note changing this may require
// changes to the get_mods_element function)
modslistselector: 'ul.section',
// Original onbeforeunload event.
originalUnloadEvent: null,
/**
* Initalise the drag and drop upload interface
@@ -765,7 +763,10 @@ M.course_dndupload = {
xhr.onreadystatechange = function() {
if (xhr.readyState == 1) {
this.originalUnloadEvent = window.onbeforeunload;
self.reportUploadDirtyState(true);
// Trigger form upload start events.
require(['core_form/events'], function(FormEvent) {
FormEvent.triggerUploadStarted(section.get('id'));
});
}
if (xhr.readyState == 4) {
if (xhr.status == 200) {
@@ -793,7 +794,10 @@ M.course_dndupload = {
} else {
new M.core.alert({message: M.util.get_string('servererror', 'moodle')});
}
self.reportUploadDirtyState(false);
// Trigger form upload complete events.
require(['core_form/events'], function(FormEvent) {
FormEvent.triggerUploadCompleted(section.get('id'));
});
}
};
@@ -1025,7 +1029,10 @@ M.course_dndupload = {
xhr.onreadystatechange = function() {
if (xhr.readyState == 1) {
this.originalUnloadEvent = window.onbeforeunload;
self.reportUploadDirtyState(true);
// Trigger form upload start events.
require(['core_form/events'], function(FormEvent) {
FormEvent.triggerUploadStarted(section.get('id'));
});
}
if (xhr.readyState == 4) {
if (xhr.status == 200) {
@@ -1043,13 +1050,24 @@ M.course_dndupload = {
} else {
// Error - remove the dummy element
resel.parent.removeChild(resel.li);
// Trigger form upload complete events.
require(['core_form/events'], function(FormEvent) {
FormEvent.triggerUploadCompleted(section.get('id'));
});
new M.core.alert({message: result.error});
}
}
} else {
// Trigger form upload complete events.
require(['core_form/events'], function(FormEvent) {
FormEvent.triggerUploadCompleted(section.get('id'));
});
new M.core.alert({message: M.util.get_string('servererror', 'moodle')});
}
self.reportUploadDirtyState(false);
// Trigger form upload complete events.
require(['core_form/events'], function(FormEvent) {
FormEvent.triggerUploadCompleted(section.get('id'));
});
}
};
@@ -1083,24 +1101,5 @@ M.course_dndupload = {
if (M.core.actionmenu && M.core.actionmenu.newDOMNode) {
M.core.actionmenu.newDOMNode(node);
}
},
/**
* Set the event to prevent user navigate away when upload progress still running.
*
* @param {bool} enable true if upload progress is running, false otherwise
*/
reportUploadDirtyState: function(enable) {
if (!enable) {
window.onbeforeunload = this.originalUnloadEvent;
} else {
window.onbeforeunload = function(e) {
var warningMessage = M.util.get_string('changesmadereallygoaway', 'moodle');
if (e) {
e.returnValue = warningMessage;
}
return warningMessage;
};
}
}
};
+16 -3
View File
@@ -621,10 +621,23 @@ abstract class moodleform_mod extends moodleform {
if (!empty($CFG->enableavailability)) {
// Add special button to end of previous section if groups/groupings
// are enabled.
if ($this->_features->groups || $this->_features->groupings) {
$availabilityplugins = \core\plugininfo\availability::get_enabled_plugins();
$groupavailability = $this->_features->groups && array_key_exists('group', $availabilityplugins);
$groupingavailability = $this->_features->groupings && array_key_exists('grouping', $availabilityplugins);
if ($groupavailability || $groupingavailability) {
// When creating the button, we need to set type=button to prevent it behaving as a submit.
$mform->addElement('static', 'restrictgroupbutton', '',
html_writer::tag('button', get_string('restrictbygroup', 'availability'),
array('id' => 'restrictbygroup', 'disabled' => 'disabled', 'class' => 'btn btn-secondary')));
html_writer::tag('button', get_string('restrictbygroup', 'availability'), [
'id' => 'restrictbygroup',
'type' => 'button',
'disabled' => 'disabled',
'class' => 'btn btn-secondary',
'data-groupavailability' => $groupavailability,
'data-groupingavailability' => $groupingavailability
])
);
}
// Availability field. This is just a textarea; the user interface
@@ -55,12 +55,16 @@ class field_controller extends \core_customfield\field_controller {
$mform->addElement('text', 'configdata[displaysize]', get_string('displaysize', 'customfield_text'), ['size' => 6]);
$mform->setType('configdata[displaysize]', PARAM_INT);
$mform->setDefault('configdata[displaysize]', 50);
if (!$this->get_configdata_property('displaysize')) {
$mform->setDefault('configdata[displaysize]', 50);
}
$mform->addRule('configdata[displaysize]', null, 'numeric', null, 'client');
$mform->addElement('text', 'configdata[maxlength]', get_string('maxlength', 'customfield_text'), ['size' => 6]);
$mform->setType('configdata[maxlength]', PARAM_INT);
$mform->setDefault('configdata[maxlength]', 1333);
if (!$this->get_configdata_property('maxlength')) {
$mform->setDefault('configdata[maxlength]', 1333);
}
$mform->addRule('configdata[maxlength]', null, 'numeric', null, 'client');
$mform->addElement('selectyesno', 'configdata[ispassword]', get_string('ispassword', 'customfield_text'));
@@ -113,7 +117,7 @@ class field_controller extends \core_customfield\field_controller {
$errors['configdata[link]'] = get_string('errorconfiglinkplaceholder', 'customfield_text');
} else if (!validateUrlSyntax(str_replace('$$', 'XYZ', $link), 's+H?S?F-E-u-P-a?I?p?f?q?r?')) {
// This validation is more strict than PARAM_URL - it requires the protocol and it must be either http or https.
$errors['configdata[link]'] = get_string('errorconfigdisplaysize', 'customfield_text');
$errors['configdata[link]'] = get_string('errorconfiglinksyntax', 'customfield_text');
}
}
}
+6 -2
View File
@@ -188,7 +188,9 @@ $removeenabled = $canunenrol ? '' : 'disabled="disabled"';
</td>
<td id="buttonscell">
<div id="addcontrols">
<input name="add" <?php echo $addenabled; ?> id="add" type="submit" value="<?php echo $OUTPUT->larrow().'&nbsp;'.get_string('add'); ?>" title="<?php print_string('add'); ?>" /><br />
<input class="btn btn-secondary" name="add" <?php echo $addenabled; ?> id="add" type="submit"
value="<?php echo $OUTPUT->larrow() . '&nbsp;' . get_string('add'); ?>"
title="<?php print_string('add'); ?>" /><br />
<div class="enroloptions">
@@ -205,7 +207,9 @@ $removeenabled = $canunenrol ? '' : 'disabled="disabled"';
</div>
<div id="removecontrols">
<input name="remove" id="remove" <?php echo $removeenabled; ?> type="submit" value="<?php echo get_string('remove').'&nbsp;'.$OUTPUT->rarrow(); ?>" title="<?php print_string('remove'); ?>" />
<input class="btn btn-secondary" name="remove" id="remove" <?php echo $removeenabled; ?> type="submit"
value="<?php echo get_string('remove') . '&nbsp;' . $OUTPUT->rarrow(); ?>"
title="<?php print_string('remove'); ?>" />
</div>
</td>
<td id="potentialcell">
@@ -98,6 +98,7 @@ Feature: Users can auto-enrol themself in courses where self enrolment is allowe
And I log in as "student1"
And I am on "Course 1" course homepage
And I press "Enrol me"
And I should see "You are enrolled in the course"
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
@@ -118,6 +119,7 @@ Feature: Users can auto-enrol themself in courses where self enrolment is allowe
And I log in as "student1"
And I am on "Course 1" course homepage
And I press "Enrol me"
And I should see "You are enrolled in the course"
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
+126
View File
@@ -1036,6 +1036,59 @@ class core_enrollib_testcase extends advanced_testcase {
$this->assertEquals([$course1->id, $course2->id, $course3->id, $course4->id], array_keys($courses));
}
/**
* Data provider for {@see test_enrol_get_my_courses_by_time}
*
* @return array
*/
public function enrol_get_my_courses_by_time_provider(): array {
return [
'No start or end time' =>
[null, null, true],
'Start time now, no end time' =>
[0, null, true],
'Start time now, end time in the future' =>
[0, MINSECS, true],
'Start time in the past, no end time' =>
[-MINSECS, null, true],
'Start time in the past, end time in the future' =>
[-MINSECS, MINSECS, true],
'Start time in the past, end time in the past' =>
[-DAYSECS, -HOURSECS, false],
'Start time in the future' =>
[MINSECS, null, false],
];
}
/**
* Test that expected course enrolments are returned when they have timestart / timeend specified
*
* @param int|null $timestartoffset Null for 0, otherwise offset from current time
* @param int|null $timeendoffset Null for 0, otherwise offset from current time
* @param bool $expectreturn
*
* @dataProvider enrol_get_my_courses_by_time_provider
*/
public function test_enrol_get_my_courses_by_time(?int $timestartoffset, ?int $timeendoffset, bool $expectreturn): void {
$this->resetAfterTest();
$time = time();
$timestart = $timestartoffset === null ? 0 : $time + $timestartoffset;
$timeend = $timeendoffset === null ? 0 : $time + $timeendoffset;
$course = $this->getDataGenerator()->create_course();
$user = $this->getDataGenerator()->create_and_enrol($course, 'student', null, 'manual', $timestart, $timeend);
$this->setUser($user);
$courses = enrol_get_my_courses();
if ($expectreturn) {
$this->assertCount(1, $courses);
$this->assertEquals($course->id, reset($courses)->id);
} else {
$this->assertEmpty($courses);
}
}
/**
* test_course_users
*
@@ -1362,4 +1415,77 @@ class core_enrollib_testcase extends advanced_testcase {
$durationinday = $duration / DAYSECS;
$this->assertEquals(9, $durationinday);
}
/**
* Test get_enrolled_with_capabilities_join cannotmatchanyrows attribute.
*
* @dataProvider get_enrolled_with_capabilities_join_cannotmatchanyrows_data()
* @param string $capability the tested capability
* @param bool $useprohibit if the capability must be assigned to prohibit
* @param int $expectedmatch expected cannotmatchanyrows value
* @param int $expectedcount expceted count value
*/
public function test_get_enrolled_with_capabilities_join_cannotmatchanyrows(
string $capability,
bool $useprohibit,
int $expectedmatch,
int $expectedcount
) {
global $DB, $CFG;
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$context = context_course::instance($course->id);
$roleid = $CFG->defaultuserroleid;
// Override capability if necessary.
if ($useprohibit && $capability) {
assign_capability($capability, CAP_PROHIBIT, $roleid, $context);
}
// Check if we must enrol or not.
$this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
$join = get_enrolled_with_capabilities_join($context, '', $capability);
// Execute query.
$sql = "SELECT COUNT(DISTINCT u.id)
FROM {user} u {$join->joins}
WHERE {$join->wheres}";
$countrecords = $DB->count_records_sql($sql, $join->params);
// Validate cannotmatchanyrows.
$this->assertEquals($expectedmatch, $join->cannotmatchanyrows);
$this->assertEquals($expectedcount, $countrecords);
}
/**
* Data provider for test_get_enrolled_with_capabilities_join_cannotmatchanyrows
*
* @return @array of testing scenarios
*/
public function get_enrolled_with_capabilities_join_cannotmatchanyrows_data() {
return [
'no prohibits, no capability' => [
'capability' => '',
'useprohibit' => false,
'expectedmatch' => 0,
'expectedcount' => 1,
],
'no prohibits with capability' => [
'capability' => 'moodle/course:manageactivities',
'useprohibit' => false,
'expectedmatch' => 0,
'expectedcount' => 1,
],
'prohibits with capability' => [
'capability' => 'moodle/course:manageactivities',
'useprohibit' => true,
'expectedmatch' => 1,
'expectedcount' => 0,
],
];
}
}
+14 -2
View File
@@ -23,6 +23,16 @@ class grade_export_xml extends grade_export {
public $plugin = 'xml';
public $updatedgradesonly = false; // default to export ALL grades
/**
* Ensure we produce correctly formed XML content by encoding idnumbers appropriately
*
* @param string $idnumber
* @return string
*/
private static function xml_export_idnumber(string $idnumber): string {
return htmlspecialchars($idnumber, ENT_QUOTES | ENT_XML1);
}
/**
* To be implemented by child classes
* @param boolean $feedback
@@ -84,9 +94,11 @@ class grade_export_xml extends grade_export {
}
// only need id number
fwrite($handle, "\t\t<assignment>{$grade_item->idnumber}</assignment>\n");
$gradeitemidnumber = self::xml_export_idnumber($grade_item->idnumber);
fwrite($handle, "\t\t<assignment>{$gradeitemidnumber}</assignment>\n");
// this column should be customizable to use either student id, idnumber, uesrname or email.
fwrite($handle, "\t\t<student>{$user->idnumber}</student>\n");
$useridnumber = self::xml_export_idnumber($user->idnumber);
fwrite($handle, "\t\t<student>{$useridnumber}</student>\n");
// Format and display the grade in the selected display type (real, letter, percentage).
if (is_array($this->displaytype)) {
// Grades display type came from the return of export_bulk_export_data() on grade publishing.
+13 -5
View File
@@ -12,10 +12,12 @@ Feature: I need to export grades as xml
| username | firstname | lastname | email | idnumber |
| teacher1 | Teacher | 1 | teacher1@example.com | t1 |
| student1 | Student | 1 | student1@example.com | s1 |
| student2 | Student | 2 | student2@example.com | 'Bill'&"Ben"<tag>Hello</tag> |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
And the following "activities" exist:
| activity | course | idnumber | name | intro |
| assign | C1 | a1 | Test assignment name | Submit something! |
@@ -24,15 +26,21 @@ Feature: I need to export grades as xml
And I navigate to "View > Grader report" in the course gradebook
And I turn editing mode on
And I give the grade "80.00" to the user "Student 1" for the grade item "Test assignment name"
And I give the grade "42.00" to the user "Student 2" for the grade item "Test assignment name"
And I press "Save changes"
@javascript
Scenario: Export grades as text
Scenario: Export grades as XML
When I navigate to "Export > XML file" in the course gradebook
And I expand all fieldsets
And I set the field "Grade export decimal places" to "1"
And I press "Download"
Then I should see "s1"
And I should see "a1"
And I should see "80.0"
And I should not see "80.00"
Then I should see "s1" in the "//results//result[1]//student" "xpath_element"
And I should see "a1" in the "//results//result[1]//assignment" "xpath_element"
And I should see "80.0" in the "//results//result[1]//score" "xpath_element"
And I should not see "80.00" in the "//results//result[1]//score" "xpath_element"
# Ensure we have the encoded ID number of student 2.
And I should see "'Bill'&\"Ben\"<tag>Hello</tag>" in the "//results//result[2]//student" "xpath_element"
And I should see "a1" in the "//results//result[2]//assignment" "xpath_element"
And I should see "42.0" in the "//results//result[2]//score" "xpath_element"
And I should not see "42.00" in the "//results//result[2]//score" "xpath_element"
@@ -156,6 +156,9 @@ class fetch extends external_api {
$hasgrade = $gradeitem->user_has_grade($gradeduser);
$grade = $gradeitem->get_grade_for_user($gradeduser, $USER);
$instance = $gradeitem->get_advanced_grading_instance($USER, $grade);
if (!$instance) {
throw new moodle_exception('error:gradingunavailable', 'grading');
}
$controller = $instance->get_controller();
$definition = $controller->get_definition();
$fillings = $instance->get_guide_filling();
@@ -149,6 +149,10 @@ class fetch extends external_api {
$hasgrade = $gradeitem->user_has_grade($gradeduser);
$grade = $gradeitem->get_grade_for_user($gradeduser, $USER);
$instance = $gradeitem->get_advanced_grading_instance($USER, $grade);
if (!$instance) {
throw new moodle_exception('error:gradingunavailable', 'grading');
}
$controller = $instance->get_controller();
$definition = $controller->get_definition();
$fillings = $instance->get_rubric_filling();
+1 -1
View File
@@ -231,7 +231,7 @@ if (!empty($method)) {
} else {
$tag = html_writer::tag('span', get_string('statusdraft', 'core_grading'), array('class' => 'status draft'));
}
echo $output->heading(s($definition->name) . ' ' . $tag, 3, 'definition-name');
echo $output->heading(format_string($definition->name) . ' ' . $tag, 3, 'definition-name');
echo $output->box($controller->render_preview($PAGE), 'definition-preview');
}
}
+4
View File
@@ -240,6 +240,10 @@ class gradeimport_csv_load_data {
$select = "{$field} = :{$field}";
}
// Validate if the user id value is numerical.
if ($field === 'id' && !is_numeric($value)) {
$errorkey = 'usermappingerror';
}
// Make sure the record exists and that there's only one matching record found.
$user = $DB->get_record_select('user', $select, array($userfields['field'] => $value), '*', MUST_EXIST);
} catch (dml_missing_record_exception $missingex) {
@@ -87,7 +87,7 @@ class provider implements
* @param int $userid The userid of the user whose data is to be exported.
*/
public static function export_user_preferences(int $userid) {
$preferences = get_user_preferences();
$preferences = get_user_preferences(null, null, $userid);
foreach ($preferences as $name => $value) {
$prefname = null;
$prefdescription = null;
+6 -2
View File
@@ -63,14 +63,18 @@ class gradereport_grader_privacy_testcase extends \core_privacy\tests\provider_t
* These preferences can be set on each course, but the value is shared in the whole site.
*/
public function test_export_user_preferences_single() {
// Add some user preferences.
// Create test user, add some preferences.
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
set_user_preference('grade_report_showcalculations', 1, $user);
set_user_preference('grade_report_meanselection', GRADE_REPORT_MEAN_GRADED, $user);
set_user_preference('grade_report_studentsperpage', 50, $user);
// Validate exported data.
// Switch to admin user (so we can validate preferences of our test user are still exported).
$this->setAdminUser();
// Validate exported data for our test user.
provider::export_user_preferences($user->id);
$context = context_user::instance($user->id);
$writer = writer::with_context($context);
@@ -13,4 +13,4 @@ Feature: We can use the user report
And I am on "Course 1" course homepage
And I navigate to "View > User report" in the course gradebook
And I select "All users (0)" from the "Select all or one user" singleselect
Then I should see "No students enrolled in this course yet"
Then I should see "There are no students enrolled in this course."
+1 -1
View File
@@ -232,7 +232,7 @@ if ($editform->is_cancelled()) {
$newgroup = new stdClass();
$newgroup->courseid = $data->courseid;
$newgroup->name = $group['name'];
$newgroup->enablemessaging = $data->enablemessaging;
$newgroup->enablemessaging = $data->enablemessaging ?? 0;
$groupid = groups_create_group($newgroup);
$createdgroups[] = $groupid;
foreach($group['members'] as $user) {
+2
View File
@@ -421,6 +421,8 @@ class helper {
* @return array The JS array converted to PHP array.
*/
public static function parse_js_array(string $jscontent): array {
// Convert all line-endings to UNIX format first.
$jscontent = str_replace(array("\r\n", "\r"), "\n", $jscontent);
$jsarray = preg_split('/,\n\s+/', substr($jscontent, 0, -1));
$jsarray = preg_replace('~{?\\n~', '', $jsarray);
+3 -1
View File
@@ -79,7 +79,9 @@ abstract class handler {
* Register the H5P autoloader.
*/
public static function register(): void {
spl_autoload_register([static::class, 'autoload']);
// Prepend H5P libraries in order to guarantee they are loaded first. Plugins using same libraries will need to use a
// different namespace if they want to use a different version.
spl_autoload_register([static::class, 'autoload'], true, true);
}
/**
Binary file not shown.
@@ -5,52 +5,52 @@
<json>
<![CDATA[
{
"fontFamily": "h5p-core-21",
"fontFamily": "h5p-core",
"description": "Font generated by IcoMoon.",
"majorVersion": 1,
"minorVersion": 1,
"version": "Version 1.1",
"fontId": "h5p-core-21",
"psName": "h5p-core-21",
"fontId": "h5p-core",
"psName": "h5p-core",
"subFamily": "Regular",
"fullName": "h5p-core-21"
"fullName": "h5p-core"
}
]]>
</json>
</metadata>
<defs>
<font id="h5p-core-21" horiz-adv-x="1024">
<font id="h5p-core" horiz-adv-x="1024">
<font-face units-per-em="1024" ascent="960" descent="-64" />
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
<glyph unicode="&#xe565;" glyph-name="arrow-down" data-tags="arrow-down" d="M234 389.669h556l-278-278z" />
<glyph unicode="&#xe566;" glyph-name="arrow-left" data-tags="arrow-left" d="M381-11.331v524l262-262z" />
<glyph unicode="&#xe58e;" glyph-name="colapse" data-tags="colapse" d="M512 447.336l256-256-60-60-196 196-196-196-60 60z" />
<glyph unicode="&#xe58f;" glyph-name="expand" data-tags="expand" d="M708 423.336l60-60-256-256-256 256 60 60 196-196z" />
<glyph unicode="&#xe600;" glyph-name="move" data-tags="move" d="M386.662 725.063h71.27v-71.27h-71.27v71.27zM566.067 725.063h71.27v-71.27h-71.27v71.27zM386.662 568.8h71.27v-71.27h-71.27v71.27zM566.067 568.8h71.27v-71.27h-71.27v71.27zM386.662 412.435h71.27v-71.27h-71.27v71.27zM566.067 412.435h71.27v-71.27h-71.27v71.27zM386.662 256.173h71.27v-71.27h-71.27v71.27zM566.067 256.173h71.27v-71.27h-71.27v71.27zM386.662 99.808h71.27v-71.27h-71.27v71.27zM566.067 99.808h71.27v-71.27h-71.27v71.27zM386.662-56.454h71.27v-71.27h-71.27v71.27zM566.067-56.454h71.27v-71.27h-71.27v71.27z" />
<glyph unicode="&#xe601;" glyph-name="check-mark" data-tags="check-mark" d="M454.299 245.924l-116.917 116.917-84.781-84.707 201.696-201.697 317.097 317.097-84.781 84.706z" />
<glyph unicode="&#xe888;" glyph-name="arrow-up-circle" data-tags="arrow-up-circle" d="M512 606.057c-148.616 0-264.722-120.75-260.077-269.367 0-125.395 88.241-232.212 208.991-255.434v213.636h-92.885c-13.933 0-13.933 9.288-9.288 18.577l139.327 171.838c4.645 9.288 13.933 9.288 23.221 4.645 0 0 4.645-4.645 4.645-4.645l139.327-171.838c9.288-9.288 4.645-18.577-9.288-18.577h-92.885v-213.636c143.972 32.51 232.212 171.838 199.703 315.808-23.221 120.75-130.039 204.347-250.789 208.991z" />
<glyph unicode="&#xe889;" glyph-name="info-circle" data-tags="info-circle" d="M512 601.601c-144.077 0-260.266-116.191-260.266-260.266s116.191-260.266 260.266-260.266 260.266 116.191 260.266 260.266v0c0 139.429-116.191 255.619-260.266 260.266zM470.171 550.478h88.305v-69.714h-88.305v69.714zM600.305 160.078h-181.257v51.123h51.123v162.666h-51.123v51.123h139.429v-218.438h46.477l-4.648-46.477z" />
<glyph unicode="&#xe88a;" glyph-name="search" data-tags="search" d="M772.098 125.51l-110.68 110.68c71.943 99.612 49.806 243.494-49.806 315.437s-243.494 44.27-315.437-55.339c-71.943-99.612-49.806-243.494 49.806-315.437 77.475-55.339 182.623-55.339 260.098 0l110.68-110.68c5.533-5.533 11.068-5.533 16.601 0 0 0 0 0 0 0l33.205 33.205c11.068 5.533 11.068 16.601 5.533 22.137 0 0 0 0 0 0zM478.795 202.985c-88.544 0-160.486 71.943-160.486 160.486s71.943 160.486 160.486 160.486 160.486-71.943 160.486-160.486-71.943-160.486-160.486-160.486v0z" />
<glyph unicode="&#xe88c;" glyph-name="fullscreen" data-tags="fullscreen" d="M368.55 490.521c5.737 5.737 0 5.737-5.737 5.737l-103.284 11.476c-5.737 5.737-11.476 0-11.476-5.737l11.476-109.021c0-5.737 5.737-5.737 5.737-5.737l103.284 103.284zM293.959 427.403l63.118-63.118c5.737-5.737 11.476-5.737 17.213 0l22.953 22.953c5.737 5.737 5.737 11.476 0 17.213l-63.118 57.379-40.166-34.429zM787.42 387.237c5.737-5.737 5.737 0 5.737 5.737l11.476 109.021c0 5.737-5.737 11.476-11.476 11.476l-109.021-11.476c-5.737 0-5.737-5.737-5.737-5.737l109.021-109.021zM724.305 461.832l-63.118-63.118c-5.737-5.737-5.737-11.476 0-17.213l22.953-22.953c5.737-5.737 11.476-5.737 17.213 0l63.118 63.118-40.166 40.166zM689.876 180.672c-5.737-5.737 0-5.737 5.737-5.737l109.021-11.476c5.737 0 11.476 5.737 11.476 11.476l-17.213 103.284c0 5.737-5.737 5.737-5.737 5.737l-103.284-103.284zM758.731 249.527l-63.118 63.118c-5.737 5.737-11.476 5.737-17.213 0l-22.953-22.953c-5.737-5.737-5.737-11.476 0-17.213l63.118-63.118 40.166 40.166zM265.269 283.956c-5.737 5.737-5.737 0-5.737-5.737l-11.476-109.021c0-5.737 5.737-11.476 11.476-11.476l109.021 11.476c5.737 0 5.737 5.737 5.737 5.737l-109.021 109.021zM334.124 209.362l63.118 63.118c5.737 5.737 5.737 11.476 0 17.213l-22.953 22.953c-5.737 5.737-11.476 5.737-17.213 0l-63.118-63.118 40.166-40.166zM161.985 593.805v-499.201h722.979v499.201h-722.979zM844.799 134.77h-636.911v413.13h636.911v-413.13z" />
<glyph unicode="&#xe88e;" glyph-name="h5p" data-tags="h5p" d="M934.072 489.192c-22.319 16.738-50.216 27.897-89.273 27.897h-139.487v-66.954h-156.225l-11.159-55.795c11.159 5.579 27.897 11.159 39.057 11.159s22.319 0 33.476 0c33.476 0 66.954-11.159 89.273-33.476s33.476-50.216 33.476-83.692c0-22.319-5.579-44.635-16.738-66.954s-27.897-39.057-50.216-50.216c-5.579-5.579-16.738 0-22.319-11.159h117.17v133.908h66.954c44.635 0 78.113 11.159 100.43 27.897 22.319 22.319 33.476 50.216 33.476 83.692 0 39.057-11.159 66.954-27.897 83.692v0zM839.221 377.603c-11.159-5.579-22.319-11.159-44.635-11.159h-33.476v83.692h39.057c22.319 0 33.476-5.579 44.635-11.159 5.579-5.579 11.159-16.738 11.159-27.897 0-16.738-5.579-27.897-16.738-33.476v0zM565.826 338.546c-16.738 0-33.476-11.159-44.635-27.897l-94.851 16.738 44.635 195.281h-94.851v-150.646h-117.17v150.646h-111.589v-362.667h111.589v133.908h117.17v-133.908h139.487c-16.738 11.159-33.476 11.159-44.635 22.319s-22.319 22.319-27.897 33.476c-5.579 11.159-11.159 22.319-16.738 39.057l94.851 16.738c5.579-16.738 22.319-27.897 44.635-27.897 27.897 0 50.216 22.319 50.216 50.216 0 22.319-22.319 44.635-50.216 44.635v0z" />
<glyph unicode="&#xe88f;" glyph-name="rights-of-use" data-tags="rights-of-use" d="M899.611 329.519c0-5.907 0-5.907 0-5.907-23.631-23.631-47.261-35.448-76.799-41.355-11.813 0-23.631-5.907-35.448-5.907s-17.724 0-29.537 0c0 0-5.907 0-5.907 5.907-64.985 59.079-135.877 118.153-200.863 183.139 0 0-5.907 0-5.907 0-23.631-5.907-47.261-11.813-70.892-17.724s-53.168 0-76.799 11.813c-17.724 11.813-23.631 17.724-29.537 35.448-5.907 5.907 0 23.631 11.813 23.631 41.355 11.813 88.616 29.537 129.971 47.261 11.813 5.907 29.537 5.907 41.355 5.907 5.907 0 11.813-5.907 11.813-5.907 41.355-17.724 82.709-29.537 124.060-47.261 0 0 5.907 0 5.907 0 29.537 5.907 64.985 17.724 94.523 23.631 5.907 0 5.907 0 5.907 0l106.34-212.676zM291.12 335.429c17.724 11.813 35.448 5.907 53.168-11.813 11.813-11.813 11.813-29.537 5.907-47.261 17.724 5.907 35.448-5.907 41.355-17.724 11.813-17.724 5.907-35.448-5.907-47.261 5.907 0 11.813 0 17.724 0 11.813-5.907 23.631-11.813 29.537-29.537s0-29.537-5.907-35.448c-5.907-5.907-11.813-11.813-17.724-17.724s-11.813-11.813-17.724-17.724-35.448-17.724-53.168 0c-29.537 29.537-53.168 64.985-82.709 94.523-17.724 23.631-35.448 41.355-47.261 64.985-5.907 11.813-11.813 17.724-11.813 29.537 0 5.907 0 17.724 5.907 23.631 11.813 11.813 17.724 17.724 29.537 29.537 17.724 17.724 47.261 11.813 64.985-5.907-5.907 0-5.907-5.907-5.907-11.813v0zM438.811 128.66l29.537-29.537c17.724-17.724 47.261-11.813 59.079 5.907l-5.907 5.907c-23.631 23.631-47.261 47.261-70.892 70.892-5.907 5.907-5.907 5.907-5.907 11.813s5.907 5.907 11.813 11.813c5.907 0 11.813 0 11.813-5.907 11.813-11.813 29.537-29.537 47.261-47.261 11.813-11.813 29.537-29.537 47.261-47.261 5.907-11.813 17.724-11.813 29.537-11.813 11.813 5.907 23.631 11.813 29.537 23.631 0 5.907 0 5.907 0 5.907-41.355 41.355-88.616 82.709-129.971 129.971-5.907 5.907-5.907 5.907-5.907 11.813 0 11.813 11.813 11.813 23.631 5.907 0 0 5.907 0 5.907-5.907 41.355-41.355 88.616-88.616 129.971-129.971 5.907-5.907 5.907-5.907 5.907-5.907 17.724 0 35.448 17.724 35.448 35.448 0 5.907 0 5.907 0 5.907-47.261 47.261-100.429 100.429-147.691 147.691-5.907 5.907-5.907 5.907-5.907 11.813s5.907 11.813 5.907 11.813c5.907 0 11.813 0 11.813-5.907 5.907-5.907 5.907-5.907 11.813-11.813 35.448-35.448 70.892-70.892 106.34-106.34 11.813-11.813 23.631-23.631 29.537-29.537 0 0 5.907-5.907 5.907 0 23.631 5.907 35.448 29.537 29.537 53.168h35.448c0 0 0 0 0 0 0-5.907 0-17.724 0-23.631-5.907-29.537-23.631-47.261-53.168-59.079 0 0-5.907 0-5.907-5.907-11.813-29.537-35.448-53.168-64.985-53.168-5.907 0-5.907 0-5.907-5.907-17.724-35.448-59.079-47.261-88.616-35.448-5.907 0-11.813 5.907-11.813 5.907-5.907-5.907-11.813-11.813-23.631-17.724-29.537-11.813-59.079-5.907-76.799 11.813-11.813 11.813-17.724 17.724-29.537 29.537 17.724 23.631 23.631 29.537 29.537 41.355v0 0zM273.396 642.628c29.537-11.813 64.985-23.631 94.523-29.537 35.448-11.813 64.985-23.631 100.429-29.537 0 0 0 0 5.907 0-17.724-5.907-35.448-11.813-47.261-17.724 0 0-5.907 0-5.907 0-47.261 11.813-94.523 23.631-135.877 41.355-5.907 0-5.907 0-5.907 0l-76.799-183.139c0-11.813 5.907-17.724 11.813-23.631s5.907-5.907 5.907-11.813c-5.907-5.907-11.813-17.724-23.631-23.631-17.724 17.724-29.537 35.448-29.537 64.985l88.616 212.676c-5.907-11.813 5.907 5.907 17.724 0v0z" />
<glyph unicode="&#xe890;" glyph-name="delete-circle" data-tags="delete-circle" d="M512 601.601c-147.107 0-260.266-118.817-260.266-260.266s118.817-260.266 260.266-260.266 260.266 118.817 260.266 260.266-113.158 260.266-260.266 260.266zM653.449 262.123c5.659-5.659 5.659-16.973 0-28.29l-33.949-33.949c-5.659-5.659-16.973-5.659-28.29 0l-79.212 79.212-79.212-79.212c-5.659-5.659-16.973-5.659-28.29 0l-33.949 33.949c-5.659 5.659-5.659 16.973 0 28.29l84.871 79.212-79.212 79.212c-5.659 5.659-5.659 16.973 0 28.29l33.949 33.949c5.659 5.659 16.973 5.659 28.29 0l73.554-84.871 79.212 79.212c5.659 5.659 16.973 5.659 28.29 0l33.949-33.949c5.659-5.659 5.659-16.973 0-28.29l-79.212-73.554 79.212-79.212z" />
<glyph unicode="&#xe891;" glyph-name="window" data-tags="window" d="M203.936 461.136c-5.704-5.704 0-5.704 5.704-5.704l108.394-11.41c5.704 0 11.41 5.704 11.41 11.41l-17.114 102.687c0 5.704-5.704 5.704-5.704 5.704l-102.687-102.687zM272.395 523.891l-62.752 62.752c-5.704 5.704-11.41 5.704-17.114 0l-17.114-22.821c-5.704-5.704-5.704-11.41 0-17.114l62.752-62.752 34.228 39.935zM751.605 558.119c-5.704 5.704-5.704 0-5.704-5.704l-11.41-108.394c0-5.704 5.704-11.41 11.41-11.41l108.394 11.41c5.704 0 5.704 5.704 5.704 5.704l-108.394 108.394zM814.357 483.957l62.752 62.752c5.704 5.704 5.704 11.41 0 17.114l-22.821 22.821c-5.704 5.704-11.41 5.704-17.114 0l-62.752-62.752 39.935-39.935zM848.588 221.534c5.704 5.704 0 5.704-5.704 5.704l-102.687 17.114c-5.704 0-11.41-5.704-11.41-11.41l11.41-108.394c0-5.704 5.704-5.704 5.704-5.704l102.687 102.687zM780.129 158.779l62.752-62.752c5.704-5.704 11.41-5.704 17.114 0l22.821 22.821c5.704 5.704 5.704 11.41 0 17.114l-62.752 62.752-39.935-39.935zM300.919 124.551c5.704-5.704 5.704 0 5.704 5.704l11.41 108.394c0 5.704-5.704 11.41-11.41 11.41l-108.394-11.41c-5.704 0-5.704-5.704-5.704-5.704l108.394-108.394zM238.167 193.010l-62.752-62.752c-5.704-5.704-5.704-11.41 0-17.114l22.821-22.821c5.704-5.704 11.41-5.704 17.114 0l62.752 62.752-39.935 39.935zM352.264 466.843v-239.605h347.998v239.605h-347.998zM654.622 267.172h-262.424v154.032h262.424v-154.032z" />
<glyph unicode="&#xe892;" glyph-name="code" data-tags="code" d="M449.641 235.325c6.235-6.235 6.235-12.472 6.235-18.707v-62.359c0-6.235-6.235-6.235-6.235-6.235l-230.728 155.897c-6.235 6.235-6.235 12.472-6.235 18.707v49.886c0 6.235 6.235 12.472 6.235 18.707l230.728 155.897c6.235 6.235 6.235 0 6.235-6.235v-62.359c0-6.235-6.235-12.472-6.235-18.707l-162.134-112.245c-6.235-6.235-6.235-6.235 0-12.472l162.134-99.776zM736.493 341.335c6.235 6.235 6.235 6.235 0 12.472l-155.897 112.245c-6.235 6.235-6.235 12.472-6.235 18.707v62.359c0 6.235 6.235 6.235 6.235 6.235l230.728-155.897c6.235-6.235 6.235-12.472 6.235-18.707v-49.886c0-6.235-6.235-12.472-6.235-18.707l-230.728-155.897c-6.235-6.235-6.235 0-6.235 6.235v62.359c0 6.235 6.235 12.472 6.235 18.707l155.897 99.776z" />
<glyph unicode="&#xe893;" glyph-name="download" data-tags="download" d="M358.941 435.525c-11.773 0-17.66-5.887-5.887-17.66l153.059-188.382c5.887-11.773 23.547-11.773 29.433 0l153.059 188.382c5.887 11.773 5.887 17.66-5.887 17.66h-323.782zM576.756 423.751v135.399c0 11.773-11.773 23.547-23.547 23.547h-70.643c-11.773 0-23.547-11.773-23.547-23.547v-141.286h117.739zM653.286 288.352c-5.887 0-17.66-5.887-23.547-11.773l-76.53-94.19c-5.887-5.887-17.66-17.66-23.547-23.547 0 0-5.887-5.887-11.773-5.887s-17.66 11.773-17.66 11.773c-5.887 5.887-17.66 17.66-23.547 23.547l-76.53 94.19c-5.887 5.887-17.66 11.773-23.547 11.773h-123.626c-5.887 0-17.66-5.887-17.66-17.66v-141.286c0-5.887 5.887-17.66 17.66-17.66h529.824c5.887 0 17.66 5.887 17.66 17.66v141.286c0 5.887-5.887 17.66-17.66 17.66l-129.513-5.887zM305.958 176.502c-17.66 0-29.433 11.773-29.433 29.433s11.773 29.433 29.433 29.433c17.66 0 29.433-11.773 29.433-29.433s-11.773-29.433-29.433-29.433v0z" />
<glyph unicode="&#xe894;" glyph-name="delete" data-tags="delete" d="M620.266 341.335l134.045 134.045c10.311 10.311 10.311 30.934 0 41.245l-61.866 61.866c-10.311 10.311-30.934 10.311-41.245 0l-134.045-134.045-134.045 134.045c-10.311 10.311-30.934 10.311-41.245 0l-61.866-61.866c-10.311-10.311-10.311-30.934 0-41.245l134.045-134.045-134.045-134.045c-10.311-10.311-10.311-30.934 0-41.245l61.866-61.866c10.311-10.311 30.934-10.311 41.245 0l134.045 134.045 134.045-134.045c10.311-10.311 30.934-10.311 41.245 0l61.866 61.866c10.311 10.311 10.311 30.934 0 41.245l-134.045 134.045z" />
<glyph unicode="&#xe900;" glyph-name="edit-image" data-tags="edit-image" d="M300.237 621.639c69.018 23.142 133.325 14.234 189.133-33.28 56.627-48.128 77.619-110.592 63.181-183.808-2.355-12.186 0.307-19.456 8.704-27.853 93.901-93.389 156.774-156.467 250.47-250.163 5.427-5.427 10.957-10.854 15.667-16.896 39.424-50.278 16.794-124.006-44.237-142.029-36.966-10.957-68.403 0-95.334 27.034-95.642 96.051-160.973 160.973-256.614 257.024-6.963 6.963-12.8 8.909-22.63 6.758-117.76-26.317-229.171 60.826-231.731 181.453-0.614 26.419 3.584 52.326 15.974 77.926 34.816-34.816 68.506-67.789 101.274-101.786 10.445-10.752 20.992-15.36 36.045-15.36 14.643 0 25.19 3.891 34.816 14.848 10.752 12.39 23.040 23.347 34.611 35.021 14.336 14.438 14.336 46.080-0.205 60.518-35.123 35.226-70.349 70.349-106.598 106.496 3.891 2.253 5.632 3.482 7.475 4.096zM703.386 63.559c-0.41-24.269 20.685-45.466 44.851-45.158 23.757 0.41 44.032 20.992 43.93 44.544-0.102 23.757-20.275 44.032-44.237 44.134-23.859 0.307-44.237-19.661-44.544-43.52z" />
<glyph unicode="&#xe901;" glyph-name="hourglass" data-tags="hourglass" d="M733.286-10.579c-147.763 0-295.526 0-443.29 0 0 2.048 0.102 4.096 0 6.144-0.307 13.824-1.024 32.666-0.922 46.49 0.41 39.731 6.861 78.131 19.046 115.2 17.203 52.224 43.725 96.256 81.306 130.355 4.506 4.096 9.216 7.885 13.722 11.776-0.205 0.717-0.307 1.126-0.41 1.229-1.331 1.229-2.765 2.355-4.198 3.584-28.058 22.63-50.688 51.405-68.403 85.606-30.618 59.085-43.52 123.597-41.165 192.614 0.205 7.168 0.614 18.33 0.922 25.498 147.763 0 295.526 0 443.29 0 0.205-1.331 0.512-2.662 0.614-3.994 2.662-36.966 1.229-77.722-5.939-113.869-14.336-72.909-44.544-133.837-95.027-179.405-4.096-3.686-8.294-7.066-12.39-10.547 0.205-0.717 0.307-1.126 0.512-1.331 0.819-0.717 1.638-1.434 2.458-2.15 42.189-33.894 71.68-79.872 90.931-135.782 11.776-34.202 18.637-69.837 20.070-106.701 0.819-19.763-0.614-44.851-1.126-64.717zM687.309 32.634c0 6.554 0.205 12.493 0 18.432-1.331 37.581-7.27 74.138-19.866 108.749-17.92 49.562-45.568 88.269-88.678 108.646-2.458 1.126-2.97 3.072-2.97 5.837 0.102 16.691 0.102 33.485 0 50.176 0 3.994 1.331 5.427 4.096 6.963 9.114 5.325 18.432 10.24 26.829 16.896 29.696 23.552 49.152 56.934 62.362 95.744 10.342 30.413 15.77 62.259 17.818 94.822 0.614 9.114 0.102 18.227 0.102 27.546-116.634 0-233.574 0-351.027 0 0.307-8.704 0.614-16.998 1.024-25.395 1.946-37.274 8.499-73.216 21.504-107.213 18.125-47.104 45.261-83.558 86.528-103.117 2.253-1.024 2.867-2.662 2.867-5.427-0.102-17.203-0.102-34.509 0-51.712 0-3.072-1.024-4.506-3.277-5.632-5.632-2.867-11.366-5.734-16.691-9.216-34.304-22.733-56.832-57.754-71.987-100.147-12.493-35.123-18.125-71.987-19.661-109.875-0.205-5.325 0-10.752 0-16.282 117.35 0.205 234.189 0.205 351.027 0.205zM410.214 451.962c68.096 0 135.373 0 203.674 0-3.789-6.554-7.168-12.595-10.752-18.227-10.957-16.998-24.269-30.618-39.731-41.472s-27.75-25.293-32.768-46.592c-1.638-6.963-2.765-14.336-2.867-21.606-0.307-17.203-0.205-34.406 0.307-51.712 0.717-28.058 12.493-48.947 32.154-62.566 43.008-30.003 65.843-75.878 75.776-132.506 0.307-1.638 0.307-3.379 0.614-5.53-83.149 0-166.093 0-249.242 0 2.662 20.685 7.885 40.346 15.462 59.085 13.312 32.973 32.768 59.187 59.494 77.722 16.589 11.469 28.365 27.955 32.358 50.995 0.819 4.813 1.331 9.83 1.434 14.746 0.102 18.637 0.614 37.274-0.205 55.808-1.126 24.678-11.981 43.213-28.57 57.139-9.216 7.782-18.944 14.746-27.648 23.142-11.981 11.162-21.197 25.395-29.491 41.574z" />
<glyph unicode="&#xe902;" glyph-name="plus-icon" data-tags="plus-icon" d="M768 285.015c0-19.323-15.664-34.987-34.987-34.987h-151.040v-151.467c0-19.323-15.664-34.987-34.987-34.987h-69.547c-19.323 0-34.987 15.664-34.987 34.987v151.467h-151.467c-19.323 0-34.987 15.664-34.987 34.987v69.547c0 19.323 15.664 34.987 34.987 34.987h151.467v151.467c0 19.323 15.664 34.987 34.987 34.987h69.547c19.323 0 34.987-15.664 34.987-34.987v-151.467h151.467c19.323 0 34.987-15.664 34.987-34.987z" />
<glyph unicode="&#xe903;" glyph-name="video-upload-icon" data-tags="video-upload-icon" d="M384 328.535v-128c0-21.333 21.333-42.667 42.667-42.667h128c21.333 0 42.667 17.067 42.667 42.667v128c0 21.333-17.067 42.667-42.667 42.667h-128c-21.333 0-42.667-17.067-42.667-42.667zM785.067 499.201l-102.4 106.667c-12.8 12.8-38.4 21.333-55.467 21.333h-140.8l21.333-42.667h89.6v-136.533c0-17.067 12.8-29.867 29.867-29.867h140.8v-341.333h-426.667v328.533h-42.667v-341.333c0-17.067 12.8-29.867 29.867-29.867h448c17.067 0 29.867 12.8 29.867 29.867v384c4.267 17.067-8.533 38.4-21.333 51.2zM640 456.535v123.733c4.267 0 12.8-4.267 12.8-8.533l102.4-102.4c4.267-4.267 4.267-8.533 8.533-12.8h-123.733zM725.333 166.401v196.267c0 4.267-4.267 8.533-8.533 8.533s-8.533 0-12.8-4.267l-89.6-89.6v-29.867l89.6-89.6c8.533-4.267 8.533 0 12.8 0 4.267 4.267 8.533 4.267 8.533 8.533zM349.867 473.601v136.533l59.733-59.733c8.533-8.533 17.067-4.267 25.6 0l12.8 12.8c8.533 8.533 8.533 17.067 0 25.6l-115.2 106.667c-8.533 8.533-17.067 8.533-21.333 0l-115.2-110.933c-4.267-8.533-4.267-17.067 0-25.6l12.8-12.8c8.533-8.533 17.067-8.533 21.333 0l59.733 59.733v-136.533c0-8.533 8.533-17.067 17.067-17.067h25.6c0 0 17.067 8.533 17.067 21.333z" />
<glyph unicode="&#xe904;" glyph-name="play-icon" data-tags="play-icon" d="M392.533 597.335c81.067 46.933 187.733 46.933 273.067 0 42.667-25.6 72.533-55.467 98.133-98.133 72.533-128 29.867-294.4-98.133-371.2-128-72.533-294.4-29.867-371.2 98.133-46.933 81.067-46.933 187.733 0 273.067 21.333 42.667 55.467 72.533 98.133 98.133zM661.333 345.601c12.8 8.533 12.8 29.867 0 38.4l-192 110.933c-8.533 4.267-12.8 4.267-21.333 0s-12.8-12.8-12.8-21.333v-226.133c0-8.533 4.267-17.067 12.8-21.333s17.067-4.267 21.333 0l192 119.467z" />
<glyph unicode="&#xe905;" glyph-name="copy" data-tags="copy" d="M722.133 561.201h-247.733c-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-65.867 53.333-119.2 119.2-119.2h247.867c65.867 0 119.2 53.333 119.2 119.2v288.533c-0.267 65.867-53.467 119.2-119.333 119.2zM778.533 156.534c0-31.333-25.067-56.4-56.4-56.4h-247.867c-31.333 0-56.4 25.067-56.4 56.4v285.467c0 31.333 25.067 56.4 56.4 56.4h247.733c31.333 0 56.4-25.067 56.4-56.4v-285.467zM245.2 326.001v288.533c0 31.333 25.067 56.4 56.4 56.4h247.733c31.333 0 56.4-25.067 56.4-56.4v-18.8h62.667v18.8c0 65.867-53.333 119.2-119.2 119.2h-247.467c-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-65.867 53.333-119.2 119.2-119.2h18.8v62.667h-18.8c-31.467-3.067-56.533 22-56.533 56.533zM681.2 360.534h-163.067c-18.8 0-31.333 12.533-31.333 31.333s12.533 31.333 31.333 31.333h163.067c18.8 0 31.333-12.533 31.333-31.333s-15.6-31.333-31.333-31.333zM681.2 266.401h-163.067c-18.8 0-31.333 12.533-31.333 31.333s12.533 31.333 31.333 31.333h163.067c18.8 0 31.333-12.533 31.333-31.333s-15.6-31.333-31.333-31.333zM681.2 172.268h-163.067c-18.8 0-31.333 12.533-31.333 31.333s12.533 31.333 31.333 31.333h163.067c18.8 0 31.333-12.533 31.333-31.333s-15.6-31.333-31.333-31.333z" />
<glyph unicode="&#xe906;" glyph-name="examples-icon" data-tags="examples-icon" d="M213.333 166.402c89.6 38.4 183.467 68.267 273.067 17.067v281.6c-68.267 46.933-157.867 55.467-234.667 12.8l-38.4-311.467zM810.667 166.402l-42.667 315.733c-72.533 38.4-166.4 34.133-234.667-17.067v-285.867c93.867 51.2 187.733 21.333 277.333-12.8zM832 520.535c-51.2 29.867-110.933 46.933-170.667 55.467-51.2 0-102.4-8.533-149.333-29.867-46.933 21.333-98.133 29.867-149.333 29.867-59.733-4.267-119.467-25.6-170.667-55.467l-64-452.267c0 0 29.867-17.067 110.933 21.333 46.933 25.6 102.4 34.133 157.867 25.6 42.667-4.267 85.333-21.333 115.2-55.467v0c29.867 34.133 72.533 51.2 115.2 55.467 55.467 4.267 106.667-4.267 157.867-29.867 81.067-38.4 110.933-21.333 110.933-21.333l-64 456.533zM793.6 115.202c-42.667 21.333-89.6 34.133-140.8 34.133-8.533 0-21.333 0-29.867 0-42.667-4.267-81.067-17.067-115.2-42.667-34.133 25.6-72.533 38.4-115.2 42.667-12.8 0-21.333 0-34.133 0-46.933 0-93.867-8.533-136.533-29.867-21.333-12.8-46.933-21.333-72.533-25.6l64 413.867c46.933 25.6 98.133 38.4 149.333 42.667 46.933 0 93.867-8.533 136.533-25.6l12.8-8.533 12.8 4.267c42.667 17.067 89.6 25.6 136.533 25.6 51.2-4.267 102.4-17.067 149.333-42.667l59.733-418.133c-29.867 8.533-51.2 17.067-76.8 29.867z" />
<glyph unicode="&#xe907;" glyph-name="tutorials-icon" data-tags="tutorials-icon" d="M887.467 430.935l-375.467-110.933h-4.267l-217.6 68.267c-21.333-25.6-34.133-59.733-34.133-98.133 21.333-12.8 25.6-38.4 12.8-59.733-4.267-4.267-8.533-8.533-12.8-12.8l17.067-145.067c0-4.267 0-4.267-4.267-8.533 0 0 0 0-4.267 0h-64c-4.267 0-4.267 0-8.533 4.267 0 4.267-4.267 4.267-4.267 8.533l17.067 145.067c-12.8 8.533-17.067 21.333-17.067 34.133 0 17.067 8.533 29.867 21.333 38.4 0 38.4 12.8 76.8 34.133 110.933l-106.667 29.867c-8.533 4.267-8.533 8.533-8.533 17.067 0 4.267 4.267 4.267 4.267 4.267l375.467 119.467h4.267l375.467-123.733c4.267 0 8.533-4.267 8.533-8.533s-4.267-8.533-8.533-12.8zM725.333 234.669c4.267-46.933-93.867-85.333-213.333-85.333s-213.333 38.4-213.333 85.333l4.267 106.667 192-64c4.267 0 12.8 0 17.067 0s12.8 0 17.067 4.267l192 59.733 4.267-106.667z" />
<glyph unicode="&#xe908;" glyph-name="info-important-description" data-tags="info-important-description" d="M512 697.368c-188.5 0-341.3-152.8-341.3-341.3s152.8-341.4 341.3-341.4 341.3 152.8 341.3 341.3-152.8 341.4-341.3 341.4v0zM512 43.268c-172.7 0-312.7 140-312.7 312.7s140 312.7 312.7 312.7c172.7 0 312.7-140 312.7-312.7-0.2-172.6-140.1-312.5-312.7-312.7v0zM512 605.568c-137.9 0-249.6-111.8-249.6-249.6s111.7-249.6 249.6-249.6 249.6 111.8 249.6 249.6-111.8 249.6-249.6 249.6v0z" />
<glyph unicode="&#xe909;" glyph-name="icon-info" data-tags="icon-info" d="M467.2 459.522h87.467c0.028 0 0.062 0 0.095 0 6.056 0 11.499 2.629 15.248 6.808 3.979 4.15 6.419 9.769 6.419 15.957 0 0.097-0.001 0.194-0.002 0.29v70.385c0.001 0.082 0.002 0.179 0.002 0.276 0 6.188-2.44 11.806-6.409 15.946-3.759 4.19-9.201 6.819-15.257 6.819-0.033 0-0.067 0-0.1 0h-87.462c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-69.959c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.715-4.373 9.2-7.159 15.338-7.245zM597.333 156.589h-22.187v209.92c0.001 0.082 0.002 0.179 0.002 0.276 0 6.188-2.44 11.806-6.409 15.946-3.759 4.19-9.201 6.819-15.257 6.819-0.033 0-0.067 0-0.1 0h-130.128c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-46.492c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.759-4.19 9.201-6.819 15.257-6.819 0.033 0 0.067 0 0.1 0h22.182v-139.947h-22.187c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-46.492c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.759-4.19 9.201-6.819 15.257-6.819 0.033 0 0.067 0 0.1 0h174.075c0.028 0 0.062 0 0.095 0 6.056 0 11.499 2.629 15.248 6.808 3.979 4.15 6.419 9.769 6.419 15.957 0 0.097-0.001 0.194-0.002 0.29v46.065c0.043 0.527 0.067 1.141 0.067 1.761 0 5.302-1.791 10.185-4.8 14.079-3.742 4.424-9.36 7.247-15.636 7.247-0.489 0-0.975-0.017-1.456-0.051z" />
<glyph unicode="&#xe90a;" glyph-name="paste" data-tags="paste" d="M394.402 702.4h-75.333c-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-56.4 37.6-100.4 87.867-116v69.067c-15.733 9.467-25.067 25.067-25.067 47.067v288.4c0 31.333 25.067 56.4 56.4 56.4h131.733c0 0 0 0 3.2 3.2v0c0 31.333-28.267 59.6-59.6 59.6zM704.802 592.533c0 0-28.267 0-40.8 0-12.533 34.533-43.867 59.6-84.667 59.6s-69.067-25.067-81.6-59.6c-12.533 0-40.8 0-40.8 0-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-65.867 53.333-119.2 119.2-119.2h247.867c65.867 0 119.2 53.333 119.2 119.2v285.467c3.2 65.867-53.2 122.267-119.2 122.267zM582.535 605.2c22 0 40.8-18.8 40.8-40.8s-18.8-40.8-40.8-40.8c-22 0-40.8 18.8-40.8 40.8s15.733 40.8 40.8 40.8zM764.402 181.733c0-31.333-25.067-56.4-56.4-56.4h-250.933c-31.333 0-56.4 25.067-56.4 56.4v288.533c0 18.8 9.467 37.6 25.067 47.067v0c0-43.867 34.533-78.4 78.4-78.4h160c43.867 0 78.4 34.533 78.4 78.4v0c12.533-9.467 22-28.267 22-47.067v-288.533z" />
<glyph unicode="&#xe565;" glyph-name="arrow-down" data-tags="arrow-down" d="M234 565.667h556l-278-278z" />
<glyph unicode="&#xe566;" glyph-name="arrow-left" data-tags="arrow-left" d="M381 164.667v524l262-262z" />
<glyph unicode="&#xe58e;" glyph-name="colapse" data-tags="colapse" d="M512 584.667l256-256-60-60-196 196-196-196-60 60z" />
<glyph unicode="&#xe58f;" glyph-name="expand" data-tags="expand" d="M708 584.667l60-60-256-256-256 256 60 60 196-196z" />
<glyph unicode="&#xe600;" glyph-name="move" data-tags="move" d="M386.662 853.061h71.27v-71.27h-71.27v71.27zM566.067 853.061h71.27v-71.27h-71.27v71.27zM386.662 696.798h71.27v-71.27h-71.27v71.27zM566.067 696.798h71.27v-71.27h-71.27v71.27zM386.662 540.433h71.27v-71.27h-71.27v71.27zM566.067 540.433h71.27v-71.27h-71.27v71.27zM386.662 384.171h71.27v-71.27h-71.27v71.27zM566.067 384.171h71.27v-71.27h-71.27v71.27zM386.662 227.806h71.27v-71.27h-71.27v71.27zM566.067 227.806h71.27v-71.27h-71.27v71.27zM386.662 71.544h71.27v-71.27h-71.27v71.27zM566.067 71.544h71.27v-71.27h-71.27v71.27z" />
<glyph unicode="&#xe601;" glyph-name="check-mark" data-tags="check-mark" d="M454.301 395.253l-116.917 116.917-84.781-84.707 201.696-201.697 317.097 317.097-84.781 84.706z" />
<glyph unicode="&#xe888;" glyph-name="arrow-up-circle" data-tags="arrow-up-circle" d="M513.344 689.068c-148.616 0-264.722-120.75-260.077-269.367 0-125.395 88.241-232.212 208.991-255.434v213.636h-92.885c-13.933 0-13.933 9.288-9.288 18.577l139.327 171.838c4.645 9.288 13.933 9.288 23.221 4.645 0 0 4.645-4.645 4.645-4.645l139.327-171.838c9.288-9.288 4.645-18.577-9.288-18.577h-92.885v-213.636c143.972 32.51 232.212 171.838 199.703 315.808-23.221 120.75-130.039 204.347-250.789 208.991z" />
<glyph unicode="&#xe889;" glyph-name="info-circle" data-tags="info-circle" d="M512 686.933c-144.077 0-260.266-116.191-260.266-260.266s116.191-260.266 260.266-260.266 260.266 116.191 260.266 260.266v0c0 139.429-116.191 255.619-260.266 260.266zM470.171 635.81h88.305v-69.714h-88.305v69.714zM600.305 245.41h-181.257v51.123h51.123v162.666h-51.123v51.123h139.429v-218.438h46.477l-4.648-46.477z" />
<glyph unicode="&#xe88a;" glyph-name="search" data-tags="search" d="M769.263 223.163l-110.68 110.68c71.943 99.612 49.806 243.494-49.806 315.437s-243.494 44.27-315.437-55.339c-71.943-99.612-49.806-243.494 49.806-315.437 77.475-55.339 182.623-55.339 260.098 0l110.68-110.68c5.533-5.533 11.068-5.533 16.601 0 0 0 0 0 0 0l33.205 33.205c11.068 5.533 11.068 16.601 5.533 22.137 0 0 0 0 0 0zM475.96 300.638c-88.544 0-160.486 71.943-160.486 160.486s71.943 160.486 160.486 160.486 160.486-71.943 160.486-160.486-71.943-160.486-160.486-160.486v0z" />
<glyph unicode="&#xe88c;" glyph-name="fullscreen" data-tags="fullscreen" d="M357.075 572.983c5.737 5.737 0 5.737-5.737 5.737l-103.284 11.476c-5.737 5.737-11.476 0-11.476-5.737l11.476-109.021c0-5.737 5.737-5.737 5.737-5.737l103.284 103.284zM282.484 509.865l63.118-63.118c5.737-5.737 11.476-5.737 17.213 0l22.953 22.953c5.737 5.737 5.737 11.476 0 17.213l-63.118 57.379-40.166-34.429zM775.945 469.699c5.737-5.737 5.737 0 5.737 5.737l11.476 109.021c0 5.737-5.737 11.476-11.476 11.476l-109.021-11.476c-5.737 0-5.737-5.737-5.737-5.737l109.021-109.021zM712.83 544.294l-63.118-63.118c-5.737-5.737-5.737-11.476 0-17.213l22.953-22.953c5.737-5.737 11.476-5.737 17.213 0l63.118 63.118-40.166 40.166zM678.401 263.134c-5.737-5.737 0-5.737 5.737-5.737l109.021-11.476c5.737 0 11.476 5.737 11.476 11.476l-17.213 103.284c0 5.737-5.737 5.737-5.737 5.737l-103.284-103.284zM747.256 331.989l-63.118 63.118c-5.737 5.737-11.476 5.737-17.213 0l-22.953-22.953c-5.737-5.737-5.737-11.476 0-17.213l63.118-63.118 40.166 40.166zM253.794 366.418c-5.737 5.737-5.737 0-5.737-5.737l-11.476-109.021c0-5.737 5.737-11.476 11.476-11.476l109.021 11.476c5.737 0 5.737 5.737 5.737 5.737l-109.021 109.021zM322.649 291.824l63.118 63.118c5.737 5.737 5.737 11.476 0 17.213l-22.953 22.953c-5.737 5.737-11.476 5.737-17.213 0l-63.118-63.118 40.166-40.166zM150.51 676.267v-499.201h722.979v499.201h-722.979zM833.324 217.232h-636.911v413.13h636.911v-413.13z" />
<glyph unicode="&#xe88e;" glyph-name="h5p" data-tags="h5p" d="M891.406 574.524c-22.319 16.738-50.216 27.897-89.273 27.897h-139.487v-66.954h-156.225l-11.159-55.795c11.159 5.579 27.897 11.159 39.057 11.159s22.319 0 33.476 0c33.476 0 66.954-11.159 89.273-33.476s33.476-50.216 33.476-83.692c0-22.319-5.579-44.635-16.738-66.954s-27.897-39.057-50.216-50.216c-5.579-5.579-16.738 0-22.319-11.159h117.17v133.908h66.954c44.635 0 78.113 11.159 100.43 27.897 22.319 22.319 33.476 50.216 33.476 83.692 0 39.057-11.159 66.954-27.897 83.692v0zM796.555 462.935c-11.159-5.579-22.319-11.159-44.635-11.159h-33.476v83.692h39.057c22.319 0 33.476-5.579 44.635-11.159 5.579-5.579 11.159-16.738 11.159-27.897 0-16.738-5.579-27.897-16.738-33.476v0zM523.16 423.878c-16.738 0-33.476-11.159-44.635-27.897l-94.851 16.738 44.635 195.281h-94.851v-150.646h-117.17v150.646h-111.589v-362.667h111.589v133.908h117.17v-133.908h139.487c-16.738 11.159-33.476 11.159-44.635 22.319s-22.319 22.319-27.897 33.476c-5.579 11.159-11.159 22.319-16.738 39.057l94.851 16.738c5.579-16.738 22.319-27.897 44.635-27.897 27.897 0 50.216 22.319 50.216 50.216 0 22.319-22.319 44.635-50.216 44.635v0z" />
<glyph unicode="&#xe88f;" glyph-name="rights-of-use" data-tags="rights-of-use" d="M878.277 414.35c0-5.907 0-5.907 0-5.907-23.631-23.631-47.261-35.448-76.799-41.355-11.813 0-23.631-5.907-35.448-5.907s-17.724 0-29.537 0c0 0-5.907 0-5.907 5.907-64.985 59.079-135.877 118.153-200.863 183.139 0 0-5.907 0-5.907 0-23.631-5.907-47.261-11.813-70.892-17.724s-53.168 0-76.799 11.813c-17.724 11.813-23.631 17.724-29.537 35.448-5.907 5.907 0 23.631 11.813 23.631 41.355 11.813 88.616 29.537 129.971 47.261 11.813 5.907 29.537 5.907 41.355 5.907 5.907 0 11.813-5.907 11.813-5.907 41.355-17.724 82.709-29.537 124.060-47.261 0 0 5.907 0 5.907 0 29.537 5.907 64.985 17.724 94.523 23.631 5.907 0 5.907 0 5.907 0l106.34-212.676zM269.786 420.26c17.724 11.813 35.448 5.907 53.168-11.813 11.813-11.813 11.813-29.537 5.907-47.261 17.724 5.907 35.448-5.907 41.355-17.724 11.813-17.724 5.907-35.448-5.907-47.261 5.907 0 11.813 0 17.724 0 11.813-5.907 23.631-11.813 29.537-29.537s0-29.537-5.907-35.448c-5.907-5.907-11.813-11.813-17.724-17.724s-11.813-11.813-17.724-17.724-35.448-17.724-53.168 0c-29.537 29.537-53.168 64.985-82.709 94.523-17.724 23.631-35.448 41.355-47.261 64.985-5.907 11.813-11.813 17.724-11.813 29.537 0 5.907 0 17.724 5.907 23.631 11.813 11.813 17.724 17.724 29.537 29.537 17.724 17.724 47.261 11.813 64.985-5.907-5.907 0-5.907-5.907-5.907-11.813v0zM417.477 213.491l29.537-29.537c17.724-17.724 47.261-11.813 59.079 5.907l-5.907 5.907c-23.631 23.631-47.261 47.261-70.892 70.892-5.907 5.907-5.907 5.907-5.907 11.813s5.907 5.907 11.813 11.813c5.907 0 11.813 0 11.813-5.907 11.813-11.813 29.537-29.537 47.261-47.261 11.813-11.813 29.537-29.537 47.261-47.261 5.907-11.813 17.724-11.813 29.537-11.813 11.813 5.907 23.631 11.813 29.537 23.631 0 5.907 0 5.907 0 5.907-41.355 41.355-88.616 82.709-129.971 129.971-5.907 5.907-5.907 5.907-5.907 11.813 0 11.813 11.813 11.813 23.631 5.907 0 0 5.907 0 5.907-5.907 41.355-41.355 88.616-88.616 129.971-129.971 5.907-5.907 5.907-5.907 5.907-5.907 17.724 0 35.448 17.724 35.448 35.448 0 5.907 0 5.907 0 5.907-47.261 47.261-100.429 100.429-147.691 147.691-5.907 5.907-5.907 5.907-5.907 11.813s5.907 11.813 5.907 11.813c5.907 0 11.813 0 11.813-5.907 5.907-5.907 5.907-5.907 11.813-11.813 35.448-35.448 70.892-70.892 106.34-106.34 11.813-11.813 23.631-23.631 29.537-29.537 0 0 5.907-5.907 5.907 0 23.631 5.907 35.448 29.537 29.537 53.168h35.448c0 0 0 0 0 0 0-5.907 0-17.724 0-23.631-5.907-29.537-23.631-47.261-53.168-59.079 0 0-5.907 0-5.907-5.907-11.813-29.537-35.448-53.168-64.985-53.168-5.907 0-5.907 0-5.907-5.907-17.724-35.448-59.079-47.261-88.616-35.448-5.907 0-11.813 5.907-11.813 5.907-5.907-5.907-11.813-11.813-23.631-17.724-29.537-11.813-59.079-5.907-76.799 11.813-11.813 11.813-17.724 17.724-29.537 29.537 17.724 23.631 23.631 29.537 29.537 41.355v0 0zM252.062 727.459c29.537-11.813 64.985-23.631 94.523-29.537 35.448-11.813 64.985-23.631 100.429-29.537 0 0 0 0 5.907 0-17.724-5.907-35.448-11.813-47.261-17.724 0 0-5.907 0-5.907 0-47.261 11.813-94.523 23.631-135.877 41.355-5.907 0-5.907 0-5.907 0l-76.799-183.139c0-11.813 5.907-17.724 11.813-23.631s5.907-5.907 5.907-11.813c-5.907-5.907-11.813-17.724-23.631-23.631-17.724 17.724-29.537 35.448-29.537 64.985l88.616 212.676c-5.907-11.813 5.907 5.907 17.724 0v0z" />
<glyph unicode="&#xe890;" glyph-name="delete-circle" data-tags="delete-circle" d="M512 686.933c-147.107 0-260.266-118.817-260.266-260.266s118.817-260.266 260.266-260.266 260.266 118.817 260.266 260.266-113.158 260.266-260.266 260.266zM653.449 347.455c5.659-5.659 5.659-16.973 0-28.29l-33.949-33.949c-5.659-5.659-16.973-5.659-28.29 0l-79.212 79.212-79.212-79.212c-5.659-5.659-16.973-5.659-28.29 0l-33.949 33.949c-5.659 5.659-5.659 16.973 0 28.29l84.871 79.212-79.212 79.212c-5.659 5.659-5.659 16.973 0 28.29l33.949 33.949c5.659 5.659 16.973 5.659 28.29 0l73.554-84.871 79.212 79.212c5.659 5.659 16.973 5.659 28.29 0l33.949-33.949c5.659-5.659 5.659-16.973 0-28.29l-79.212-73.554 79.212-79.212z" />
<glyph unicode="&#xe891;" glyph-name="window" data-tags="window" d="M186.821 549.319c-5.704-5.704 0-5.704 5.704-5.704l108.394-11.41c5.704 0 11.41 5.704 11.41 11.41l-17.114 102.687c0 5.704-5.704 5.704-5.704 5.704l-102.687-102.687zM255.28 612.074l-62.752 62.752c-5.704 5.704-11.41 5.704-17.114 0l-17.114-22.821c-5.704-5.704-5.704-11.41 0-17.114l62.752-62.752 34.228 39.935zM734.49 646.302c-5.704 5.704-5.704 0-5.704-5.704l-11.41-108.394c0-5.704 5.704-11.41 11.41-11.41l108.394 11.41c5.704 0 5.704 5.704 5.704 5.704l-108.394 108.394zM797.242 572.14l62.752 62.752c5.704 5.704 5.704 11.41 0 17.114l-22.821 22.821c-5.704 5.704-11.41 5.704-17.114 0l-62.752-62.752 39.935-39.935zM831.473 309.717c5.704 5.704 0 5.704-5.704 5.704l-102.687 17.114c-5.704 0-11.41-5.704-11.41-11.41l11.41-108.394c0-5.704 5.704-5.704 5.704-5.704l102.687 102.687zM763.014 246.962l62.752-62.752c5.704-5.704 11.41-5.704 17.114 0l22.821 22.821c5.704 5.704 5.704 11.41 0 17.114l-62.752 62.752-39.935-39.935zM283.804 212.734c5.704-5.704 5.704 0 5.704 5.704l11.41 108.394c0 5.704-5.704 11.41-11.41 11.41l-108.394-11.41c-5.704 0-5.704-5.704-5.704-5.704l108.394-108.394zM221.052 281.193l-62.752-62.752c-5.704-5.704-5.704-11.41 0-17.114l22.821-22.821c5.704-5.704 11.41-5.704 17.114 0l62.752 62.752-39.935 39.935zM335.149 555.026v-239.605h347.998v239.605h-347.998zM637.507 355.355h-262.424v154.032h262.424v-154.032z" />
<glyph unicode="&#xe892;" glyph-name="code" data-tags="code" d="M446.523 311.303c6.235-6.235 6.235-12.472 6.235-18.707v-62.359c0-6.235-6.235-6.235-6.235-6.235l-230.728 155.897c-6.235 6.235-6.235 12.472-6.235 18.707v49.886c0 6.235 6.235 12.472 6.235 18.707l230.728 155.897c6.235 6.235 6.235 0 6.235-6.235v-62.359c0-6.235-6.235-12.472-6.235-18.707l-162.134-112.245c-6.235-6.235-6.235-6.235 0-12.472l162.134-99.776zM733.375 417.313c6.235 6.235 6.235 6.235 0 12.472l-155.897 112.245c-6.235 6.235-6.235 12.472-6.235 18.707v62.359c0 6.235 6.235 6.235 6.235 6.235l230.728-155.897c6.235-6.235 6.235-12.472 6.235-18.707v-49.886c0-6.235-6.235-12.472-6.235-18.707l-230.728-155.897c-6.235-6.235-6.235 0-6.235 6.235v62.359c0 6.235 6.235 12.472 6.235 18.707l155.897 99.776z" />
<glyph unicode="&#xe893;" glyph-name="download" data-tags="download" d="M353.050 512.027c-11.773 0-17.66-5.887-5.887-17.66l153.059-188.382c5.887-11.773 23.547-11.773 29.433 0l153.059 188.382c5.887 11.773 5.887 17.66-5.887 17.66h-323.782zM570.865 500.253v135.399c0 11.773-11.773 23.547-23.547 23.547h-70.643c-11.773 0-23.547-11.773-23.547-23.547v-141.286h117.739zM647.395 364.854c-5.887 0-17.66-5.887-23.547-11.773l-76.53-94.19c-5.887-5.887-17.66-17.66-23.547-23.547 0 0-5.887-5.887-11.773-5.887s-17.66 11.773-17.66 11.773c-5.887 5.887-17.66 17.66-23.547 23.547l-76.53 94.19c-5.887 5.887-17.66 11.773-23.547 11.773h-123.626c-5.887 0-17.66-5.887-17.66-17.66v-141.286c0-5.887 5.887-17.66 17.66-17.66h529.824c5.887 0 17.66 5.887 17.66 17.66v141.286c0 5.887-5.887 17.66-17.66 17.66l-129.513-5.887zM300.067 253.004c-17.66 0-29.433 11.773-29.433 29.433s11.773 29.433 29.433 29.433c17.66 0 29.433-11.773 29.433-29.433s-11.773-29.433-29.433-29.433v0z" />
<glyph unicode="&#xe894;" glyph-name="delete" data-tags="delete" d="M615.111 426.667l134.045 134.045c10.311 10.311 10.311 30.934 0 41.245l-61.866 61.866c-10.311 10.311-30.934 10.311-41.245 0l-134.045-134.045-134.045 134.045c-10.311 10.311-30.934 10.311-41.245 0l-61.866-61.866c-10.311-10.311-10.311-30.934 0-41.245l134.045-134.045-134.045-134.045c-10.311-10.311-10.311-30.934 0-41.245l61.866-61.866c10.311-10.311 30.934-10.311 41.245 0l134.045 134.045 134.045-134.045c10.311-10.311 30.934-10.311 41.245 0l61.866 61.866c10.311 10.311 10.311 30.934 0 41.245l-134.045 134.045z" />
<glyph unicode="&#xe900;" glyph-name="edit-image" data-tags="edit-image" d="M300.336 749.664c69.018 23.142 133.325 14.234 189.133-33.28 56.627-48.128 77.619-110.592 63.181-183.808-2.355-12.186 0.307-19.456 8.704-27.853 93.901-93.389 156.774-156.467 250.47-250.163 5.427-5.427 10.957-10.854 15.667-16.896 39.424-50.278 16.794-124.006-44.237-142.029-36.966-10.957-68.403 0-95.334 27.034-95.642 96.051-160.973 160.973-256.614 257.024-6.963 6.963-12.8 8.909-22.63 6.758-117.76-26.317-229.171 60.826-231.731 181.453-0.614 26.419 3.584 52.326 15.974 77.926 34.816-34.816 68.506-67.789 101.274-101.786 10.445-10.752 20.992-15.36 36.045-15.36 14.643 0 25.19 3.891 34.816 14.848 10.752 12.39 23.040 23.347 34.611 35.021 14.336 14.438 14.336 46.080-0.205 60.518-35.123 35.226-70.349 70.349-106.598 106.496 3.891 2.253 5.632 3.482 7.475 4.096zM703.485 191.584c-0.41-24.269 20.685-45.466 44.851-45.158 23.757 0.41 44.032 20.992 43.93 44.544-0.102 23.757-20.275 44.032-44.237 44.134-23.859 0.307-44.237-19.661-44.544-43.52z" />
<glyph unicode="&#xe901;" glyph-name="hourglass" data-tags="hourglass" d="M733.414 117.419c-147.763 0-295.526 0-443.29 0 0 2.048 0.102 4.096 0 6.144-0.307 13.824-1.024 32.666-0.922 46.49 0.41 39.731 6.861 78.131 19.046 115.2 17.203 52.224 43.725 96.256 81.306 130.355 4.506 4.096 9.216 7.885 13.722 11.776-0.205 0.717-0.307 1.126-0.41 1.229-1.331 1.229-2.765 2.355-4.198 3.584-28.058 22.63-50.688 51.405-68.403 85.606-30.618 59.085-43.52 123.597-41.165 192.614 0.205 7.168 0.614 18.33 0.922 25.498 147.763 0 295.526 0 443.29 0 0.205-1.331 0.512-2.662 0.614-3.994 2.662-36.966 1.229-77.722-5.939-113.869-14.336-72.909-44.544-133.837-95.027-179.405-4.096-3.686-8.294-7.066-12.39-10.547 0.205-0.717 0.307-1.126 0.512-1.331 0.819-0.717 1.638-1.434 2.458-2.15 42.189-33.894 71.68-79.872 90.931-135.782 11.776-34.202 18.637-69.837 20.070-106.701 0.819-19.763-0.614-44.851-1.126-64.717zM687.437 160.632c0 6.554 0.205 12.493 0 18.432-1.331 37.581-7.27 74.138-19.866 108.749-17.92 49.562-45.568 88.269-88.678 108.646-2.458 1.126-2.97 3.072-2.97 5.837 0.102 16.691 0.102 33.485 0 50.176 0 3.994 1.331 5.427 4.096 6.963 9.114 5.325 18.432 10.24 26.829 16.896 29.696 23.552 49.152 56.934 62.362 95.744 10.342 30.413 15.77 62.259 17.818 94.822 0.614 9.114 0.102 18.227 0.102 27.546-116.634 0-233.574 0-351.027 0 0.307-8.704 0.614-16.998 1.024-25.395 1.946-37.274 8.499-73.216 21.504-107.213 18.125-47.104 45.261-83.558 86.528-103.117 2.253-1.024 2.867-2.662 2.867-5.427-0.102-17.203-0.102-34.509 0-51.712 0-3.072-1.024-4.506-3.277-5.632-5.632-2.867-11.366-5.734-16.691-9.216-34.304-22.733-56.832-57.754-71.987-100.147-12.493-35.123-18.125-71.987-19.661-109.875-0.205-5.325 0-10.752 0-16.282 117.35 0.205 234.189 0.205 351.027 0.205zM410.342 579.96c68.096 0 135.373 0 203.674 0-3.789-6.554-7.168-12.595-10.752-18.227-10.957-16.998-24.269-30.618-39.731-41.472s-27.75-25.293-32.768-46.592c-1.638-6.963-2.765-14.336-2.867-21.606-0.307-17.203-0.205-34.406 0.307-51.712 0.717-28.058 12.493-48.947 32.154-62.566 43.008-30.003 65.843-75.878 75.776-132.506 0.307-1.638 0.307-3.379 0.614-5.53-83.149 0-166.093 0-249.242 0 2.662 20.685 7.885 40.346 15.462 59.085 13.312 32.973 32.768 59.187 59.494 77.722 16.589 11.469 28.365 27.955 32.358 50.995 0.819 4.813 1.331 9.83 1.434 14.746 0.102 18.637 0.614 37.274-0.205 55.808-1.126 24.678-11.981 43.213-28.57 57.139-9.216 7.782-18.944 14.746-27.648 23.142-11.981 11.162-21.197 25.395-29.491 41.574z" />
<glyph unicode="&#xe902;" glyph-name="plus-icon" data-tags="plus-icon" d="M767.787 391.893c0-19.323-15.664-34.987-34.987-34.987h-151.040v-151.467c0-19.323-15.664-34.987-34.987-34.987h-69.547c-19.323 0-34.987 15.664-34.987 34.987v151.467h-151.467c-19.323 0-34.987 15.664-34.987 34.987v69.547c0 19.323 15.664 34.987 34.987 34.987h151.467v151.467c0 19.323 15.664 34.987 34.987 34.987h69.547c19.323 0 34.987-15.664 34.987-34.987v-151.467h151.467c19.323 0 34.987-15.664 34.987-34.987z" />
<glyph unicode="&#xe903;" glyph-name="video-upload-icon" data-tags="video-upload-icon" d="M395.848 387.201v-128c0-21.333 21.333-42.667 42.667-42.667h128c21.333 0 42.667 17.067 42.667 42.667v128c0 21.333-17.067 42.667-42.667 42.667h-128c-21.333 0-42.667-17.067-42.667-42.667zM796.915 557.867l-102.4 106.667c-12.8 12.8-38.4 21.333-55.467 21.333h-140.8l21.333-42.667h89.6v-136.533c0-17.067 12.8-29.867 29.867-29.867h140.8v-341.333h-426.667v328.533h-42.667v-341.333c0-17.067 12.8-29.867 29.867-29.867h448c17.067 0 29.867 12.8 29.867 29.867v384c4.267 17.067-8.533 38.4-21.333 51.2zM651.848 515.201v123.733c4.267 0 12.8-4.267 12.8-8.533l102.4-102.4c4.267-4.267 4.267-8.533 8.533-12.8h-123.733zM737.181 225.067v196.267c0 4.267-4.267 8.533-8.533 8.533s-8.533 0-12.8-4.267l-89.6-89.6v-29.867l89.6-89.6c8.533-4.267 8.533 0 12.8 0 4.267 4.267 8.533 4.267 8.533 8.533zM361.715 532.267v136.533l59.733-59.733c8.533-8.533 17.067-4.267 25.6 0l12.8 12.8c8.533 8.533 8.533 17.067 0 25.6l-115.2 106.667c-8.533 8.533-17.067 8.533-21.333 0l-115.2-110.933c-4.267-8.533-4.267-17.067 0-25.6l12.8-12.8c8.533-8.533 17.067-8.533 21.333 0l59.733 59.733v-136.533c0-8.533 8.533-17.067 17.067-17.067h25.6c0 0 17.067 8.533 17.067 21.333z" />
<glyph unicode="&#xe904;" glyph-name="play-icon" data-tags="play-icon" d="M375.444 661.357c81.067 46.933 187.733 46.933 273.067 0 42.667-25.6 72.533-55.467 98.133-98.133 72.533-128 29.867-294.4-98.133-371.2-128-72.533-294.4-29.867-371.2 98.133-46.933 81.067-46.933 187.733 0 273.067 21.333 42.667 55.467 72.533 98.133 98.133zM644.244 409.623c12.8 8.533 12.8 29.867 0 38.4l-192 110.933c-8.533 4.267-12.8 4.267-21.333 0s-12.8-12.8-12.8-21.333v-226.133c0-8.533 4.267-17.067 12.8-21.333s17.067-4.267 21.333 0l192 119.467z" />
<glyph unicode="&#xe905;" glyph-name="copy" data-tags="copy" d="M722.133 603.867h-247.733c-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-65.867 53.333-119.2 119.2-119.2h247.867c65.867 0 119.2 53.333 119.2 119.2v288.533c-0.267 65.867-53.467 119.2-119.333 119.2zM778.533 199.2c0-31.333-25.067-56.4-56.4-56.4h-247.867c-31.333 0-56.4 25.067-56.4 56.4v285.467c0 31.333 25.067 56.4 56.4 56.4h247.733c31.333 0 56.4-25.067 56.4-56.4v-285.467zM245.2 368.667v288.533c0 31.333 25.067 56.4 56.4 56.4h247.733c31.333 0 56.4-25.067 56.4-56.4v-18.8h62.667v18.8c0 65.867-53.333 119.2-119.2 119.2h-247.467c-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-65.867 53.333-119.2 119.2-119.2h18.8v62.667h-18.8c-31.467-3.067-56.533 22-56.533 56.533zM681.2 403.2h-163.067c-18.8 0-31.333 12.533-31.333 31.333s12.533 31.333 31.333 31.333h163.067c18.8 0 31.333-12.533 31.333-31.333s-15.6-31.333-31.333-31.333zM681.2 309.067h-163.067c-18.8 0-31.333 12.533-31.333 31.333s12.533 31.333 31.333 31.333h163.067c18.8 0 31.333-12.533 31.333-31.333s-15.6-31.333-31.333-31.333zM681.2 214.934h-163.067c-18.8 0-31.333 12.533-31.333 31.333s12.533 31.333 31.333 31.333h163.067c18.8 0 31.333-12.533 31.333-31.333s-15.6-31.333-31.333-31.333z" />
<glyph unicode="&#xe906;" glyph-name="examples-icon" data-tags="examples-icon" d="M213.333 275.201c89.6 38.4 183.467 68.267 273.067 17.067v281.6c-68.267 46.933-157.867 55.467-234.667 12.8l-38.4-311.467zM810.667 275.201l-42.667 315.733c-72.533 38.4-166.4 34.133-234.667-17.067v-285.867c93.867 51.2 187.733 21.333 277.333-12.8zM832 629.334c-51.2 29.867-110.933 46.933-170.667 55.467-51.2 0-102.4-8.533-149.333-29.867-46.933 21.333-98.133 29.867-149.333 29.867-59.733-4.267-119.467-25.6-170.667-55.467l-64-452.267c0 0 29.867-17.067 110.933 21.333 46.933 25.6 102.4 34.133 157.867 25.6 42.667-4.267 85.333-21.333 115.2-55.467v0c29.867 34.133 72.533 51.2 115.2 55.467 55.467 4.267 106.667-4.267 157.867-29.867 81.067-38.4 110.933-21.333 110.933-21.333l-64 456.533zM793.6 224.001c-42.667 21.333-89.6 34.133-140.8 34.133-8.533 0-21.333 0-29.867 0-42.667-4.267-81.067-17.067-115.2-42.667-34.133 25.6-72.533 38.4-115.2 42.667-12.8 0-21.333 0-34.133 0-46.933 0-93.867-8.533-136.533-29.867-21.333-12.8-46.933-21.333-72.533-25.6l64 413.867c46.933 25.6 98.133 38.4 149.333 42.667 46.933 0 93.867-8.533 136.533-25.6l12.8-8.533 12.8 4.267c42.667 17.067 89.6 25.6 136.533 25.6 51.2-4.267 102.4-17.067 149.333-42.667l59.733-418.133c-29.867 8.533-51.2 17.067-76.8 29.867z" />
<glyph unicode="&#xe907;" glyph-name="tutorials-icon" data-tags="tutorials-icon" d="M887.468 537.598l-375.467-110.933h-4.267l-217.6 68.267c-21.333-25.6-34.133-59.733-34.133-98.133 21.333-12.8 25.6-38.4 12.8-59.733-4.267-4.267-8.533-8.533-12.8-12.8l17.067-145.067c0-4.267 0-4.267-4.267-8.533 0 0 0 0-4.267 0h-64c-4.267 0-4.267 0-8.533 4.267 0 4.267-4.267 4.267-4.267 8.533l17.067 145.067c-12.8 8.533-17.067 21.333-17.067 34.133 0 17.067 8.533 29.867 21.333 38.4 0 38.4 12.8 76.8 34.133 110.933l-106.667 29.867c-8.533 4.267-8.533 8.533-8.533 17.067 0 4.267 4.267 4.267 4.267 4.267l375.467 119.467h4.267l375.467-123.733c4.267 0 8.533-4.267 8.533-8.533s-4.267-8.533-8.533-12.8zM725.334 341.332c4.267-46.933-93.867-85.333-213.333-85.333s-213.333 38.4-213.333 85.333l4.267 106.667 192-64c4.267 0 12.8 0 17.067 0s12.8 0 17.067 4.267l192 59.733 4.267-106.667z" />
<glyph unicode="&#xe908;" glyph-name="info-important-description" data-tags="info-important-description" d="M512 768.017c-188.5 0-341.3-152.8-341.3-341.3s152.8-341.4 341.3-341.4 341.3 152.8 341.3 341.3-152.8 341.4-341.3 341.4v0zM512 113.917c-172.7 0-312.7 140-312.7 312.7s140 312.7 312.7 312.7c172.7 0 312.7-140 312.7-312.7-0.2-172.6-140.1-312.5-312.7-312.7v0zM512 676.217c-137.9 0-249.6-111.8-249.6-249.6s111.7-249.6 249.6-249.6 249.6 111.8 249.6 249.6-111.8 249.6-249.6 249.6v0z" />
<glyph unicode="&#xe909;" glyph-name="icon-info" data-tags="icon-info" d="M468.875 565.974h87.467c0.028 0 0.062 0 0.095 0 6.056 0 11.499 2.629 15.248 6.808 3.979 4.15 6.419 9.769 6.419 15.957 0 0.097-0.001 0.194-0.002 0.29v70.385c0.001 0.082 0.002 0.179 0.002 0.276 0 6.188-2.44 11.806-6.409 15.946-3.759 4.19-9.201 6.819-15.257 6.819-0.033 0-0.067 0-0.1 0h-87.462c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-69.959c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.715-4.373 9.2-7.159 15.338-7.245zM599.008 263.041h-22.187v209.92c0.001 0.082 0.002 0.179 0.002 0.276 0 6.188-2.44 11.806-6.409 15.946-3.759 4.19-9.201 6.819-15.257 6.819-0.033 0-0.067 0-0.1 0h-130.128c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-46.492c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.759-4.19 9.201-6.819 15.257-6.819 0.033 0 0.067 0 0.1 0h22.182v-139.947h-22.187c-0.028 0-0.062 0-0.095 0-6.056 0-11.499-2.629-15.248-6.808-3.979-4.15-6.419-9.769-6.419-15.957 0-0.097 0.001-0.194 0.002-0.29v-46.492c-0.001-0.082-0.002-0.179-0.002-0.276 0-6.188 2.44-11.806 6.409-15.946 3.759-4.19 9.201-6.819 15.257-6.819 0.033 0 0.067 0 0.1 0h174.075c0.028 0 0.062 0 0.095 0 6.056 0 11.499 2.629 15.248 6.808 3.979 4.15 6.419 9.769 6.419 15.957 0 0.097-0.001 0.194-0.002 0.29v46.065c0.043 0.527 0.067 1.141 0.067 1.761 0 5.302-1.791 10.185-4.8 14.079-3.742 4.424-9.36 7.247-15.636 7.247-0.489 0-0.975-0.017-1.456-0.051z" />
<glyph unicode="&#xe90a;" glyph-name="paste" data-tags="paste" d="M394.402 745.067h-75.333c-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-56.4 37.6-100.4 87.867-116v69.067c-15.733 9.467-25.067 25.067-25.067 47.067v288.4c0 31.333 25.067 56.4 56.4 56.4h131.733c0 0 0 0 3.2 3.2v0c0 31.333-28.267 59.6-59.6 59.6zM704.802 635.2c0 0-28.267 0-40.8 0-12.533 34.533-43.867 59.6-84.667 59.6s-69.067-25.067-81.6-59.6c-12.533 0-40.8 0-40.8 0-65.867 0-119.2-53.333-119.2-119.2v-288.533c0-65.867 53.333-119.2 119.2-119.2h247.867c65.867 0 119.2 53.333 119.2 119.2v285.467c3.2 65.867-53.2 122.267-119.2 122.267zM582.535 647.867c22 0 40.8-18.8 40.8-40.8s-18.8-40.8-40.8-40.8c-22 0-40.8 18.8-40.8 40.8s15.733 40.8 40.8 40.8zM764.402 224.4c0-31.333-25.067-56.4-56.4-56.4h-250.933c-31.333 0-56.4 25.067-56.4 56.4v288.533c0 18.8 9.467 37.6 25.067 47.067v0c0-43.867 34.533-78.4 78.4-78.4h160c43.867 0 78.4 34.533 78.4 78.4v0c12.533-9.467 22-28.267 22-47.067v-288.533z" />
<glyph unicode="&#xe90b;" glyph-name="reuse" data-tags="reuse" d="M734.974 624.751c-54.605 61.619-134.123 100.573-222.977 100.573-164.936 0-298.661-133.724-298.661-298.661h74.667c0 123.721 100.272 223.993 223.993 223.993 68.214 0 128.747-30.96 169.766-79.119l-70.213-70.213h199.109v199.109l-75.689-75.689zM511.999 202.671c-68.214 0-128.747 30.96-169.766 79.119l70.213 70.213h-199.109v-199.109l75.689 75.689c54.605-61.619 134.123-100.573 222.977-100.573 164.936 0 298.661 133.724 298.661 298.661h-74.667c0-123.721-100.272-223.993-223.993-223.993z" />
<glyph unicode="&#xe90c;" glyph-name="info-outlined" data-tags="info-outlined" d="M467.199 181.336h89.599v268.8h-89.599v-268.8zM512 853.335c-247.296 0-448.001-200.705-448.001-448.001s200.705-448.001 448.001-448.001 448.001 200.705 448.001 448.001-200.705 448.001-448.001 448.001zM512 46.936c-197.568 0-358.398 160.83-358.398 358.398s160.83 358.398 358.398 358.398 358.398-160.83 358.398-358.398-160.83-358.398-358.398-358.398zM467.199 539.734h89.599v89.599h-89.599v-89.599z" />
<glyph unicode="&#xe90d;" glyph-name="spinner" data-tags="spinner" d="M600 808.001c0-48.602-39.398-88-88-88s-88 39.398-88 88 39.398 88 88 88 88-39.398 88-88zM512 133.333c-48.602 0-88-39.398-88-88s39.398-88 88-88 88 39.398 88 88-39.398 88-88 88zM893.334 514.667c-48.602 0-88-39.398-88-88s39.398-88 88-88 88 39.398 88 88-39.398 88-88 88zM218.666 426.667c0 48.602-39.398 88-88 88s-88-39.398-88-88 39.398-88 88-88 88 39.398 88 88zM242.357 245.024c-48.602 0-88-39.398-88-88s39.398-88 88-88 88 39.398 88 88c0 48.6-39.4 88-88 88zM781.643 245.024c-48.602 0-88-39.398-88-88s39.398-88 88-88 88 39.398 88 88c0 48.6-39.398 88-88 88zM242.357 784.31c-48.602 0-88-39.398-88-88s39.398-88 88-88 88 39.398 88 88-39.4 88-88 88z" />

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.
Binary file not shown.
@@ -107,7 +107,7 @@ abstract class H5PMetadata {
switch ($config['type']) {
case 'text':
if ($value !== null && strlen($value) > $config['maxLength']) {
$value = \core_text::substr($value, 0, $config['maxLength']);
$value = mb_substr($value, 0, $config['maxLength']);
}
$types[] = '%s';
break;
+13 -17
View File
@@ -758,14 +758,11 @@ class H5PValidator {
unlink($tmpPath);
return FALSE;
}
// Moodle: the extension mbstring is optional.
/*
if (!extension_loaded('mbstring')) {
$this->h5pF->setErrorMessage($this->h5pF->t('The mbstring PHP extension is not loaded. H5P need this to function properly'), 'mbstring-unsupported');
unlink($tmpPath);
return FALSE;
}
*/
// Create a temporary dir to extract package in.
$tmpDir = $this->h5pF->getUploadedH5pFolderPath();
@@ -812,7 +809,7 @@ class H5PValidator {
}
$totalSize += $fileStat['size'];
$fileName = \core_text::strtolower($fileStat['name']);
$fileName = mb_strtolower($fileStat['name']);
if (preg_match('/(^[\._]|\/[\._])/', $fileName) !== 0) {
continue; // Skip any file or folder starting with a . or _
}
@@ -3318,15 +3315,12 @@ class H5PCore {
$setup->disable_hub = TRUE;
}
// Moodle: the extension mbstring is optional.
/*
if (!extension_loaded('mbstring')) {
$setup->errors[] = $this->h5pF->t(
'The mbstring PHP extension is not loaded. H5P needs this to function properly'
);
$setup->disable_hub = TRUE;
}
*/
// Check php version >= 5.2
$php_version = explode('.', phpversion());
@@ -3674,13 +3668,12 @@ class H5PContentValidator {
// Check if string is within allowed length
if (isset($semantics->maxLength)) {
// Moodle: the extension mbstring is optional.
/*
if (!extension_loaded('mbstring')) {
$this->h5pF->setErrorMessage($this->h5pF->t('The mbstring PHP extension is not loaded. H5P need this to function properly'), 'mbstring-unsupported');
}
*/
$text = \core_text::substr($text, 0, $semantics->maxLength);
else {
$text = mb_substr($text, 0, $semantics->maxLength);
}
}
// Check if string is according to optional regexp in semantics
@@ -3730,14 +3723,11 @@ class H5PContentValidator {
// file name, 2. testing against a returned error array that could
// never be more than 1 element long anyway, 3. recreating the regex
// for every file.
// Moodle: the extension mbstring is optional.
/*
if (!extension_loaded('mbstring')) {
$this->h5pF->setErrorMessage($this->h5pF->t('The mbstring PHP extension is not loaded. H5P need this to function properly'), 'mbstring-unsupported');
$valid = FALSE;
}
*/
if (!preg_match($wl_regex, \core_text::strtolower($file))) {
else if (!preg_match($wl_regex, mb_strtolower($file))) {
$this->h5pF->setErrorMessage($this->h5pF->t('File "%filename" not allowed. Only files with the following extensions are allowed: %files-allowed.', array('%filename' => $file, '%files-allowed' => $whitelist)), 'not-in-whitelist');
$valid = FALSE;
}
@@ -4279,7 +4269,7 @@ class H5PContentValidator {
return '&lt;';
}
if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9\-]+)([^>]*)>?|(<!--.*?-->)$%', $string, $matches)) {
if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9\-]+)\s*([^>]*)>?|(<!--.*?-->)$%', $string, $matches)) {
// Seriously malformed.
return '';
}
@@ -4341,7 +4331,13 @@ class H5PContentValidator {
// Attribute name, href for instance.
if (preg_match('/^([-a-zA-Z]+)/', $attr, $match)) {
$attrName = strtolower($match[1]);
$skip = ($attrName == 'style' || substr($attrName, 0, 2) == 'on');
$skip = (
$attrName == 'style' ||
substr($attrName, 0, 2) == 'on' ||
substr($attrName, 0, 1) == '-' ||
// Ignore long attributes to avoid unnecessary processing overhead.
strlen($attrName) > 96
);
$working = $mode = 1;
$attr = preg_replace('/^[-a-zA-Z]+/', '', $attr);
}
+13 -3
View File
@@ -1030,7 +1030,7 @@ H5P.t = function (key, vars, ns) {
H5P.Dialog = function (name, title, content, $element) {
/** @alias H5P.Dialog# */
var self = this;
var $dialog = H5P.jQuery('<div class="h5p-popup-dialog h5p-' + name + '-dialog">\
var $dialog = H5P.jQuery('<div class="h5p-popup-dialog h5p-' + name + '-dialog" role="dialog" tabindex="-1">\
<div class="h5p-inner">\
<h2>' + title + '</h2>\
<div class="h5p-scroll-content">' + content + '</div>\
@@ -1053,6 +1053,12 @@ H5P.Dialog = function (name, title, content, $element) {
.click(function () {
self.close();
})
.keypress(function (e) {
if (e.which === 13 || e.which === 32) {
self.close();
return false;
}
})
.end()
.find('a')
.click(function (e) {
@@ -1072,6 +1078,7 @@ H5P.Dialog = function (name, title, content, $element) {
$dialog.addClass('h5p-open'); // Fade in
// Triggering an event, in case something has to be done after dialog has been opened.
H5P.jQuery(self).trigger('dialog-opened', [$dialog]);
$dialog.focus();
}, 1);
};
@@ -1083,6 +1090,8 @@ H5P.Dialog = function (name, title, content, $element) {
setTimeout(function () {
$dialog.remove();
H5P.jQuery(self).trigger('dialog-closed', [$dialog]);
$element.attr('tabindex', '-1');
$element.focus();
}, 200);
};
};
@@ -1363,11 +1372,11 @@ H5P.openEmbedDialog = function ($element, embedCode, resizeCode, size, instance)
var $expander = H5P.jQuery(this);
var $content = $expander.next();
if ($content.is(':visible')) {
$expander.removeClass('h5p-open').text(H5P.t('showAdvanced'));
$expander.removeClass('h5p-open').text(H5P.t('showAdvanced')).attr('aria-expanded', 'true');
$content.hide();
}
else {
$expander.addClass('h5p-open').text(H5P.t('hideAdvanced'));
$expander.addClass('h5p-open').text(H5P.t('hideAdvanced')).attr('aria-expanded', 'false');
$content.show();
}
$dialog.find('.h5p-embed-code-container').each(function () {
@@ -1378,6 +1387,7 @@ H5P.openEmbedDialog = function ($element, embedCode, resizeCode, size, instance)
$dialog.find('.h5p-expander').click(expand).keypress(function (event) {
if (event.keyCode === 32) {
expand.apply(this);
return false;
}
});
}).on('dialog-closed', function () {
+7 -20
View File
@@ -14,7 +14,7 @@ Removed:
Added:
* readme_moodle.txt
Downloaded version: 1.24 release
Downloaded version: 1.24.2 release
Changes:
1. In order to allow the dependency path to be overridden by child H5PCore classes, a couple of minor changes have been added to the
@@ -31,33 +31,21 @@ https://github.com/h5p/h5p-php-library/compare/master...andrewnicols:libraryPath
Hopefully, when upgrading, these patch won't be needed because it will be included in the H5P library by default.
2. As the mbstring extension is optional in Moodle, the following changes have been hardcoded to the library:
2.1. Comment the following methods in h5p.classes.php file where the extension_loaded('mbstring') is called:
* isValidPackage
* checkSetupErrorMessage
* validateText
* validateContentFiles
2. Replace the $_SESSION references to $SESSION. That implies that the information is saved to backends, so only the Moodle one
should be used by core (core should be free from $_SESSION and always use $SESSION).
2.2. Change all the mb_uses straight to the core_text() alternatives. Version 1.24 has 3 ocurrences in h5p.classes.php
and 1 ocurrence in h5p-metadata.class.php.
3. Another PR has been sent to H5P library (https://github.com/h5p/h5p-php-library/pull/69) to fix some php74 minor problems. The same fix is being applied locally by MDL-67077. Once we import a new version, if it includes de fix, this won't be needed to reapply and can be removed.
4. Replace the $_SESSION references to $SESSION. That implies that the information is saved to backends, so only the Moodle one should be used by core (core should be free from $_SESSION and always use $SESSION).
h5p.classes.php file:
- Into hashToken method:
Declare the global $SESSION.
Change all the $_SESSION by $SESSION.
A script for testing this part can be found in MDL-68068
The point 2 from above won't be needed once the mbstring extension becomes mandatory in Moodle. A request has been
sent to MDL-65809.
5. Upgrade and patch JQuery library.
3. Upgrade and patch JQuery library.
Once https://github.com/h5p/h5p-php-library/issues/83 gets integrated in
H5P PHP Library (upgrading the JQuery version), this change won't be needed.
5.1. Prepare the patched JQuery 1.12.4 library following these steps:
3.1. Prepare the patched JQuery 1.12.4 library following these steps:
a) Download the uncompressed JQuery Core 1.12.4 from https://code.jquery.com/jquery-1.12.4.js
b) Add the patch in https://snyk.io/vuln/SNYK-JS-JQUERY-174006 to the downloaded file.
You'll need to replace this code (line 212):
@@ -75,15 +63,14 @@ H5P PHP Library (upgrading the JQuery version), this change won't be needed.
}
c) Minify the patched jquery-1-12.4.js.
5.2. Edit h5p/h5plib/v124/joubel/core/js/jquery.js and replace the JQuery piece of code
3.2. Edit h5p/h5plib/v124/joubel/core/js/jquery.js and replace the JQuery piece of code
(at the beginning of the file, above the comment "// Snap this specific version of jQuery into H5P. jQuery.noConflict will")
with the previous patched and minified JQuery version.
5.3. Remove the following comment in h5p/h5plib/v124/joubel/core/js/jquery.js:
3.3. Remove the following comment in h5p/h5plib/v124/joubel/core/js/jquery.js:
/**
* jQuery v1.9.1
*
* @member
*/
+26 -8
View File
@@ -202,7 +202,7 @@ div.h5p-fullscreen {
color: #999;
text-decoration: none;
outline: none;
line-height: 23px;
line-height: 22px;
}
.h5p-actions > .h5p-button:hover {
color: #666;
@@ -223,8 +223,8 @@ div.h5p-fullscreen {
.h5p-actions > .h5p-button:before {
font-family: 'H5P';
font-size: 20px;
line-height: 20px;
vertical-align: top;
line-height: 23px;
vertical-align: bottom;
padding-right: 0;
}
.h5p-actions > .h5p-button.h5p-export:before {
@@ -367,10 +367,6 @@ div.h5p-fullscreen {
}
.h5p-popup-dialog .h5p-close {
cursor: pointer;
}
.h5p-popup-dialog .h5p-close:after {
font-family: 'H5P';
content: "\e894";
font-size: 2em;
position: absolute;
right: 0;
@@ -383,6 +379,10 @@ div.h5p-fullscreen {
text-indent: -0.065em;
z-index: 3
}
.h5p-popup-dialog .h5p-close:after {
font-family: 'H5P';
content: "\e894";
}
.h5p-popup-dialog .h5p-close:hover:after,
.h5p-popup-dialog .h5p-close:focus:after {
color: #454545;
@@ -412,7 +412,6 @@ div.h5p-fullscreen {
.h5p-expander {
cursor: pointer;
font-size: 1.125em;
outline: none;
margin: 0.5em 0 0;
display: inline-block;
}
@@ -543,6 +542,25 @@ div.h5p-fullscreen {
opacity: 0;
visibility: hidden;
}
.h5p-content code,
.h5peditor code {
color: #3d3d3d;
background: #e0e0e0;
border-radius: 2px;
padding: 0 5px;
}
.h5p-content pre > code,
.h5peditor pre > code {
background-color: #fafafa;
padding: 5px;
display: block;
line-height: normal;
border: 1px solid #c7c7c7;
border-left-width: 4px;
max-width: 100%;
white-space: pre;
overflow: auto;
}
/* This is loaded as part of Core and not Editor since this needs to be outside the editor iframe */
+1 -1
View File
@@ -4,7 +4,7 @@
<location>joubel/core</location>
<name>h5p-php-library</name>
<license>GPL-3.0</license>
<version>1.24</version>
<version>1.24.2</version>
</library>
<library>
<location>joubel/editor</location>
+46 -1
View File
@@ -36,7 +36,7 @@ use advanced_testcase;
* @copyright 2019 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class helper_testcase extends \advanced_testcase {
class helper_test extends \advanced_testcase {
/**
* Test the behaviour of get_display_options().
@@ -379,4 +379,49 @@ class helper_testcase extends \advanced_testcase {
$helperfile = helper::get_export_info('nofileexist.h5p', $url);
$this->assertNull($helperfile);
}
/**
* Test the parse_js_array function with a range of content.
*
* @dataProvider parse_js_array_provider
* @param string $content
* @param array $expected
*/
public function test_parse_js_array(string $content, array $expected): void {
$this->assertEquals($expected, helper::parse_js_array($content));
}
/**
* Data provider for test_parse_js_array().
*
* @return array
*/
public function parse_js_array_provider(): array {
$lines = [
"{",
" missingTranslation: '[Missing translation :key]',",
" loading: 'Loading, please wait...',",
" selectLibrary: 'Select the library you wish to use for your content.',",
"}",
];
$expected = [
'missingTranslation' => '[Missing translation :key]',
'loading' => 'Loading, please wait...',
'selectLibrary' => 'Select the library you wish to use for your content.',
];
return [
'Strings with \n' => [
implode("\n", $lines),
$expected,
],
'Strings with \r\n' => [
implode("\r\n", $lines),
$expected,
],
'Strings with \r' => [
implode("\r", $lines),
$expected,
],
];
}
}
+3
View File
@@ -1,6 +1,9 @@
This files describes API changes in core libraries and APIs,
information provided here is intended especially for developers.
=== 3.10.4 ===
* The third-party library h5p/h5plib/v124/core has been updated to version 1.24.2.
=== 3.10 ===
* Added a new cache for h5p_library_files (MDL-69207)
+33
View File
@@ -0,0 +1,33 @@
<?php
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* Automatically generated strings for Moodle installer
*
* Do not edit this file manually! It contains just a subset of strings
* needed during the very first steps of installation. This file was
* generated automatically by export-installer.php (which is part of AMOS
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
* list of strings defined in /install/stringnames.txt.
*
* @package installer
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$string['parentlanguage'] = 'da';
$string['thislanguage'] = 'Dansk til Workplace';
+9
View File
@@ -31,4 +31,13 @@ defined('MOODLE_INTERNAL') || die();
$string['clianswerno'] = 'n';
$string['cliansweryes'] = 'w';
$string['cliincorrectvalueerror'] = 'Erè, valè kòrèk "{$ a-> valè}" pou "{$ a-> opsyon}"';
$string['cliincorrectvalueretry'] = 'Valè ki pa kòrèk, tanpri eseye ankò';
$string['clitypevalue'] = 'valè kalite';
$string['clitypevaluedefault'] = 'tape valè, peze Antre pou itilize valè default ({$ a})';
$string['cliunknowoption'] = 'Opsyon ki pa rekonèt:
{$ a}
Tanpri itilize opsyon --help.';
$string['cliyesnoprompt'] = 'Tape w (pou wi) oswa n (pou non)';
$string['environmentrequireinstall'] = 'dwe enstale ak pèmèt';
$string['environmentrequireversion'] = 'vèsyon {$ a-> bezwen} obligatwa epi w ap kouri {$ a-> current}';
+1 -1
View File
@@ -29,6 +29,6 @@
defined('MOODLE_INTERNAL') || die();
$string['parentlanguage'] = 'he';
$string['parentlanguage'] = '';
$string['thisdirection'] = 'rtl';
$string['thislanguage'] = 'עברית';
+49
View File
@@ -0,0 +1,49 @@
<?php
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* Automatically generated strings for Moodle installer
*
* Do not edit this file manually! It contains just a subset of strings
* needed during the very first steps of installation. This file was
* generated automatically by export-installer.php (which is part of AMOS
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
* list of strings defined in /install/stringnames.txt.
*
* @package installer
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$string['cannotcreatedboninstall'] = '<p> Tidak dapat membuat basis data. </p> <p> Basis data yang ditentukan tidak ada dan pengguna yang diberikan tidak memiliki izin untuk membuat basis data. </p> <p> Administrator situs harus memverifikasi konfigurasi basis data. < / p>';
$string['cannotcreatelangdir'] = 'Tidak dapat membuat direktori lang';
$string['cannotcreatetempdir'] = 'Tidak dapat membuat direktori temp';
$string['cannotdownloadcomponents'] = 'Tidak dapat mengunduh komponen';
$string['cannotdownloadzipfile'] = 'Tidak dapat mengunduh berkas ZIP';
$string['cannotfindcomponent'] = 'Tidak dapat menemukan komponen';
$string['cannotsavemd5file'] = 'Tidak dapat menyimpan berkas md5';
$string['cannotsavezipfile'] = 'Tidak dapat menyimpan berkas ZIP';
$string['cannotunzipfile'] = 'Tidak dapat mengekstrak berkas';
$string['componentisuptodate'] = 'Komponen sudah mutakhir';
$string['dmlexceptiononinstall'] = '<p>Terjadi kesalahan basis data [{$a->errorcode}].<br />{$a->debuginfo}</p>';
$string['downloadedfilecheckfailed'] = 'Pemeriksaan berkas yang diunduh gagal';
$string['invalidmd5'] = 'Variabel periksa salah - coba lagi';
$string['missingrequiredfield'] = 'Beberapa ruas wajib tidak ada';
$string['remotedownloaderror'] = '<p> Pengunduhan komponen ke peladen Anda gagal. Harap verifikasi setelan proksi; ekstensi PHP cURL sangat direkomendasikan. </p> <p> Anda harus mengunduh berkas <a href="{$a->url} ">{$a->url} </a> secara manual, menyalinnya ke"{$a->dest} "di peladen Anda dan uraikan di sana. </p>';
$string['wrongdestpath'] = 'Jalur tujuan salah';
$string['wrongsourcebase'] = 'Basis URL sumber salah';
$string['wrongzipfilename'] = 'Nama file ZIP salah';
+4 -4
View File
@@ -70,12 +70,12 @@ $string['pathsroparentdataroot'] = 'La cartella genitore ({$a->parent}) non è s
$string['pathssubadmindir'] = 'Alcuni web host utilizzano la cartella /admin come URL di accesso a pannelli di controllo od altre funzioni particolari. Tuttavia questo nome coincide con il nome della cartella che Moodle utilizza per i propri file di amministrazione. Per evitare conflitti, è possibile specificare un nome alternativo per la cartella Admin di Moodle. Ad esempio:<p><b>moodleadmin</b></p>
Tutti i link che puntano ai file di amministrazione di Moodle terranno conto di questa variazione.';
$string['pathssubdataroot'] = '<p>La cartella dove Moodle memorizzerà i file caricati dagli utenti.</p>
<p>L\'utente con il qule gira il processo del web server (in genere \'www-data\' o \'apache\') deve avere i permessi di lettura e di scrittura su questa cartella.</p>
<p>L\'utente con il quale gira il processo del web server (in genere \'www-data\' o \'apache\') deve avere i permessi di lettura e di scrittura su questa cartella.</p>
<p>La cartella inoltre non deve essere direttamente accessibile via web.</p>
<p>Qualora la cartella non esista, lo script di installazione tenterà di crearla.</p>';
$string['pathssubdirroot'] = '<p>Percorso assoluto della cartella dove si trova il codice di Moodle.</p>';
$string['pathssubwwwroot'] = '<p>L\'iIndirizzo web per raggiungere a Moodle, in altre parole l\'indirizzo che gli utenti inseriranno nella barra degli indirizzi del proprio browser per accedere a questa installazione.</p>
<p>Non è possibile accedere alla stessa installazione Moodle usando più di un indirizzi web. Se il tuo sito usa più indirizzi web, devi configurare dei re-indirizzamenti permanenti per tutti gli altri indirizzi web.</p>
$string['pathssubwwwroot'] = '<p>L\'indirizzo web per raggiungere a Moodle, in altre parole l\'indirizzo che gli utenti inseriranno nella barra degli indirizzi del proprio browser per accedere a questa installazione.</p>
<p>Non è possibile accedere alla stessa installazione Moodle usando più di un indirizzo web. Se il tuo sito usa più indirizzi web, devi configurare dei re-indirizzamenti permanenti per tutti gli altri indirizzi web.</p>
<p>Se il tuo sito è raggiungibile sia dalla Internet sia dalla rete interna (a volte chiamata Intranet), allora usa l\'indirizzo Internet pubblico.</p>
<p>Se l\'indirizzo utilizzato è errato, per favore correggilo nella barra degli indirizzi del browser e avvia nuovamente l\'installazione.</p>';
$string['pathsunsecuredataroot'] = 'La posizione della Cartella dati non è sicura';
@@ -89,7 +89,7 @@ $string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
$string['welcomep20'] = 'Se vedi questa pagina hai installato correttamente e lanciato il pacchetto <strong>{$a->packname} {$a->packversion}</strong>. Complimenti!';
$string['welcomep30'] = 'La release di <strong>{$a->installername}</strong> include l\'applicazione per creare l\'ambiente necessario a far girare <strong>Moodle</strong>:';
$string['welcomep40'] = 'Il pacchetto include anche <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
$string['welcomep50'] = 'L\'utilizzo delle applicazioni incluse in questo pacchetto è regolato dalle rispettive licenze. L\'intero pacchetto <strong>{$a->installername}</strong> è <a href="http://www.opensource.org/docs/definition_plain.html">open source</a> ed è distribuito in accordo alla licenza <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>.';
$string['welcomep50'] = 'L\'utilizzo delle applicazioni incluse in questo pacchetto è regolato dalle rispettive licenze. L\'intero pacchetto <strong>{$a->installername}</strong> è <a href="https://www.opensource.org/docs/definition_plain.html">open source</a> ed è distribuito in accordo alla licenza <a href="https://www.gnu.org/copyleft/gpl.html">GPL</a>.';
$string['welcomep60'] = 'Le prossime pagine ti guideranno attraverso semplici passi per installare e configurare <strong>Moodle</strong> nel tuo computer. Puoi utilizzare le impostazioni di default oppure modificarle per adeguarle alle tue esigenze.';
$string['welcomep70'] = 'Fai click sul pulsante "Avanti" per continuare l\'installazione di <strong>Moodle</strong>.';
$string['wwwroot'] = 'Indirizzo web';
+7 -1
View File
@@ -45,7 +45,7 @@ $string['dbprefix'] = 'Префикс на табели';
$string['dirroot'] = 'Moodle директориум';
$string['environmenthead'] = 'Ја проверувам околината...';
$string['installation'] = 'Инсталација';
$string['langdownloaderror'] = 'За жал, јазикот "{$a}" не беше инсталиран. Инсталацискиот процес ќе продолжи на англиски.';
$string['langdownloaderror'] = 'За жал, јазикот "{$a}" не е преземен. Инсталацискиот процес ќе продолжи на англиски.';
$string['memorylimithelp'] = '<p>Прагот на меморијата кај PHP за Вашиот компјутер моментално е подесена на {$a}. </p>
<p>Ова може да предизвика проблеми со меморијата подоцна,
@@ -64,6 +64,12 @@ $string['memorylimithelp'] = '<p>Прагот на меморијата кај P
<p><blockquote>php_value memory_limit 40M</blockquote></p>
<p>Како и да е, на некои компјутери, ова може да ги спречи <b>сите </b> PHP страници да работат (ќе забележите грешки на страниците) па ќе треба да ја преместите датотеката .htaccess.</p></li>
</ol>';
$string['paths'] = 'Патеки';
$string['pathshead'] = 'Потврди патеки';
$string['pathsroparentdataroot'] = 'Неможе да се запишува во предходниот директориум ({$a->parent}). Процесот на инсталација неможе да го создаде директориумот ({$a->dataroot}).';
$string['pathssubdataroot'] = '<p>Директориум каде што Moodle ќе ја зачува целата содржина на датотеки прикачена од корисниците.</p> <p>Овој директориум треба да биде има дозвола за читање и запишување од веб-серверот (најлесто \'www-data\', \'nobody\', или \'apache\').</p> <p>Не смее да биде директно достапен преку Интернет.</p> <p>Ако директориумот во моментов не постои, процесот на инсталација ќе се обиде да го создаде.</p>';
$string['pathssubdirroot'] = '<p>Целосна патека до директориумот каде што е кодот на Moodle.</p>';
$string['pathssubwwwroot'] = '<p>Целосната адреса каде што ќе се пристапува до Moodle, т.е. адресата што корисниците треба да ја внесат во лентата за адреси на нивниот прелистувач за пристап до Moodle.</p> <p>Не е можно да се пристапи до Moodle со користење на повеќе адреси. Ако вашата страница е достапна преку повеќе адреси, тогаш изберете ја најлесната и поставете трајно пренасочување за секоја од другите адреси.</p> <p>Ако вашата страница е достапна и од Интернет, и од внатрешна мрежа (понекогаш наречена Интранет), тогаш користете ја јавната адреса тука.</p> <p>Ако тековната адреса не е точна, променете ја URL-адресата во лентата за адреси на прелистувачот и повторно стартувајте ја инсталацијата.</p>';
$string['pathswrongadmindir'] = 'Администраторскиот директориум не постои';
$string['phpversion'] = 'Верзија на PHP';
$string['phpversionhelp'] = '<p>На Moodle му е потребна верзија на PHP, и тоа најмалку 4.1.0. </p>
+1
View File
@@ -29,5 +29,6 @@
defined('MOODLE_INTERNAL') || die();
$string['parentlanguage'] = 'en';
$string['thisdirection'] = 'ltr';
$string['thislanguage'] = 'Македонски';
+5 -5
View File
@@ -40,7 +40,7 @@ $string['databasehost'] = 'Servidor da base de dados';
$string['databasename'] = 'Nome da base de dados';
$string['databasetypehead'] = 'Escolha o <i>driver</i> da base de dados';
$string['dataroot'] = 'Pasta de dados';
$string['datarootpermission'] = 'Permissões da diretoria de dados';
$string['datarootpermission'] = 'Permissões da pasta de dados';
$string['dbprefix'] = 'Prefixo das tabelas';
$string['dirroot'] = 'Pasta do Moodle';
$string['environmenthead'] = 'A verificar sistema...';
@@ -55,11 +55,11 @@ $string['pathshead'] = 'Confirmar caminhos';
$string['pathsrodataroot'] = 'A pasta de dados não tem permissões de escrita.';
$string['pathsroparentdataroot'] = 'A pasta ascendente <b>{$a->parent}</b> não tem permissões de escrita. O programa de instalação não conseguiu criar a pasta <b>{$a->dataroot}</b>.';
$string['pathssubadmindir'] = 'Alguns servidores Web utilizam a pasta <strong>admin</strong> em URLs especiais de acesso a funcionalidades especiais, como é o caso de painéis de controlo. Algumas situações podem criar conflitos com a localização normal das páginas de administração do Moodle. Estes problemas podem ser resolvidos renomeando a pasta <strong>admin</strong> na instalação do Moodle e indicando aqui o novo nome a utilizar. Por exemplo:<br /><br /><b>moodleadmin</b><br /><br />Esta ação resolverá os problemas de acesso das hiperligações para as funcionalidades de administração do Moodle.';
$string['pathssubdataroot'] = '<p>Diretoria onde o Moodle irá armazenar todo o conteúdo de ficheiros enviados pelos utilizadores.</p>
<p>Esta diretoria deve ser legível e gravável pelo utilizador do servidor web (geralmente \'www-data\', \'nobody\', ou \'apache\').</p>
$string['pathssubdataroot'] = '<p>Pasta onde o Moodle irá armazenar todo o conteúdo de ficheiros enviados pelos utilizadores.</p>
<p>Esta pasta deve ser legível e gravável pelo utilizador do servidor web (geralmente \'www-data\', \'nobody\', ou \'apache\').</p>
<p>Não deve ser acessível diretamente através da web.</p>
<p>Se a diretoria não existir, o processo de instalação tentará criá-la.</p>';
$string['pathssubdirroot'] = 'Caminho completo para a diretoria que contém o código Moodle.';
<p>Se a pasta não existir, o processo de instalação tentará criá-la.</p>';
$string['pathssubdirroot'] = 'Caminho completo para a pasta que contém o código Moodle.';
$string['pathssubwwwroot'] = 'Endereço web completo de acesso ao Moodle. Não é possível aceder ao Moodle usando mais do que um endereço. Se o site tiver mais do que um endereço público, devem ser configurados redirecionamentos permanentes em todos eles, à exceção deste. Se o site pode ser acedido a partir da Internet e de Intranet, use o endereço público aqui. Se o endereço atual não está correto, altere o endereço indicado na barra de endereço do seu navegador e reinicie a instalação.';
$string['pathsunsecuredataroot'] = 'A localização da pasta de dados não é segura';
$string['pathswrongadmindir'] = 'A pasta <b>admin</b> não existe';
+1 -1
View File
@@ -75,7 +75,7 @@ $string['pathssubwwwroot'] = '<p>Пуна адреса путем које ће
<p>Није могуће приступати Moodleu коришћењем више адреса. Ако се вашем сајту може приступити са више адреса, онда изаберите најлакшу, а за све остале адресе подесите перманентну редирекцију.</p>
<p>Ако се вашем сајту може приступити како са интернета, тако и из интерне мреже (која се понекад назив интранет), онда овде употребите јавну адресу.</p>
<p>Ако је текућа адреса нетачна, молимо вас, промените URL адресу у адресној траци свог веб читача и поново покрените инсталацију.</p>';
$string['pathsunsecuredataroot'] = 'Dataroot локација није безбедна';
$string['pathsunsecuredataroot'] = 'Локација директоријума са подацима није безбедна';
$string['pathswrongadmindir'] = 'Админ директоријум не постоји';
$string['phpextension'] = '{$a} PHP екстензија';
$string['phpversion'] = 'PHP верзија';
+1 -1
View File
@@ -72,7 +72,7 @@ $string['pathssubdataroot'] = '<p>Direktorijum gde će Moodle čuvati datoteke i
<p>Ukoliko ovaj direktorijum ne postoji proces instalacije će pokušati da ga kreira.</p>';
$string['pathssubdirroot'] = '<p>Puna putanja do direktorijuma koji sadrži kôd Moodlea.</p>';
$string['pathssubwwwroot'] = '<p>Puna adresa putem koje će se pristupati Moodleu, tj. adresa koju će korisnici uneti u adresnu traku svojih veb čitača kako bi pristupili Moodleu.</p> <p>Nije moguće pristupati Moodleu korišćenjem više adresa. Ako se vašem sajtu može pristupiti sa više adresa, onda izaberite najlakšu, a za sve ostale adrese podesite permanentnu redirekciju.</p> <p>Ako se vašem sajtu može pristupiti kako sa interneta, tako i iz interne mreže (koja se ponekad naziv intranet), onda ovde upotrebite javnu adresu.</p> <p>Ako je tekuća adresa netačna, molimo vas, promenite URL adresu u adresnoj traci svog veb čitača i ponovo pokrenite instalaciju.</p>';
$string['pathsunsecuredataroot'] = 'Dataroot lokacija nije bezbedna';
$string['pathsunsecuredataroot'] = 'Lokacija direktorijuma sa podacima nije bezbedna';
$string['pathswrongadmindir'] = 'Admin direktorijum ne postoji';
$string['phpextension'] = '{$a} PHP ekstenѕija';
$string['phpversion'] = 'PHP verzija';
+4 -4
View File
@@ -37,9 +37,9 @@ $string['cannotcreatetempdir'] = 'Det går inte att skapa temp-katalogen';
$string['cannotdownloadcomponents'] = 'Kan inte ladda ned komponenter';
$string['cannotdownloadzipfile'] = 'Kan inte ladda ned ZIP-fil';
$string['cannotfindcomponent'] = 'Hittar inte komponenten';
$string['cannotsavemd5file'] = 'Det går inte att spara md5-fil';
$string['cannotsavezipfile'] = 'Det går inte att spara ZIP-fil';
$string['cannotunzipfile'] = 'Det går inte att packa upp fil';
$string['cannotsavemd5file'] = 'Kan inte spara md5-fil';
$string['cannotsavezipfile'] = 'Kan inte spara ZIP-fil';
$string['cannotunzipfile'] = 'Det går inte att packa upp filen';
$string['componentisuptodate'] = 'Komponenten är aktuell';
$string['dmlexceptiononinstall'] = '<p>Ett databasfel har inträffat [{$a->errorcode}].<br />{$a->debuginfo}</p>';
$string['downloadedfilecheckfailed'] = 'Kontrollen av den nedladdade filen misslyckades';
@@ -47,5 +47,5 @@ $string['invalidmd5'] = 'Kontrollvariabeln var felaktig - försök igen';
$string['missingrequiredfield'] = 'Det saknas några obligatoriska fält';
$string['remotedownloaderror'] = 'Nedladdningen av en komponent till din server misslyckades. Vänligen verifiera inställningar för proxy. <br /><br />Du måste ladda ner <a href="{$a->url}">{$a->url}</a> filen manuellt, kopiera den till "{$a->dest}" på din server och packa upp den där.';
$string['wrongdestpath'] = 'Fel målsökväg';
$string['wrongsourcebase'] = 'Fel bas-URL till källan';
$string['wrongsourcebase'] = 'Felaktig käll- URL rot';
$string['wrongzipfilename'] = 'Fel namn på ZIP-filen';
+1
View File
@@ -29,5 +29,6 @@
defined('MOODLE_INTERNAL') || die();
$string['parentlanguage'] = '';
$string['thisdirection'] = 'ltr';
$string['thislanguage'] = 'Svenska';
+1
View File
@@ -30,6 +30,7 @@
defined('MOODLE_INTERNAL') || die();
$string['language'] = 'Ngôn ngữ';
$string['moodlelogo'] = 'Logo Moodle';
$string['next'] = 'Tiếp theo';
$string['previous'] = 'Trước';
$string['reload'] = 'Nạp lại';
+8 -5
View File
@@ -302,8 +302,8 @@ $string['configmycoursesperpage'] = 'Maximum number of courses to display in any
$string['configmymoodleredirect'] = 'This setting forces redirects to /my on login for non-admins and replaces the top level site navigation with /my';
$string['configmypagelocked'] = 'This setting prevents the default page from being edited by any non-admins';
$string['confignavcourselimit'] = 'Limits the number of courses shown to the user in the navigation.';
$string['confignavshowallcourses'] = 'This setting determines whether users who are enrolled in courses can see Courses (listing all courses) in the navigation, in addition to My Courses (listing courses in which they are enrolled).';
$string['confignavshowcategories'] = 'Show course categories in the navigation bar and navigation blocks. This does not occur with courses the user is currently enrolled in, they will still be listed under mycourses without categories.';
$string['confignavshowallcourses'] = 'This setting determines whether users who are enrolled in courses can see Courses (listing all courses) in the navigation, in addition to My courses (listing courses in which they are enrolled).';
$string['confignavshowcategories'] = 'Show course categories in the navigation bar and navigation blocks. This does not occur with courses the user is currently enrolled in; they will still be listed under My courses without categories.';
$string['confignoreplyaddress'] = 'Emails are sometimes sent out on behalf of a user (eg forum posts). The email address you specify here will be used as the "From" address in those cases when the recipients should not be able to reply directly to the user (eg when a user chooses to keep their address private). This setting will also be used as the envelope sender when sending email.';
$string['confignotifyloginfailures'] = 'Send login failure notification messages to these selected users. This requires an internal logstore (eg Standard Logstore) to be enabled.';
$string['confignotifyloginthreshold'] = 'If notifications about failed logins are active, how many failed login attempts by one user or one IP address is it worth notifying about?';
@@ -383,7 +383,7 @@ For example: standard,orangewhite.';
$string['configtimezone'] = 'This is the default timezone for displaying dates - each user can override this setting in their profile. Cron tasks and other server settings are specified in this timezone. You should change the setting if it shows as "Invalid timezone"';
$string['configuseblogassociations'] = 'Should users be able to organize their blog by associating entries with courses and course modules?';
$string['configuseexternalyui'] = 'Instead of using local files, use online files available on Yahoo&#145;s servers. WARNING: This requires an internet connection, or no AJAX will work on your site. This setting is not compatible with sites using https.';
$string['configusesitenameforsitepages'] = 'If enabled the site\'s shortname will be used for the site pages node in the navigation rather than the string \'Site pages\'';
$string['configusesitenameforsitepages'] = 'If enabled the site\'s short name will be used for the site pages node in the navigation rather than the string \'Site pages\'.';
$string['configusetags'] = 'Should tags functionality across the site be enabled?';
$string['configvariables'] = 'Variables';
$string['configverifychangedemail'] = 'Enables verification of changed email addresses using allowed and denied email domains settings. If this setting is disabled the domains are enforced only when creating new users.';
@@ -871,7 +871,7 @@ $string['navshowfrontpagemods_help'] = 'If enabled, front page activities will b
$string['navshowallcourses'] = 'Show all courses';
$string['navshowcategories'] = 'Show course categories';
$string['navshowmycoursecategories'] = 'Show my course categories';
$string['navshowmycoursecategories_help'] = 'If enabled courses in the users my courses branch will be shown in categories.';
$string['navshowmycoursecategories_help'] = 'If enabled, courses in the user\'s My courses branch will be shown in categories in the navigation block (Classic-based themes only).';
$string['navsortmycourseshiddenlast'] = 'Sort my hidden courses last';
$string['navsortmycourseshiddenlast_help'] = 'If enabled, any hidden courses will be listed after visible courses (for users who can view hidden courses). Otherwise, all courses, regardless of their visibility, will be listed according to the \'Sort my courses\' setting.';
$string['navsortmycoursessort'] = 'Sort my courses';
@@ -1023,7 +1023,8 @@ $string['profilesignup'] = 'Display on signup page?';
$string['profilespecificsettings'] = 'Specific settings';
$string['profilevisible'] = 'Who is this field visible to?';
$string['profilevisible_help'] = '* Not visible - For private data only viewable by administrators
* Visible to user - For private data only viewable by the user and by administrators
* Visible to user - For private data only viewable by the user and administrators
* Visible to user, teachers and admins - For private data only viewable by the user, administrators and teachers (on course profile)
* Visible to everyone';
$string['profilevisibleall'] = 'Visible to everyone';
$string['profilevisiblenone'] = 'Not visible';
@@ -1191,6 +1192,8 @@ $string['sessionhandling'] = 'Session handling';
$string['sessiontimeout'] = 'Timeout';
$string['settingdependenton'] = 'This setting may be hidden, based on the value of <strong>{$a}</strong>.';
$string['settingfileuploads'] = 'File uploading is required for normal operation, please enable it in PHP configuration.';
$string['settingmaxinputvars'] = 'PHP setting max_input_vars is recommended to be at least 5000.';
$string['settingmaxinputvarsrequired'] = 'PHP setting max_input_vars must be at least 5000.';
$string['settingmemorylimit'] = 'Insufficient memory detected, please set higher memory limit in PHP settings.';
$string['settingsafemode'] = 'Moodle is not fully compatible with safe mode, please ask server administrator to turn it off. Running Moodle under safe mode is not supported, please expect various problems if you do so.';
$string['setupsearchengine'] = 'Setup search engine';
+2
View File
@@ -391,6 +391,7 @@ $string['loginasnoenrol'] = 'You cannot use enrol or unenrol when in course "Log
$string['loginasonecourse'] = 'You cannot enter this course.<br /> You have to terminate the "Login as" session before entering any other course.';
$string['maxbytesfile'] = 'The file {$a->file} is too large. The maximum size you can upload is {$a->size}.';
$string['maxareabytes'] = 'The file is larger than the space remaining in this area.';
$string['maxdraftitemids'] = 'Due to uploading a high volume of files, your file uploads are temporarily limited. Please try again after a few seconds.';
$string['messageundeliveredbynotificationsettings'] = 'The message could not be sent because personal messages between users (in Notification settings) has been disabled by a site administrator.';
$string['messagingdisable'] = 'Messaging is disabled on this site';
$string['mimetexisnotexist'] = 'Your system is not configured to run mimeTeX. You need to obtain the C source from <a href="https://www.forkosh.com/mimetex.zip">https://www.forkosh.com/mimetex.zip</a>, compile it and put the executable into your moodle/filter/tex/ directory.';
@@ -468,6 +469,7 @@ $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['oauth2refreshtokenerror'] = 'Could not refresh OAuth 2 token. HTTP status for remote endpoint: {$a}';
$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
View File
@@ -95,3 +95,4 @@ $string['templatetypeown'] = 'Own form';
$string['templatetypeshared'] = 'Shared template';
$string['templatesource'] = 'Location: {$a->component} ({$a->area})';
$string['error:notinrange'] = 'Invalid grade \'{$a->grade}\' provided. Grades must be between 0 and {$a->maxgrade}.';
$string['error:gradingunavailable'] = 'The advanced grading method is not correctly set. Please check the whole forum grading options in the forum settings.';
+1 -1
View File
@@ -120,7 +120,7 @@ $string['roleassignmentsnumber'] = 'Number of role assignments ({$a})';
$string['search'] = 'Search';
$string['sendingsize'] = 'Please wait the course file is uploading ({$a->total}Mb)...';
$string['sendfollowinginfo'] = 'More information';
$string['sendfollowinginfo_help'] = 'The following information will be sent to contribute to overall statistics only. It will not be made public on any site listing.';
$string['sendfollowinginfo_help'] = 'The following information will be sent to Moodle each time your site registration is updated (by default weekly, when the \'Site registration\' scheduled task is run). The information contributes to overall statistics only and will not be made public on any site listing.';
$string['sent'] = '...finished';
$string['siteadmin'] = 'Administrator';
$string['siteadmin_help'] = 'The full name of the site administrator.';
+1 -1
View File
@@ -1472,7 +1472,7 @@ $string['normalfilter'] = 'Normal search';
$string['nosite'] = 'Could not find site-level course';
$string['nostudentsfound'] = 'No {$a} found';
$string['nostudentsingroup'] = 'There are no students in this group yet';
$string['nostudentsyet'] = 'No students enrolled in this course yet';
$string['nostudentsyet'] = 'There are no students enrolled in this course.';
$string['nosuchemail'] = 'No such email address';
$string['notavailable'] = 'Not available';
$string['notavailablecourse'] = '{$a} is not available';
+36 -11
View File
@@ -5525,9 +5525,11 @@ abstract class context extends stdClass implements IteratorAggregate {
* type of context, e.g. User, Course, Forum, etc.
* @param boolean $short whether to use the short name of the thing. Only applies
* to course contexts
* @param boolean $escape Whether the returned name of the thing is to be
* HTML escaped or not.
* @return string the human readable context name.
*/
public function get_context_name($withprefix = true, $short = false) {
public function get_context_name($withprefix = true, $short = false, $escape = true) {
// must be implemented in all context levels
throw new coding_exception('can not get name of abstract context');
}
@@ -6229,9 +6231,10 @@ class context_system extends context {
*
* @param boolean $withprefix does not apply to system context
* @param boolean $short does not apply to system context
* @param boolean $escape does not apply to system context
* @return string the human readable context name.
*/
public function get_context_name($withprefix = true, $short = false) {
public function get_context_name($withprefix = true, $short = false, $escape = true) {
return self::get_level_name();
}
@@ -6488,9 +6491,10 @@ class context_user extends context {
*
* @param boolean $withprefix whether to prefix the name of the context with User
* @param boolean $short does not apply to user context
* @param boolean $escape does not apply to user context
* @return string the human readable context name.
*/
public function get_context_name($withprefix = true, $short = false) {
public function get_context_name($withprefix = true, $short = false, $escape = true) {
global $DB;
$name = '';
@@ -6675,9 +6679,10 @@ class context_coursecat extends context {
*
* @param boolean $withprefix whether to prefix the name of the context with Category
* @param boolean $short does not apply to course categories
* @param boolean $escape Whether the returned name of the context is to be HTML escaped or not.
* @return string the human readable context name.
*/
public function get_context_name($withprefix = true, $short = false) {
public function get_context_name($withprefix = true, $short = false, $escape = true) {
global $DB;
$name = '';
@@ -6685,7 +6690,11 @@ class context_coursecat extends context {
if ($withprefix){
$name = get_string('category').': ';
}
$name .= format_string($category->name, true, array('context' => $this));
if (!$escape) {
$name .= format_string($category->name, true, array('context' => $this, 'escape' => false));
} else {
$name .= format_string($category->name, true, array('context' => $this));
}
}
return $name;
}
@@ -6907,9 +6916,10 @@ class context_course extends context {
*
* @param boolean $withprefix whether to prefix the name of the context with Course
* @param boolean $short whether to use the short name of the thing.
* @param bool $escape Whether the returned category name is to be HTML escaped or not.
* @return string the human readable context name.
*/
public function get_context_name($withprefix = true, $short = false) {
public function get_context_name($withprefix = true, $short = false, $escape = true) {
global $DB;
$name = '';
@@ -6921,9 +6931,18 @@ class context_course extends context {
$name = get_string('course').': ';
}
if ($short){
$name .= format_string($course->shortname, true, array('context' => $this));
if (!$escape) {
$name .= format_string($course->shortname, true, array('context' => $this, 'escape' => false));
} else {
$name .= format_string($course->shortname, true, array('context' => $this));
}
} else {
$name .= format_string(get_course_display_name_for_list($course));
if (!$escape) {
$name .= format_string(get_course_display_name_for_list($course), true, array('context' => $this,
'escape' => false));
} else {
$name .= format_string(get_course_display_name_for_list($course), true, array('context' => $this));
}
}
}
}
@@ -7130,9 +7149,10 @@ class context_module extends context {
* @param boolean $withprefix whether to prefix the name of the context with the
* module name, e.g. Forum, Glossary, etc.
* @param boolean $short does not apply to module context
* @param boolean $escape Whether the returned name of the context is to be HTML escaped or not.
* @return string the human readable context name.
*/
public function get_context_name($withprefix = true, $short = false) {
public function get_context_name($withprefix = true, $short = false, $escape = true) {
global $DB;
$name = '';
@@ -7144,7 +7164,11 @@ class context_module extends context {
if ($withprefix){
$name = get_string('modulename', $cm->modname).': ';
}
$name .= format_string($mod->name, true, array('context' => $this));
if (!$escape) {
$name .= format_string($mod->name, true, array('context' => $this, 'escape' => false));
} else {
$name .= format_string($mod->name, true, array('context' => $this));
}
}
}
return $name;
@@ -7405,9 +7429,10 @@ class context_block extends context {
*
* @param boolean $withprefix whether to prefix the name of the context with Block
* @param boolean $short does not apply to block context
* @param boolean $escape does not apply to block context
* @return string the human readable context name.
*/
public function get_context_name($withprefix = true, $short = false) {
public function get_context_name($withprefix = true, $short = false, $escape = true) {
global $DB, $CFG;
$name = '';
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+48 -13
View File
@@ -68,6 +68,22 @@ define([
/** @var {Array} disallowedNestedHelpers - List of helpers that can't be called within other helpers */
var disallowedNestedHelpers = ['js'];
/**
* Normalise the provided component such that '', 'moodle', and 'core' are treated consistently.
*
* @param {String} component
* @returns {String}
*/
var getNormalisedComponent = function(component) {
if (component) {
if (component !== 'moodle' && component !== 'core') {
return component;
}
}
return 'core';
};
/**
* Search the various caches for a template promise for the given search key.
* The search key should be in the format <theme>/<component>/<template> e.g. boost/core/modal.
@@ -133,7 +149,7 @@ define([
var requests = [];
// Get a list of promises for each of the templates we need to load.
var templatePromises = templatesToLoad.map(function(templateData) {
var component = templateData.component;
var component = getNormalisedComponent(templateData.component);
var name = templateData.name;
var searchKey = templateData.searchKey;
var theme = templateData.theme;
@@ -177,6 +193,7 @@ define([
// Process all of the template dependencies for this template and add
// them to the caches so that we don't request them again later.
response.templates.forEach(function(data) {
data.component = getNormalisedComponent(data.component);
// Generate the search key for this template in the response so that we
// can add it to the caches.
var tempSearchKey = [theme, data.component, data.name].join('/');
@@ -200,7 +217,7 @@ define([
// with them now so that we don't need to re-fetch them.
str.cache_strings(response.strings.map(function(data) {
return {
component: data.component,
component: getNormalisedComponent(data.component),
key: data.name,
value: data.value
};
@@ -315,7 +332,7 @@ define([
// This is the first time this has been requested so let's add it to the buffer
// to be loaded.
var parts = templateName.split('/');
var component = parts.shift();
var component = getNormalisedComponent(parts.shift());
var name = parts.join('/');
var deferred = $.Deferred();
@@ -361,7 +378,7 @@ define([
// This is the first time this has been requested so let's add it to the buffer to be loaded.
var parts = templateName.split('/');
var component = parts.shift();
var component = getNormalisedComponent(parts.shift());
var name = parts.join('/');
// Add this template to the buffer to be loaded.
@@ -409,6 +426,7 @@ define([
Renderer.prototype.renderIcon = function(key, component, title) {
// Preload the module to do the icon rendering based on the theme iconsystem.
var modulename = config.iconsystemmodule;
component = getNormalisedComponent(component);
// RequireJS does not return a promise.
var ready = $.Deferred();
@@ -425,7 +443,12 @@ define([
return ready.then(function(iconSystem) {
return this.getTemplate(iconSystem.getTemplateName());
}.bind(this)).then(function(template) {
return iconSystem.renderIcon(key, component, title, template);
return iconSystem.renderIcon(
key,
component,
title,
template
);
});
};
@@ -456,15 +479,21 @@ define([
}
var templateName = iconSystem.getTemplateName();
var searchKey = this.currentThemeName + '/' + templateName;
var template = templateCache[searchKey];
component = getNormalisedComponent(component);
// The key might have been escaped by the JS Mustache engine which
// converts forward slashes to HTML entities. Let us undo that here.
key = key.replace(/&#x2F;/gi, '/');
return iconSystem.renderIcon(key, component, text, template);
return iconSystem.renderIcon(
key,
component,
text,
template
);
};
/**
@@ -508,9 +537,7 @@ define([
param = parts.join(',').trim();
}
if (!component || component === 'moodle') {
component = 'core';
}
component = getNormalisedComponent(component);
if (param !== '') {
// Allow variable expansion in the param part only.
@@ -522,7 +549,11 @@ define([
}
var index = this.requiredStrings.length;
this.requiredStrings.push({key: key, component: component, param: param});
this.requiredStrings.push({
key: key,
component: component,
param: param
});
// The placeholder must not use {{}} as those can be misinterpreted by the engine.
return '[[_s' + index + ']]';
@@ -545,7 +576,7 @@ define([
// This involves wrapping {{, and }} in change delimeter tags.
content = content
.replace(/"/g, '\\"')
.replace(/([\{\}]{2,3})/g, '{{=<% %>=}}$1<%={{ }}=%>')
.replace(/([{}]{2,3})/g, '{{=<% %>=}}$1<%={{ }}=%>')
.replace(/(\r\n|\r|\n)/g, '&#x0a;')
;
return '"' + content + '"';
@@ -1173,7 +1204,11 @@ define([
*/
renderPix: function(key, component, title) {
var renderer = new Renderer();
return renderer.renderIcon(key, component, title);
return renderer.renderIcon(
key,
getNormalisedComponent(component),
title
);
},
/**
+20 -9
View File
@@ -731,17 +731,28 @@ class behat_config_util {
}
$installedversion = $package->version;
} else if (!empty($CFG->behat_ionic_wwwroot)) {
// Get app version from config.json inside wwwroot.
$jsonurl = $CFG->behat_ionic_wwwroot . '/config.json';
$json = @download_file_content($jsonurl);
// Get app version from env.json inside wwwroot.
$jsonurl = $CFG->behat_ionic_wwwroot . '/assets/env.json';
$json = @file_get_contents($jsonurl);
if (!$json) {
throw new coding_exception('Unable to load app version from ' . $jsonurl);
// Fall back to ionic 3 config file.
$jsonurl = $CFG->behat_ionic_wwwroot . '/config.json';
$json = @file_get_contents($jsonurl);
if (!$json) {
throw new coding_exception('Unable to load app version from ' . $jsonurl);
}
$config = json_decode($json);
if ($config === null || empty($config->versionname)) {
throw new coding_exception('Invalid app config data in ' . $jsonurl);
}
$installedversion = str_replace('-dev', '', $config->versionname);
} else {
$env = json_decode($json);
if (empty($env->build->version ?? null)) {
throw new coding_exception('Invalid app config data in ' . $jsonurl);
}
$installedversion = $env->build->version;
}
$config = json_decode($json);
if ($config === null || empty($config->versionname)) {
throw new coding_exception('Invalid app config data in ' . $jsonurl);
}
$installedversion = str_replace('-dev', '', $config->versionname);
} else {
return '';
}
+3 -48
View File
@@ -25,10 +25,11 @@
defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/../../behat/behat_base.php');
use Behat\Gherkin\Node\TableNode as TableNode;
use Behat\Behat\Tester\Exception\PendingException as PendingException;
/**
* Class to quickly create Behat test data using component data generators.
*
@@ -480,53 +481,7 @@ abstract class behat_generator_base {
* @return context
*/
protected function get_context($levelname, $contextref) {
global $DB;
// Getting context levels and names (we will be using the English ones as it is the test site language).
$contextlevels = context_helper::get_all_levels();
$contextnames = array();
foreach ($contextlevels as $level => $classname) {
$contextnames[context_helper::get_level_name($level)] = $level;
}
if (empty($contextnames[$levelname])) {
throw new Exception('The specified "' . $levelname . '" context level does not exist');
}
$contextlevel = $contextnames[$levelname];
// Return it, we don't need to look for other internal ids.
if ($contextlevel == CONTEXT_SYSTEM) {
return context_system::instance();
}
switch ($contextlevel) {
case CONTEXT_USER:
$instanceid = $DB->get_field('user', 'id', array('username' => $contextref));
break;
case CONTEXT_COURSECAT:
$instanceid = $DB->get_field('course_categories', 'id', array('idnumber' => $contextref));
break;
case CONTEXT_COURSE:
$instanceid = $DB->get_field('course', 'id', array('shortname' => $contextref));
break;
case CONTEXT_MODULE:
$instanceid = $DB->get_field('course_modules', 'id', array('idnumber' => $contextref));
break;
default:
break;
}
$contextclass = $contextlevels[$contextlevel];
if (!$context = $contextclass::instance($instanceid, IGNORE_MISSING)) {
throw new Exception('The specified "' . $contextref . '" context reference does not exist');
}
return $context;
return behat_base::get_context($levelname, $contextref);
}
/**
+63
View File
@@ -1068,6 +1068,69 @@ EOF;
\core\session\manager::set_user($user);
}
/**
* Gets the internal moodle context id from the context reference.
*
* The context reference changes depending on the context
* level, it can be the system, a user, a category, a course or
* a module.
*
* @throws Exception
* @param string $levelname The context level string introduced by the test writer
* @param string $contextref The context reference introduced by the test writer
* @return context
*/
public static function get_context(string $levelname, string $contextref): context {
global $DB;
// Getting context levels and names (we will be using the English ones as it is the test site language).
$contextlevels = context_helper::get_all_levels();
$contextnames = array();
foreach ($contextlevels as $level => $classname) {
$contextnames[context_helper::get_level_name($level)] = $level;
}
if (empty($contextnames[$levelname])) {
throw new Exception('The specified "' . $levelname . '" context level does not exist');
}
$contextlevel = $contextnames[$levelname];
// Return it, we don't need to look for other internal ids.
if ($contextlevel == CONTEXT_SYSTEM) {
return context_system::instance();
}
switch ($contextlevel) {
case CONTEXT_USER:
$instanceid = $DB->get_field('user', 'id', array('username' => $contextref));
break;
case CONTEXT_COURSECAT:
$instanceid = $DB->get_field('course_categories', 'id', array('idnumber' => $contextref));
break;
case CONTEXT_COURSE:
$instanceid = $DB->get_field('course', 'id', array('shortname' => $contextref));
break;
case CONTEXT_MODULE:
$instanceid = $DB->get_field('course_modules', 'id', array('idnumber' => $contextref));
break;
default:
break;
}
$contextclass = $contextlevels[$contextlevel];
if (!$context = $contextclass::instance($instanceid, IGNORE_MISSING)) {
throw new Exception('The specified "' . $contextref . '" context reference does not exist');
}
return $context;
}
/**
* Trigger click on node via javascript instead of actually clicking on it via pointer.
*

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