Merge branch 'MDL-70126' of git://github.com/paulholden/moodle
authorAndrew Nicols <andrew@nicols.co.uk>
Wed, 11 Nov 2020 02:20:00 +0000 (10:20 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Wed, 11 Nov 2020 02:20:00 +0000 (10:20 +0800)
14 files changed:
auth/db/auth.php
auth/db/tests/db_test.php
lib/amd/build/icon_system_fontawesome.min.js
lib/amd/build/icon_system_fontawesome.min.js.map
lib/amd/src/icon_system_fontawesome.js
mod/quiz/mod_form.php
mod/quiz/tests/behat/editing_add_from_question_bank.feature
question/classes/bank/view.php
question/type/ddimageortext/amd/build/question.min.js
question/type/ddimageortext/amd/build/question.min.js.map
question/type/ddimageortext/amd/src/question.js
theme/boost/scss/moodle/modules.scss
theme/boost/style/moodle.css
theme/classic/style/moodle.css

index 5c0f74f..9d3cc18 100644 (file)
@@ -460,7 +460,7 @@ class auth_plugin_db extends auth_plugin_base {
                     continue;
                 }
                 try {
-                    $id = user_create_user($user, false); // It is truly a new user.
+                    $id = user_create_user($user, false, false); // It is truly a new user.
                     $trace->output(get_string('auth_dbinsertuser', 'auth_db', array('name'=>$user->username, 'id'=>$id)), 1);
                 } catch (moodle_exception $e) {
                     $trace->output(get_string('auth_dbinsertusererror', 'auth_db', $user->username), 1);
@@ -479,6 +479,8 @@ class auth_plugin_db extends auth_plugin_base {
 
                 // Make sure user context is present.
                 context_user::instance($id);
+
+                \core\event\user_created::create_from_userid($id)->trigger();
             }
             unset($add_users);
         }
index b17a7c0..1de432c 100644 (file)
@@ -119,6 +119,7 @@ class auth_db_testcase extends advanced_testcase {
         $table->add_field('email', XMLDB_TYPE_CHAR, '255', null, null, null);
         $table->add_field('firstname', XMLDB_TYPE_CHAR, '255', null, null, null);
         $table->add_field('lastname', XMLDB_TYPE_CHAR, '255', null, null, null);
+        $table->add_field('animal', XMLDB_TYPE_CHAR, '255', null, null, null);
         $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
         if ($dbman->table_exists($table)) {
             $dbman->drop_table($table);
@@ -137,6 +138,15 @@ class auth_db_testcase extends advanced_testcase {
         set_config('field_updateremote_email', '0', 'auth_db');
         set_config('field_lock_email', 'unlocked', 'auth_db');
 
+        // Create a user profile field and add mapping to it.
+        $DB->insert_record('user_info_field', ['shortname' => 'pet', 'name' => 'Pet', 'required' => 0,
+            'visible' => 1, 'locked' => 0, 'categoryid' => 1, 'datatype' => 'text']);
+
+        set_config('field_map_profile_field_pet', 'animal', 'auth_db');
+        set_config('field_updatelocal_profile_field_pet', 'oncreate', 'auth_db');
+        set_config('field_updateremote_profile_field_pet', '0', 'auth_db');
+        set_config('field_lock_profile_field_pet', 'unlocked', 'auth_db');
+
         // Init the rest of settings.
         set_config('passtype', 'plaintext', 'auth_db');
         set_config('changepasswordurl', '', 'auth_db');
@@ -156,6 +166,7 @@ class auth_db_testcase extends advanced_testcase {
 
     public function test_plugin() {
         global $DB, $CFG;
+        require_once($CFG->dirroot . '/user/profile/lib.php');
 
         $this->resetAfterTest(true);
 
@@ -193,7 +204,7 @@ class auth_db_testcase extends advanced_testcase {
 
         // Test bulk user account creation.
 
-        $user2 = (object)array('name'=>'u2', 'pass'=>'heslo', 'email'=>'u2@example.com');
+        $user2 = (object)['name' => 'u2', 'pass' => 'heslo', 'email' => 'u2@example.com', 'animal' => 'cat'];
         $user2->id = $DB->insert_record('auth_db_users', $user2);
 
         $user3 = (object)array('name'=>'admin', 'pass'=>'heslo', 'email'=>'admin@example.com'); // Should be skipped.
@@ -202,13 +213,24 @@ class auth_db_testcase extends advanced_testcase {
         $this->assertCount(2, $DB->get_records('user'));
 
         $trace = new null_progress_trace();
+
+        // Sync users and make sure that two events user_created werer triggered.
+        $sink = $this->redirectEvents();
         $auth->sync_users($trace, false);
+        $events = $sink->get_events();
+        $sink->close();
+        $this->assertCount(2, $events);
+        $this->assertTrue($events[0] instanceof  \core\event\user_created);
+        $this->assertTrue($events[1] instanceof  \core\event\user_created);
 
+        // Assert the two users were created.
         $this->assertEquals(4, $DB->count_records('user'));
         $u1 = $DB->get_record('user', array('username'=>$user1->name, 'auth'=>'db'));
         $this->assertSame($user1->email, $u1->email);
+        $this->assertEmpty(profile_user_record($u1->id)->pet);
         $u2 = $DB->get_record('user', array('username'=>$user2->name, 'auth'=>'db'));
         $this->assertSame($user2->email, $u2->email);
+        $this->assertSame($user2->animal, profile_user_record($u2->id)->pet);
         $admin = $DB->get_record('user', array('username'=>'admin', 'auth'=>'manual'));
         $this->assertNotEmpty($admin);
 
@@ -217,12 +239,14 @@ class auth_db_testcase extends advanced_testcase {
 
         $user2b = clone($user2);
         $user2b->email = 'u2b@example.com';
+        $user2b->animal = 'dog';
         $DB->update_record('auth_db_users', $user2b);
 
         $auth->sync_users($trace, false);
         $this->assertEquals(4, $DB->count_records('user'));
         $u2 = $DB->get_record('user', array('username'=>$user2->name));
         $this->assertSame($user2->email, $u2->email);
+        $this->assertSame($user2->animal, profile_user_record($u2->id)->pet);
 
         $auth->sync_users($trace, true);
         $this->assertEquals(4, $DB->count_records('user'));
@@ -231,6 +255,8 @@ class auth_db_testcase extends advanced_testcase {
 
         set_config('field_updatelocal_email', 'onlogin', 'auth_db');
         $auth->config->field_updatelocal_email = 'onlogin';
+        set_config('field_updatelocal_profile_field_pet', 'onlogin', 'auth_db');
+        $auth->config->field_updatelocal_profile_field_pet = 'onlogin';
 
         $auth->sync_users($trace, false);
         $this->assertEquals(4, $DB->count_records('user'));
@@ -241,6 +267,7 @@ class auth_db_testcase extends advanced_testcase {
         $this->assertEquals(4, $DB->count_records('user'));
         $u2 = $DB->get_record('user', array('username'=>$user2->name));
         $this->assertSame($user2b->email, $u2->email);
+        $this->assertSame($user2b->animal, profile_user_record($u2->id)->pet);
 
 
         // Test sync deletes and suspends.
index 47c4244..10ffe0b 100644 (file)
Binary files a/lib/amd/build/icon_system_fontawesome.min.js and b/lib/amd/build/icon_system_fontawesome.min.js differ
index 1bb4e1d..374c798 100644 (file)
Binary files a/lib/amd/build/icon_system_fontawesome.min.js.map and b/lib/amd/build/icon_system_fontawesome.min.js.map differ
index 25c749c..39c4711 100644 (file)
@@ -42,11 +42,13 @@ define(['core/icon_system', 'jquery', 'core/ajax', 'core/mustache', 'core/locals
      * @return {Promise}
      */
     IconSystemFontawesome.prototype.init = function() {
+        var currTheme = M.cfg.theme;
+
         if (staticMap) {
             return $.when(this);
         }
 
-        var map = LocalStorage.get('core/iconmap-fontawesome');
+        var map = LocalStorage.get('core_iconsystem/theme/' + currTheme + '/core/iconmap-fontawesome');
         if (map) {
             map = JSON.parse(map);
         }
@@ -70,7 +72,7 @@ define(['core/icon_system', 'jquery', 'core/ajax', 'core/mustache', 'core/locals
             $.each(map, function(index, value) {
                 staticMap[value.component + '/' + value.pix] = value.to;
             });
-            LocalStorage.set('core/iconmap-fontawesome', JSON.stringify(staticMap));
+            LocalStorage.set('core_iconsystem/theme/' + currTheme + '/core/iconmap-fontawesome', JSON.stringify(staticMap));
             return this;
         }.bind(this));
     };
index 9f3c90e..86bf35b 100644 (file)
@@ -378,11 +378,13 @@ class mod_quiz_mod_form extends moodleform_mod {
             list($identifier, $component) = $string;
 
             $label = get_string($identifier, $component);
+            $group[] = $mform->createElement('html', html_writer::start_div('review_option_item'));
+            $el = $mform->createElement('checkbox', $field . $whenname, '', $label);
             if ($withhelp) {
-                $label .= ' ' . $OUTPUT->help_icon($identifier, $component);
+                $el->_helpbutton = $OUTPUT->render(new help_icon($identifier, $component));
             }
-
-            $group[] = $mform->createElement('checkbox', $field . $whenname, '', $label);
+            $group[] = $el;
+            $group[] = $mform->createElement('html', html_writer::end_div());
         }
         $mform->addGroup($group, $whenname . 'optionsgrp',
                 get_string('review' . $whenname, 'quiz'), null, false);
index b8c8e68..3ff5acd 100644 (file)
@@ -79,6 +79,9 @@ Feature: Adding questions to a quiz from the question bank
     Then I should see "question 21 name" in the "categoryquestions" "table"
     And I should see "question 22 name" in the "categoryquestions" "table"
     And I should not see "question 01 name" in the "categoryquestions" "table"
+    And I click on "Show all 22" "link" in the ".pagingbottom" "css_element"
+    And I should see "question 01 name" in the "categoryquestions" "table"
+    And I should see "question 22 name" in the "categoryquestions" "table"
 
   Scenario: Questions are added in the right place with multiple sections
     Given the following "questions" exist:
index c8ec225..de74be8 100644 (file)
@@ -860,7 +860,7 @@ class view {
         if ($totalnumber > DEFAULT_QUESTIONS_PER_PAGE) {
             if ($perpage == DEFAULT_QUESTIONS_PER_PAGE) {
                 $url = new \moodle_url('edit.php', array_merge($pageurl->params(),
-                        array('qperpage' => MAXIMUM_QUESTIONS_PER_PAGE)));
+                        array('qpage' => 0, 'qperpage' => MAXIMUM_QUESTIONS_PER_PAGE)));
                 if ($totalnumber > MAXIMUM_QUESTIONS_PER_PAGE) {
                     $showall = '<a href="'.$url.'">'.get_string('showperpage', 'moodle', MAXIMUM_QUESTIONS_PER_PAGE).'</a>';
                 } else {
index d315b9d..7bebe76 100644 (file)
Binary files a/question/type/ddimageortext/amd/build/question.min.js and b/question/type/ddimageortext/amd/build/question.min.js differ
index 28b05d3..801f740 100644 (file)
Binary files a/question/type/ddimageortext/amd/build/question.min.js.map and b/question/type/ddimageortext/amd/build/question.min.js.map differ
index 8d031bf..c62e611 100644 (file)
@@ -364,10 +364,12 @@ define(['jquery', 'core/dragdrop', 'core/key_codes'], function($, dragDrop, keys
      * @param {jQuery} drag the item being moved.
      */
     DragDropOntoImageQuestion.prototype.dragMove = function(pageX, pageY, drag) {
-        var thisQ = this;
+        var thisQ = this,
+            highlighted = false;
         this.getRoot().find('.dropzone.group' + this.getGroup(drag)).each(function(i, dropNode) {
             var drop = $(dropNode);
-            if (thisQ.isPointInDrop(pageX, pageY, drop)) {
+            if (thisQ.isPointInDrop(pageX, pageY, drop) && !highlighted) {
+                highlighted = true;
                 drop.addClass('valid-drag-over-drop');
             } else {
                 drop.removeClass('valid-drag-over-drop');
@@ -375,7 +377,8 @@ define(['jquery', 'core/dragdrop', 'core/key_codes'], function($, dragDrop, keys
         });
         this.getRoot().find('.draghome.placed.group' + this.getGroup(drag)).not('.beingdragged').each(function(i, dropNode) {
             var drop = $(dropNode);
-            if (thisQ.isPointInDrop(pageX, pageY, drop)) {
+            if (thisQ.isPointInDrop(pageX, pageY, drop) && !highlighted && !thisQ.isDragSameAsDrop(drag, drop)) {
+                highlighted = true;
                 drop.addClass('valid-drag-over-drop');
             } else {
                 drop.removeClass('valid-drag-over-drop');
@@ -394,6 +397,8 @@ define(['jquery', 'core/dragdrop', 'core/key_codes'], function($, dragDrop, keys
         var thisQ = this,
             root = this.getRoot(),
             placed = false;
+
+        // Looking for drag that was dropped on a dropzone.
         root.find('.dropzone.group' + this.getGroup(drag)).each(function(i, dropNode) {
             var drop = $(dropNode);
             if (!thisQ.isPointInDrop(pageX, pageY, drop)) {
@@ -408,21 +413,24 @@ define(['jquery', 'core/dragdrop', 'core/key_codes'], function($, dragDrop, keys
             return false; // Stop the each() here.
         });
 
-        root.find('.draghome.placed.group' + this.getGroup(drag)).not('.beingdragged').each(function(i, placedNode) {
-            var placedDrag = $(placedNode);
-            if (!thisQ.isPointInDrop(pageX, pageY, placedDrag)) {
-                // Not this placed drag.
-                return true;
-            }
+        if (!placed) {
+            // Looking for drag that was dropped on a placed drag.
+            root.find('.draghome.placed.group' + this.getGroup(drag)).not('.beingdragged').each(function(i, placedNode) {
+                var placedDrag = $(placedNode);
+                if (!thisQ.isPointInDrop(pageX, pageY, placedDrag) || thisQ.isDragSameAsDrop(drag, placedDrag)) {
+                    // Not this placed drag.
+                    return true;
+                }
 
-            // Now put this drag into the drop.
-            placedDrag.removeClass('valid-drag-over-drop');
-            var currentPlace = thisQ.getClassnameNumericSuffix(placedDrag, 'inplace');
-            var drop = thisQ.getDrop(drag, currentPlace);
-            thisQ.sendDragToDrop(drag, drop);
-            placed = true;
-            return false; // Stop the each() here.
-        });
+                // Now put this drag into the drop.
+                placedDrag.removeClass('valid-drag-over-drop');
+                var currentPlace = thisQ.getClassnameNumericSuffix(placedDrag, 'inplace');
+                var drop = thisQ.getDrop(drag, currentPlace);
+                thisQ.sendDragToDrop(drag, drop);
+                placed = true;
+                return false; // Stop the each() here.
+            });
+        }
 
         if (!placed) {
             this.sendDragHome(drag);
@@ -917,6 +925,17 @@ define(['jquery', 'core/dragdrop', 'core/key_codes'], function($, dragDrop, keys
         return zIndex;
     };
 
+    /**
+     * Check that the drag is drop to it's clone.
+     *
+     * @param {jQuery} drag The drag.
+     * @param {jQuery} drop The drop.
+     * @returns {boolean}
+     */
+    DragDropOntoImageQuestion.prototype.isDragSameAsDrop = function(drag, drop) {
+        return this.getChoice(drag) === this.getChoice(drop) && this.getGroup(drag) === this.getGroup(drop);
+    };
+
     /**
      * Singleton object that handles all the DragDropOntoImageQuestions
      * on the page, and deals with event dispatching.
@@ -996,6 +1015,8 @@ define(['jquery', 'core/dragdrop', 'core/key_codes'], function($, dragDrop, keys
          * @param {jQuery} element Element to bind the event
          */
         addEventHandlersToDrag: function(element) {
+            // Unbind all the mousedown and touchstart events to prevent double binding.
+            element.unbind('mousedown touchstart');
             element.on('mousedown touchstart', questionManager.handleDragStart);
         },
 
index 5218e74..4e11c5c 100644 (file)
@@ -1159,11 +1159,16 @@ div#dock {
     clear: left;
 }
 #page-mod-quiz-mod #id_reviewoptionshdr .form-check {
-    width: 90%;
+    width: auto;
     height: 22px;
     justify-content: flex-start;
 }
 
+#page-mod-quiz-mod #id_reviewoptionshdr .review_option_item {
+    width: 90%;
+    height: 22px;
+}
+
 // Question navigation block.
 .path-mod-quiz #mod_quiz_navblock {
     .qnbutton {
index 59f212a..87f7ce7 100644 (file)
@@ -17478,10 +17478,14 @@ div#dock {
   clear: left; }
 
 #page-mod-quiz-mod #id_reviewoptionshdr .form-check {
-  width: 90%;
+  width: auto;
   height: 22px;
   justify-content: flex-start; }
 
+#page-mod-quiz-mod #id_reviewoptionshdr .review_option_item {
+  width: 90%;
+  height: 22px; }
+
 .path-mod-quiz #mod_quiz_navblock .qnbutton {
   text-decoration: none;
   font-size: 14px;
index cf7cc90..d8d736c 100644 (file)
@@ -17705,10 +17705,14 @@ div#dock {
   clear: left; }
 
 #page-mod-quiz-mod #id_reviewoptionshdr .form-check {
-  width: 90%;
+  width: auto;
   height: 22px;
   justify-content: flex-start; }
 
+#page-mod-quiz-mod #id_reviewoptionshdr .review_option_item {
+  width: 90%;
+  height: 22px; }
+
 .path-mod-quiz #mod_quiz_navblock .qnbutton {
   text-decoration: none;
   font-size: 14px;