Merge branch 'MDL-68952-master' of git://github.com/mihailges/moodle
authorJake Dallimore <jake@moodle.com>
Mon, 8 Jun 2020 06:09:14 +0000 (14:09 +0800)
committerJake Dallimore <jake@moodle.com>
Mon, 8 Jun 2020 06:09:14 +0000 (14:09 +0800)
h5p/classes/editor.php
h5p/classes/helper.php
lib/classes/plugin_manager.php
lib/templates/filemanager_selectlayout.mustache
mod/h5pactivity/classes/external/get_h5pactivity_access_information.php
mod/h5pactivity/classes/external/h5pactivity_summary_exporter.php
mod/h5pactivity/tests/external/get_h5pactivities_by_courses_test.php
mod/h5pactivity/tests/external/get_h5pactivity_access_information_test.php
repository/contentbank/tests/behat/file_update.feature [new file with mode: 0644]
theme/classic/scss/classic/post.scss
theme/classic/style/moodle.css

index 8faa32f..a4b4af7 100644 (file)
@@ -228,10 +228,6 @@ class editor {
             throw new coding_exception('Missing H5P library.');
         }
 
-        if ($content->h5plibrary != $this->library) {
-            throw new coding_exception("Wrong H5P library.");
-        }
-
         $content->params = $content->h5pparams;
 
         if (!empty($this->oldcontent)) {
@@ -310,15 +306,16 @@ class editor {
         if ($file) {
             $fields['contenthash'] = $file->get_contenthash();
 
-            // Delete old file if any.
-            if (!empty($this->oldfile)) {
-                $this->oldfile->delete();
-            }
-            // Create new file.
+            // Create or update H5P file.
             if (empty($this->filearea['filename'])) {
                 $this->filearea['filename'] = $contentarray['slug'] . '.h5p';
             }
-            $newfile = $fs->create_file_from_storedfile($this->filearea, $file);
+            if (!empty($this->oldfile)) {
+                $this->oldfile->replace_file_with($file);
+                $newfile = $this->oldfile;
+            } else {
+                $newfile = $fs->create_file_from_storedfile($this->filearea, $file);
+            }
             if (empty($this->oldcontent)) {
                 $pathnamehash = $newfile->get_pathnamehash();
             } else {
index 721187e..2cf6598 100644 (file)
@@ -359,7 +359,7 @@ class helper {
             'crossorigin' => null,
             'libraryConfig' => $core->h5pF->getLibraryConfig(),
             'pluginCacheBuster' => self::get_cache_buster(),
-            'libraryUrl' => autoloader::get_h5p_core_library_url('core/js')
+            'libraryUrl' => autoloader::get_h5p_core_library_url('js')->out(),
         );
 
         return $settings;
index 0d8d832..bb7f39d 100644 (file)
@@ -2000,7 +2000,7 @@ class core_plugin_manager {
                 'analytics', 'availabilityconditions', 'behat', 'capability', 'cohortroles', 'customlang',
                 'dataprivacy', 'dbtransfer', 'filetypes', 'generator', 'health', 'httpsreplace', 'innodb',
                 'installaddon', 'langimport', 'licensemanager', 'log', 'lp', 'lpimportcsv', 'lpmigrate', 'messageinbound',
-                'mobile', 'multilangupgrade', 'monitor', 'oauth2', 'phpunit', 'policy', 'profiling', 'recyclebin',
+                'mobile', 'moodlenet', 'multilangupgrade', 'monitor', 'oauth2', 'phpunit', 'policy', 'profiling', 'recyclebin',
                 'replace', 'spamcleaner', 'task', 'templatelibrary', 'uploadcourse', 'uploaduser', 'unsuproles',
                 'usertours', 'xmldb'
             ),
index 974c5be..d97b92e 100644 (file)
@@ -29,7 +29,7 @@
     </div>
     <div class="container">
         <form>
-            <fieldset class="form-group row">
+            <fieldset class="form-group row flex-column">
                 <div class="form-check fp-linktype-2">
                     <label class="form-check-label">
                         <input class="form-check-input" type="radio">
index ff4ae4b..20e8012 100644 (file)
@@ -35,6 +35,7 @@ use external_value;
 use external_single_structure;
 use external_warnings;
 use context_module;
+use mod_h5pactivity\local\manager;
 
 /**
  * This is the external method for getting access information for a h5p activity.
@@ -81,10 +82,16 @@ class get_h5pactivity_access_information extends external_api {
 
         $result = [];
         // Return all the available capabilities.
+        $manager = manager::create_from_coursemodule($cm);
         $capabilities = load_capability_def('mod_h5pactivity');
         foreach ($capabilities as $capname => $capdata) {
             $field = 'can' . str_replace('mod/h5pactivity:', '', $capname);
-            $result[$field] = has_capability($capname, $context);
+            // For mod/h5pactivity:submit we need to check if tracking is enabled in the h5pactivity for the current user.
+            if ($field == 'cansubmit') {
+                $result[$field] = $manager->is_tracking_enabled();
+            } else {
+                $result[$field] = has_capability($capname, $context);
+            }
         }
 
         $result['warnings'] = [];
index 26145ad..493fa1f 100644 (file)
@@ -132,6 +132,9 @@ class h5pactivity_summary_exporter extends exporter {
             'coursemodule' => [
                 'type' => PARAM_INT
             ],
+            'context' => [
+                'type' => PARAM_INT
+            ],
             'introfiles' => [
                 'type' => external_files::get_properties_for_exporter(),
                 'multiple' => true
@@ -197,6 +200,7 @@ class h5pactivity_summary_exporter extends exporter {
 
         $values = [
             'coursemodule' => $context->instanceid,
+            'context' => $context->id,
         ];
 
         $values['introfiles'] = external_util::get_area_files($context->id, 'mod_h5pactivity', 'intro', false, false);
index 62050d2..ac6014a 100644 (file)
@@ -65,16 +65,21 @@ class get_h5pactivities_by_courses_testcase extends externallib_advanced_testcas
             'introformat' => 1
         ];
         $activities[] = $this->getDataGenerator()->create_module('h5pactivity', $params);
-        // Add filename to make easier the asserts.
+        // Add filename and contextid to make easier the asserts.
         $activities[0]->filename = 'filltheblanks.h5p';
+        $context = context_module::instance($activities[0]->cmid);
+        $activities[0]->contextid = $context->id;
+
         $params = [
             'course' => $course1->id,
             'packagefilepath' => $CFG->dirroot.'/h5p/tests/fixtures/greeting-card-887.h5p',
             'introformat' => 1
         ];
         $activities[] = $this->getDataGenerator()->create_module('h5pactivity', $params);
-        // Add filename to make easier the asserts.
+        // Add filename and contextid to make easier the asserts.
         $activities[1]->filename = 'greeting-card-887.h5p';
+        $context = context_module::instance($activities[1]->cmid);
+        $activities[1]->contextid = $context->id;
 
         $course2 = $this->getDataGenerator()->create_course();
         $params = [
@@ -84,8 +89,9 @@ class get_h5pactivities_by_courses_testcase extends externallib_advanced_testcas
         ];
         $activities[] = $this->getDataGenerator()->create_module('h5pactivity', $params);
         $activities[2]->filename = 'guess-the-answer.h5p';
-
         $context = context_module::instance($activities[2]->cmid);
+        $activities[2]->contextid = $context->id;
+
         // Create a fake deploy H5P file.
         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
         $deployedfile = $generator->create_export_file($activities[2]->filename, $context->id, 'mod_h5pactivity', 'package');
@@ -176,6 +182,7 @@ class get_h5pactivities_by_courses_testcase extends externallib_advanced_testcas
             $this->assertEquals($activities[$i]->enabletracking, $result['h5pactivities'][$i]['enabletracking']);
             $this->assertEquals($activities[$i]->grademethod, $result['h5pactivities'][$i]['grademethod']);
             $this->assertEquals($activities[$i]->cmid, $result['h5pactivities'][$i]['coursemodule']);
+            $this->assertEquals($activities[$i]->contextid, $result['h5pactivities'][$i]['context']);
             $this->assertEquals($activities[$i]->filename, $result['h5pactivities'][$i]['package'][0]['filename']);
         }
     }
index fcef64d..00c587c 100644 (file)
@@ -46,42 +46,36 @@ class get_h5pactivity_access_information_testcase extends externallib_advanced_t
 
     /**
      * Test the behaviour of get_h5pactivity_access_information().
+     *
+     * @dataProvider get_h5pactivity_access_information_data
+     * @param string $role user role in course
+     * @param int $enabletracking if tracking is enabled
+     * @param array $enabledcaps capabilities enabled
      */
-    public function test_get_h5pactivity_access_information() {
+    public function test_get_h5pactivity_access_information(string $role, int $enabletracking, array $enabledcaps) {
         $this->resetAfterTest();
         $this->setAdminUser();
 
         $course = $this->getDataGenerator()->create_course();
-        $activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]);
-        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
-        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $activity = $this->getDataGenerator()->create_module('h5pactivity',
+            [
+                'course' => $course,
+                'enabletracking' => $enabletracking
+            ]
+        );
 
-        // Check the access information for a student.
-        $this->setUser($student);
-        $result = get_h5pactivity_access_information::execute($activity->id);
-        $result = external_api::clean_returnvalue(get_h5pactivity_access_information::execute_returns(), $result);
-        $this->assertCount(0, $result['warnings']);
-        unset($result['warnings']);
-
-        // Check default values for capabilities for student.
-        $enabledcaps = ['canview', 'cansubmit'];
-        foreach ($result as $capname => $capvalue) {
-            if (in_array($capname, $enabledcaps)) {
-                $this->assertTrue($capvalue);
-            } else {
-                $this->assertFalse($capvalue);
-            }
+        if ($role) {
+            $user = $this->getDataGenerator()->create_and_enrol($course, $role);
+            $this->setUser($user);
         }
 
-        // Check the access information for a teacher.
-        $this->setUser($teacher);
+        // Check the access information.
         $result = get_h5pactivity_access_information::execute($activity->id);
         $result = external_api::clean_returnvalue(get_h5pactivity_access_information::execute_returns(), $result);
         $this->assertCount(0, $result['warnings']);
         unset($result['warnings']);
 
-        // Check default values for capabilities for teacher.
-        $enabledcaps = ['canview', 'canaddinstance', 'canreviewattempts'];
+        // Check the values for capabilities.
         foreach ($result as $capname => $capvalue) {
             if (in_array($capname, $enabledcaps)) {
                 $this->assertTrue($capvalue);
@@ -89,9 +83,55 @@ class get_h5pactivity_access_information_testcase extends externallib_advanced_t
                 $this->assertFalse($capvalue);
             }
         }
+    }
+
+    /**
+     * Data provider for get_h5pactivity_access_information.
+     *
+     * @return array
+     */
+    public function get_h5pactivity_access_information_data(): array {
+        return [
+            'Admin, tracking enabled' => [
+                '', 1, ['canview', 'canreviewattempts', 'canaddinstance']
+            ],
+            'Admin, tracking disabled' => [
+                '', 0, ['canview', 'canreviewattempts', 'canaddinstance']
+            ],
+            'Student, tracking enabled' => [
+                'student', 1, ['canview', 'cansubmit']
+            ],
+            'Student, tracking disabled' => [
+                'student', 0, ['canview']
+            ],
+            'Teacher, tracking enabled' => [
+                'editingteacher', 1, [
+                    'canview',
+                    'canreviewattempts',
+                    'canaddinstance'
+                ]
+            ],
+            'Teacher, tracking disabled' => [
+                'editingteacher', 0, [
+                    'canview',
+                    'canreviewattempts',
+                    'canaddinstance'
+                ]
+            ],
+        ];
+    }
+
+    /**
+     * Test dml_missing_record_exception in get_h5pactivity_access_information.
+     */
+    public function test_dml_missing_record_exception() {
+        $this->resetAfterTest();
+        $this->setAdminUser();
+
+        $course = $this->getDataGenerator()->create_course();
 
         // Call the WS using an unexisting h5pactivityid.
         $this->expectException(dml_missing_record_exception::class);
-        $result = get_h5pactivity_access_information::execute($activity->id + 1);
+        $result = get_h5pactivity_access_information::execute(1);
     }
 }
\ No newline at end of file
diff --git a/repository/contentbank/tests/behat/file_update.feature b/repository/contentbank/tests/behat/file_update.feature
new file mode 100644 (file)
index 0000000..96cb40a
--- /dev/null
@@ -0,0 +1,103 @@
+@repository @repository_contentbank @javascript @core_h5p
+Feature: Updating a file in the content bank after using in a course
+  In order to use file alias
+  As a user
+  Updated files must update references when is an alias
+
+  Background:
+    Given the following "categories" exist:
+      | name      | category | idnumber |
+      | Category1 | 0        | CAT1     |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course1  | C1        | CAT1     |
+    And the following "contentbank content" exist:
+      | contextlevel | reference | contenttype     | user  | contentname | filepath                                  |
+      | Course       | C1        | contenttype_h5p | admin | package.h5p | /h5p/tests/fixtures/guess-the-answer.h5p  |
+    And the following "activities" exist:
+      | activity | name       | intro      | introformat | course | content  | contentformat | idnumber |
+      | page     | PageName1  | PageDesc1  | 1           | C1     | H5Ptest  | 1             | 1        |
+    And I log in as "admin"
+
+  Scenario: Referenced files updates alias as well
+    Given I am on "Course1" course homepage
+    And I follow "PageName1"
+    And I navigate to "Edit settings" in current page administration
+    And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
+    And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
+    And I select "Content bank" repository in file picker
+    And I click on "package.h5p" "file" in repository content area
+    And I click on "Create an alias/shortcut to the file" "radio"
+    And I click on "Select this file" "button"
+    And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue"
+    And I wait until the page is ready
+    And I click on "Save and display" "button"
+    And I switch to "h5p-iframe" class iframe
+    And I switch to "h5p-iframe" class iframe
+    And I should see "Press here to reveal answer"
+    And I switch to the main frame
+    # Now edit the content in the content bank.
+    When I am on "Course1" course homepage with editing mode on
+    And I add the "Navigation" block if not present
+    And I expand "Site pages" node
+    And I click on "Content bank" "link"
+    And I click on "package.h5p" "link"
+    And I click on "Edit" "link"
+    And I wait until the page is ready
+    And I switch to "h5p-editor-iframe" class iframe
+    And I set the field "Title" to "Required title"
+    And I set the field "Descriptive solution label" to "This is a new text"
+    And I switch to the main frame
+    And I click on "Save" "button"
+    And I switch to "h5p-player" class iframe
+    And I switch to "h5p-iframe" class iframe
+    And I should see "This is a new text"
+    And I switch to the main frame
+    # Check the course page is updated.
+    Then I am on "Course1" course homepage
+    And I follow "PageName1"
+    And I switch to "h5p-iframe" class iframe
+    And I switch to "h5p-iframe" class iframe
+    And I should see "This is a new text"
+    And I switch to the main frame
+
+  Scenario: Copied files should not be updated if the original is edited
+    Given I am on "Course1" course homepage
+    And I follow "PageName1"
+    And I navigate to "Edit settings" in current page administration
+    And I click on "Insert H5P" "button" in the "#fitem_id_page" "css_element"
+    And I click on "Browse repositories..." "button" in the "Insert H5P" "dialogue"
+    And I select "Content bank" repository in file picker
+    And I click on "package.h5p" "file" in repository content area
+    And I click on "Select this file" "button"
+    And I click on "Insert H5P" "button" in the "Insert H5P" "dialogue"
+    And I wait until the page is ready
+    And I click on "Save and display" "button"
+    And I switch to "h5p-iframe" class iframe
+    And I switch to "h5p-iframe" class iframe
+    And I should see "Press here to reveal answer"
+    And I switch to the main frame
+    # Now edit the content in the content bank.
+    When I am on "Course1" course homepage with editing mode on
+    And I add the "Navigation" block if not present
+    And I expand "Site pages" node
+    And I click on "Content bank" "link"
+    And I click on "package.h5p" "link"
+    And I click on "Edit" "link"
+    And I wait until the page is ready
+    And I switch to "h5p-editor-iframe" class iframe
+    And I set the field "Title" to "Required title"
+    And I set the field "Descriptive solution label" to "This is a new text"
+    And I switch to the main frame
+    And I click on "Save" "button"
+    And I switch to "h5p-player" class iframe
+    And I switch to "h5p-iframe" class iframe
+    And I should see "This is a new text"
+    And I switch to the main frame
+    # Check the course page is not updated.
+    Then I am on "Course1" course homepage
+    And I follow "PageName1"
+    And I switch to "h5p-iframe" class iframe
+    And I switch to "h5p-iframe" class iframe
+    And I should see "Press here to reveal answer"
+    And I switch to the main frame
index 33a0f58..c95eb24 100644 (file)
@@ -10,6 +10,7 @@
         .region-main {
             flex: 0 0 100%;
             padding: 0 1rem;
+            max-width: 100%;
         }
 
         &.blocks-pre {
 }
 
 @include media-breakpoint-up(sm) {
-    .block_myoverview,
-    .block_recentlyaccesseditems {
-        .dashboard-card-deck {
-            .dashboard-card {
-                width: calc(33.33% - #{$card-gutter});
-            }
+    .dashboard-card-deck .dashboard-card {
+        width: calc(50% - #{$card-gutter});
+    }
+}
+
+@include media-breakpoint-up(md) {
+    .dashboard-card-deck .dashboard-card {
+        width: calc(50% - #{$card-gutter});
+    }
+    .blocks-post,
+    .blocks-pre {
+        .dashboard-card-deck .dashboard-card {
+            width: calc(100% - #{$card-gutter});
+        }
+    }
+}
+
+@include media-breakpoint-up(lg) {
+    .dashboard-card-deck .dashboard-card {
+        width: calc(33.33% - #{$card-gutter});
+    }
+    .blocks-post,
+    .blocks-pre {
+        .dashboard-card-deck .dashboard-card {
+            width: calc(50% - #{$card-gutter});
+        }
+    }
+}
+
+@include media-breakpoint-up(xl) {
+    .dashboard-card-deck .dashboard-card {
+        width: calc(25% - #{$card-gutter});
+    }
+    .blocks-post,
+    .blocks-pre {
+        .dashboard-card-deck .dashboard-card {
+            width: calc(33.33% - #{$card-gutter});
         }
     }
 }
index 6404916..d3cda53 100644 (file)
@@ -19430,7 +19430,8 @@ body {
     display: flex; }
     #page-content .region-main {
       flex: 0 0 100%;
-      padding: 0 1rem; }
+      padding: 0 1rem;
+      max-width: 100%; }
     #page-content.blocks-pre .columnleft {
       flex: 0 0 32%;
       order: -1;
@@ -19490,7 +19491,8 @@ body {
     display: flex; }
     #page-content .region-main {
       flex: 0 0 100%;
-      padding: 0 1rem; }
+      padding: 0 1rem;
+      max-width: 100%; }
     #page-content.blocks-pre .columnleft {
       flex: 0 0 25%;
       order: -1;
@@ -19550,7 +19552,8 @@ body {
     display: flex; }
     #page-content .region-main {
       flex: 0 0 100%;
-      padding: 0 1rem; }
+      padding: 0 1rem;
+      max-width: 100%; }
     #page-content.blocks-pre .columnleft {
       flex: 0 0 20%;
       order: -1;
@@ -19615,8 +19618,28 @@ body {
     /* stylelint-disable-line declaration-no-important */ } }
 
 @media (min-width: 576px) {
-  .block_myoverview .dashboard-card-deck .dashboard-card,
-  .block_recentlyaccesseditems .dashboard-card-deck .dashboard-card {
+  .dashboard-card-deck .dashboard-card {
+    width: calc(50% - 0.5rem); } }
+
+@media (min-width: 768px) {
+  .dashboard-card-deck .dashboard-card {
+    width: calc(50% - 0.5rem); }
+  .blocks-post .dashboard-card-deck .dashboard-card,
+  .blocks-pre .dashboard-card-deck .dashboard-card {
+    width: calc(100% - 0.5rem); } }
+
+@media (min-width: 992px) {
+  .dashboard-card-deck .dashboard-card {
+    width: calc(33.33% - 0.5rem); }
+  .blocks-post .dashboard-card-deck .dashboard-card,
+  .blocks-pre .dashboard-card-deck .dashboard-card {
+    width: calc(50% - 0.5rem); } }
+
+@media (min-width: 1200px) {
+  .dashboard-card-deck .dashboard-card {
+    width: calc(25% - 0.5rem); }
+  .blocks-post .dashboard-card-deck .dashboard-card,
+  .blocks-pre .dashboard-card-deck .dashboard-card {
     width: calc(33.33% - 0.5rem); } }
 
 @media (min-width: 768px) {