first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
@@ -0,0 +1,30 @@
@core @core_contentbank
Feature: Access permission to content Bank
In order to control access to content bank
As an admin
I need to be able to configure users' permissions
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | user1@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 |
Scenario: Admins access content bank
Given I log in as "admin"
And I am on "Course 1" course homepage
Then "Content bank" "link" should exist
Scenario: Editing teachers can access content bank at course level
Given I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
Then "Content bank" "link" should exist
Scenario: Editing teachers can't access content bank at system level
Given I log in as "teacher1"
Then "Content bank" "link" should not exist
@@ -0,0 +1,175 @@
@core @core_contentbank @core_h5p @contentbank_h5p @_file_upload @javascript
Feature: Copy content from the content bank
In order copy content from the content bank
As an admin
I need to be able to copy any content from the content bank
Background:
Given the following "contentbank content" exist:
| contextlevel | reference | contenttype | user | contentname | filepath |
| System | | contenttype_h5p | admin | content2copy.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
And I log in as "admin"
And I am on site homepage
And I turn editing mode on
And the following config values are set as admin:
| unaddableblocks | | theme_boost|
And I add the "Navigation" block if not present
And I configure the "Navigation" block
And I set the following fields to these values:
| Page contexts | Display throughout the entire site |
And I press "Save changes"
Scenario: Admins can copy content from the content bank
Given I log in as "admin"
And I am on site homepage
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link"
And I click on "content2copy.h5p" "link"
And I click on "More" "button"
And I click on "Copy content" "link" in the ".cb-toolbar-container" "css_element"
And I set the following fields to these values:
| Content name | |
And I click on "Save changes" "button"
Then I should see "Empty name is not allowed"
And I click on "OK" "button" in the "Error" "dialogue"
And I set the following fields to these values:
| Content name | Fill the blanks copy 1 |
And I click on "Save changes" "button"
Then I should see "Fill the blanks copy 1"
And I click on "Edit" "link"
And I switch to "h5p-editor-iframe" class iframe
Then the field "Title" matches value "Geography"
Scenario: Users without the required capability cannot copy content
Given the following "users" exist:
| username | firstname | lastname | email |
| manager | Max | Manager | man@example.com |
And the following "role assigns" exist:
| user | role | contextlevel | reference |
| manager | manager | System | |
And the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/contentbank:copycontent | Prohibit | manager | System | |
| moodle/contentbank:copyanycontent | Prohibit | manager | System | |
And I log out
And I log in as "manager"
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
And I should see "content2copy.h5p"
And I follow "content2copy.h5p"
And I click on "More" "button"
Then I should not see "Copy content"
Scenario: Users can't copy content if they don't have the required permission
Given I log in as "admin"
And I am on site homepage
Given I navigate to "H5P > Manage H5P content types" in site administration
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "H5P content type" filemanager
And I click on "Upload H5P content types" "button" in the "#fitem_id_uploadlibraries" "css_element"
And I upload "h5p/tests/fixtures/ipsums.h5p" file to "H5P content type" filemanager
And I click on "Upload H5P content types" "button" in the "#fitem_id_uploadlibraries" "css_element"
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | user1@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 | teacher1 | filltheblanks.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
When I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
And I follow "filltheblanks.h5p"
And I click on "More" "button"
Then I should see "Copy content"
And the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/contentbank:copycontent | Prohibit | editingteacher | System | |
And I reload the page
And I click on "More" "button"
Then I should not see "Copy content"
Scenario: Teachers can copy their own content in the content bank
Given I log in as "admin"
And I am on site homepage
Given I navigate to "H5P > Manage H5P content types" in site administration
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "H5P content type" filemanager
And I click on "Upload H5P content types" "button" in the "#fitem_id_uploadlibraries" "css_element"
And I upload "h5p/tests/fixtures/ipsums.h5p" file to "H5P content type" filemanager
And I click on "Upload H5P content types" "button" in the "#fitem_id_uploadlibraries" "css_element"
And 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 |
When I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
And I follow "ipsums.h5p"
And I click on "More" "button"
Then I should see "Copy content"
Scenario: Teachers can't copy content created by other users in the content bank
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 |
When I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
And I follow "filltheblanks.h5p"
And I click on "More" "button"
Then I should not see "Copy content"
Scenario: Teachers can copy any content created by other users in the content bank if allowed
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 the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/contentbank:copyanycontent | Allow | editingteacher | System | |
When I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link"
And I follow "filltheblanks.h5p"
And I click on "More" "button"
Then I should see "Copy content"
@@ -0,0 +1,84 @@
@core @core_contentbank @core_h5p @contentbank_h5p @javascript
Feature: Delete H5P file from the content bank
In order remove H5P content from the content bank
As an admin
I need to be able to delete any H5P content from the content bank
Background:
Given the following "user private file" exists:
| user | admin |
| filepath | h5p/tests/fixtures/filltheblanks.h5p |
And I am on the "Content bank" page logged in as "admin"
And I click on "Upload" "link"
And I click on "Choose a file..." "button"
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
And I click on "filltheblanks.h5p" "link"
And I set the field "Save as" to "content2delete.h5p"
And I click on "Select this file" "button"
And I click on "Save changes" "button"
Scenario: Admins can delete content from the content bank
Given I wait "2" seconds
And I click on "More" "button"
And I should see "Delete"
And I click on "Delete" "link"
And I should see "Are you sure you want to delete the content 'content2delete.h5p'"
And I should not see "The content will only be deleted from the content bank"
And I click on "Cancel" "button" in the "Delete content" "dialogue"
Then I should see "content2delete.h5p"
And I wait "2" seconds
And I click on "More" "button"
And I click on "Delete" "link" in the ".cb-toolbar-container" "css_element"
And I click on "Delete" "button" in the "Delete content" "dialogue"
And I wait until the page is ready
And I should see "Content deleted."
And I should not see "content2delete.h5p"
Scenario: Users without the required capability can only delete their own content
Given the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/contentbank:deleteanycontent | Prohibit | manager | System | |
And the following "users" exist:
| username | firstname | lastname | email |
| manager | Max | Manager | man@example.com |
And the following "role assigns" exist:
| user | role | contextlevel | reference |
| manager | manager | System | |
And the following "user private file" exists:
| user | manager |
| filepath | h5p/tests/fixtures/find-the-words.h5p |
When I am on the "Content bank" page logged in as "manager"
And I should see "content2delete.h5p"
And I follow "content2delete.h5p"
And I wait "2" seconds
And I click on "More" "button"
Then I should not see "Delete"
And I am on the "Content bank" page
And I click on "Upload" "link"
And I click on "Choose a file..." "button"
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
And I click on "find-the-words.h5p" "link"
And I click on "Select this file" "button"
And I click on "Save changes" "button"
And I wait "2" seconds
And I click on "More" "button"
And I should see "Delete"
Scenario: The number of times a content is used is displayed before removing it
Given I am on the "My private files" page
And I click on "Add..." "button"
And I select "Content bank" repository in file picker
And I click on "content2delete.h5p" "file" in repository content area
And I click on "Link to the file" "radio"
And I click on "Select this file" "button"
And I click on "Save changes" "button"
And I am on the "Content bank" page
And I follow "content2delete.h5p"
And I wait "2" seconds
And I click on "More" "button"
And I click on "Delete" "link" in the ".cb-toolbar-container" "css_element"
Then I should see "Are you sure you want to delete the content 'content2delete.h5p'"
And I should see "The content will only be deleted from the content bank"
And I click on "Delete" "button" in the "Delete content" "dialogue"
And I should see "Content deleted."
And I should not see "content2delete.h5p"
@@ -0,0 +1,63 @@
@core @core_contentbank @core_h5p @contentbank_h5p @_file_upload @javascript
Feature: Download H5P content from the content bank
In order export H5P content from the content bank
As an admin
I need to be able to download any H5P content from the content bank
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| manager | Max | Manager | man@example.com |
And the following "role assigns" exist:
| user | role | contextlevel | reference |
| manager | manager | System | |
And the following "contentbank content" exist:
| contextlevel | reference | contenttype | user | contentname | filepath |
| System | | contenttype_h5p | admin | filltheblanksadmin.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| System | | contenttype_h5p | manager | filltheblanksmanager.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
And I log in as "admin"
And I am on site homepage
And I turn editing mode on
And the following config values are set as admin:
| unaddableblocks | | theme_boost|
And I add the "Navigation" block if not present
And I configure the "Navigation" block
And I set the following fields to these values:
| Page contexts | Display throughout the entire site |
And I press "Save changes"
Scenario: Admins can download content from the content bank
Given I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
And I follow "filltheblanksmanager.h5p"
And I click on "More" "button"
And I should see "Download"
When I click on "Download" "link"
Then I should see "filltheblanksmanager.h5p"
Scenario: Users can download content created by different users
Given the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/contentbank:manageanycontent | Prohibit | manager | System | |
And I log out
And I log in as "manager"
When I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
And I should see "filltheblanksadmin.h5p"
And I follow "filltheblanksadmin.h5p"
And I click on "More" "button"
Then I should see "Download"
And I should not see "Rename"
Scenario: Users without the required capability cannot download content
Given the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/contentbank:downloadcontent | Prohibit | manager | System | |
And I log out
And I log in as "manager"
When I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
And I should see "filltheblanksmanager.h5p"
And I follow "filltheblanksmanager.h5p"
And I click on "More" "button"
Then I should not see "Download"
@@ -0,0 +1,199 @@
@core @core_contentbank @core_h5p @contentbank_h5p @_file_upload @javascript
Feature: Content bank use editor feature
In order to add/edit content
As a user
I need to be able to access the edition options
Background:
Given I log in as "admin"
And I am on site homepage
And I turn editing mode on
And the following config values are set as admin:
| unaddableblocks | | theme_boost|
And I add the "Navigation" block if not present
And I configure the "Navigation" block
And I set the following fields to these values:
| Page contexts | Display throughout the entire site |
And I press "Save changes"
Scenario: Users see the Add button disabled if there is no content type available for creation
Given I click on "Site pages" "list_item" in the "Navigation" "block"
When I click on "Content bank" "link"
Then the "[data-action=Add-content]" "css_element" should be disabled
Scenario: Users can see the Add button if there is content type available for creation
Given the following "user private file" exists:
| user | admin |
| filepath | h5p/tests/fixtures/filltheblanks.h5p |
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
And I click on "Upload" "link"
And I click on "Choose a file..." "button"
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
And I click on "filltheblanks.h5p" "link"
And I click on "Select this file" "button"
And I click on "Save changes" "button"
When I click on "Content bank" "link"
And I click on "filltheblanks.h5p" "link"
And I click on "Exit" "link"
Then I click on "[data-action=Add-content]" "css_element"
And I should see "Fill in the Blanks"
Scenario: Users can edit content if they have the required permission
Given the following "user private file" exists:
| user | admin |
| filepath | h5p/tests/fixtures/filltheblanks.h5p |
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
And I click on "Upload" "link"
And I click on "Choose a file..." "button"
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
And I click on "filltheblanks.h5p" "link"
And I click on "Select this file" "button"
And I click on "Save changes" "button"
When I click on "Content bank" "link"
And I click on "filltheblanks.h5p" "link"
Then I click on "Edit" "link"
And I switch to "h5p-editor-iframe" class iframe
And I switch to the main frame
And I click on "Cancel" "button"
And "filltheblanks.h5p" "heading" should exist
Scenario: Users can create new content if they have the required permission
Given I navigate to "H5P > Manage H5P content types" in site administration
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "H5P content type" filemanager
And I click on "Upload H5P content types" "button" in the "#fitem_id_uploadlibraries" "css_element"
And I should see "H5P content types uploaded successfully"
And I click on "Site pages" "list_item" in the "Navigation" "block"
When I click on "Content bank" "link" in the "Navigation" "block"
And I click on "[data-action=Add-content]" "css_element"
Then I click on "Fill in the Blanks" "link"
And I switch to "h5p-editor-iframe" class iframe
And I switch to the main frame
And I click on "Cancel" "button"
Scenario: Users can't edit content if they don't have the required permission
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | user1@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 I navigate to "H5P > Manage H5P content types" in site administration
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "H5P content type" filemanager
And I click on "Upload H5P content types" "button" in the "#fitem_id_uploadlibraries" "css_element"
And I should see "H5P content types uploaded successfully"
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link"
And "[data-action=Add-content]" "css_element" should exist
When the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/contentbank:useeditor | Prohibit | editingteacher | System | |
And I reload the page
Then "[data-action=Add-content]" "css_element" should not exist
Scenario: Users can edit content and save changes
Given the following "contentbank content" exist:
| contextlevel | reference | contenttype | user | contentname | filepath |
| System | | contenttype_h5p | admin | filltheblanks.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
And I click on "filltheblanks.h5p" "link"
And I click on "Edit" "link"
And I switch to "h5p-editor-iframe" class iframe
And the field "Title" matches value "Geography"
And I set the field "Title" to "New title"
And I switch to the main frame
When I click on "Save" "button"
And "filltheblanks.h5p" "heading" should exist
And I click on "Edit" "link"
And I switch to "h5p-editor-iframe" class iframe
Then the field "Title" matches value "New title"
Scenario: Teachers can edit their own content in the content bank
Given I navigate to "H5P > Manage H5P content types" in site administration
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "H5P content type" filemanager
And I click on "Upload H5P content types" "button" in the "#fitem_id_uploadlibraries" "css_element"
And I upload "h5p/tests/fixtures/ipsums.h5p" file to "H5P content type" filemanager
And I click on "Upload H5P content types" "button" in the "#fitem_id_uploadlibraries" "css_element"
And 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 |
When I log out
And I log in as "teacher1"
And I am on "Course 1" 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"
Scenario: Teachers can't edit content created by other users in the content bank
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 |
When I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I expand "Site pages" node
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 the "Course 1" "course copy" page
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 navigate to "Content bank" in current page administration
And I follow "filltheblanks.h5p"
Then "Edit" "link" should not exist in the "region-main" "region"
+75
View File
@@ -0,0 +1,75 @@
@core @core_contentbank @core_h5p @contentbank_h5p @_switch_iframe @javascript
Feature: Confirm content bank events are triggered
In order to log content bank actions
As an admin
I need to be able to check triggered events
Background:
Given the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "contentbank content" exist:
| contextlevel | reference | contenttype | user | contentname | filepath |
| Course | C1 | contenttype_h5p | admin | Existing | /h5p/tests/fixtures/filltheblanks.h5p |
And the following "user private file" exists:
| user | admin |
| filepath | h5p/tests/fixtures/filltheblanks.h5p |
And the following config values are set as admin:
| unaddableblocks | | theme_boost|
And I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
And I add the "Navigation" block if not present
Scenario: Content created and uploaded events when uploading a content file
Given I navigate to "Reports > Live logs" in site administration
And I should not see "Content uploaded"
And I should not see "Content created"
And I am on "Course 1" course homepage
And I expand "Site pages" node
And I click on "Content bank" "link"
When I click on "Upload" "link"
And I click on "Choose a file..." "button"
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
And I click on "filltheblanks.h5p" "link"
And I click on "Select this file" "button"
And I click on "Save changes" "button"
And I navigate to "Reports > Live logs" in site administration
Then I should see "Content uploaded"
And I should see "Content created"
Scenario: Content viewed event
Given I navigate to "Reports > Live logs" in site administration
And I should not see "Content viewed"
And I am on "Course 1" course homepage
And I expand "Site pages" node
And I click on "Content bank" "link"
When I click on "Existing" "link"
And I navigate to "Reports > Live logs" in site administration
Then I should see "Content viewed"
Scenario: Content deleted event
Given I navigate to "Reports > Live logs" in site administration
And I should not see "Content deleted"
And I am on "Course 1" course homepage
And I expand "Site pages" node
And I click on "Content bank" "link"
And I click on "Existing" "link"
And I click on "More" "button"
When I click on "Delete" "link"
And I click on "Delete" "button" in the "Delete content" "dialogue"
And I navigate to "Reports > Live logs" in site administration
Then I should see "Content deleted"
Scenario: Content updated event when renaming
Given I navigate to "Reports > Live logs" in site administration
And I should not see "Content updated"
And I am on "Course 1" course homepage
And I expand "Site pages" node
And I click on "Content bank" "link"
And I click on "Existing" "link"
And I click on "More" "button"
When I click on "Rename" "link"
And I set the field "Content name" to "New name"
And I click on "Rename" "button"
And I navigate to "Reports > Live logs" in site administration
Then I should see "Content updated"
@@ -0,0 +1,101 @@
@core @core_contentbank @core_h5p @contentbank_h5p @_file_upload @javascript
Feature: Navigate to different contexts in the content bank
In order to navigate easily in the content bank
I need to be able to view dropdown with all allowed contexts in the content bank
Background:
Given I log in as "admin"
And the following "categories" exist:
| name | category | idnumber |
| Cat 1 | 0 | CAT1 |
| Cat 2 | 0 | CAT2 |
And the following "courses" exist:
| fullname | shortname | category |
| Course 0 | C0 | |
| Course 1 | C1 | CAT1 |
| Course 2 | C2 | CAT2 |
And I navigate to "H5P > Manage H5P content types" in site administration
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "H5P content type" filemanager
And I click on "Upload H5P content types" "button" in the "#fitem_id_uploadlibraries" "css_element"
And the following "contentbank content" exist:
| contextlevel | reference | contenttype | user | contentname | filepath |
| System | | contenttype_h5p | admin | santjordi.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| Category | CAT1 | contenttype_h5p | admin | santjordi_rose.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| Category | CAT2 | contenttype_h5p | admin | SantJordi_book | /h5p/tests/fixtures/filltheblanks.h5p |
| Course | C0 | contenttype_h5p | admin | Dragon.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| Course | C1 | contenttype_h5p | admin | princess.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| Course | C2 | contenttype_h5p | admin | mathsbook.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
Scenario: Admins can view and navigate to all the contexts in the content bank
Given I am on site homepage
And I turn editing mode on
And the following config values are set as admin:
| unaddableblocks | | theme_boost|
And I add the "Navigation" block if not present
And I expand "Site pages" node
When I click on "Content bank" "link"
And the "Choose course or category" select box should contain "System"
And the "Choose course or category" select box should contain "Cat 1"
And the "Choose course or category" select box should contain "Cat 2"
And the "Choose course or category" select box should contain "Course 0"
And the "Choose course or category" select box should contain "Course 1"
And the "Choose course or category" select box should contain "Course 2"
And I should see "santjordi.h5p"
And I should not see "santjordi_rose.h5p"
And I should not see "Dragon.h5p"
And I set the field "Choose course or category" to "Cat 1"
Then I should not see "santjordi.h5p"
And I should see "santjordi_rose.h5p"
And I should not see "Dragon.h5p"
And I set the field "Choose course or category" to "Course 0"
And I should not see "santjordi.h5p"
And I should not see "santjordi_rose.h5p"
And I should see "Dragon.h5p"
Scenario: Teachers can view and navigate to contexts in the content bank based on their permissions
Given the following "users" exist:
| username | firstname | lastname |
| teacher | Joseba | Cilarte |
And the following "course enrolments" exist:
| user | course | role |
| teacher | C0 | editingteacher |
| teacher | C1 | editingteacher |
And I log out
And I am on the "C0" "Course" page logged in as "teacher"
And I turn editing mode on
And the following config values are set as admin:
| unaddableblocks | | theme_boost|
And I add the "Navigation" block if not present
And I expand "Site pages" node
When I click on "Content bank" "link"
And the "Choose course or category" select box should contain "Course 0"
And the "Choose course or category" select box should contain "Course 1"
And the "Choose course or category" select box should not contain "System"
And the "Choose course or category" select box should not contain "Cat 1"
And the "Choose course or category" select box should not contain "Cat 2"
And the "Choose course or category" select box should not contain "Course 2"
And I should see "Dragon.h5p"
And I should not see "princess.h5p"
And I should not see "santjordi.h5p"
And I should not see "santjordi_rose.h5p"
And I set the field "Choose course or category" to "Course 1"
Then I should not see "Dragon.h5p"
And I should see "princess.h5p"
And I should not see "santjordi.h5p"
And I should not see "santjordi_rose.h5p"
And the following "role assigns" exist:
| user | role | contextlevel | reference |
| teacher | manager | Category | CAT1 |
And I am on the "C0" "Course" page logged in as "teacher"
And I expand "Site pages" node
When I click on "Content bank" "link"
And the "Choose course or category" select box should contain "Course 0"
And the "Choose course or category" select box should contain "Course 1"
And the "Choose course or category" select box should contain "Cat 1"
And the "Choose course or category" select box should not contain "System"
And the "Choose course or category" select box should not contain "Cat 2"
And the "Choose course or category" select box should not contain "Course 2"
And I should see "Dragon.h5p"
And I set the field "Choose course or category" to "Cat 1"
And I should not see "Dragon.h5p"
And I should see "santjordi_rose.h5p"
@@ -0,0 +1,62 @@
@core @core_contentbank @core_h5p @contentbank_h5p @_file_upload @javascript
Feature: Search content in the content bank
In order to find easily content in the content bank
As an admin
I need to be able to search content in the content bank
Background:
Given I log in as "admin"
And I navigate to "H5P > Manage H5P content types" in site administration
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "H5P content type" filemanager
And I click on "Upload H5P content types" "button" in the "#fitem_id_uploadlibraries" "css_element"
And the following "contentbank content" exist:
| contextlevel | reference | contenttype | user | contentname | filepath |
| System | | contenttype_h5p | admin | santjordi.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| System | | contenttype_h5p | admin | santjordi_rose.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| System | | contenttype_h5p | admin | SantJordi_book | /h5p/tests/fixtures/filltheblanks.h5p |
| System | | contenttype_h5p | admin | Dragon_santjordi.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| System | | contenttype_h5p | admin | princess.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| System | | contenttype_h5p | admin | mathsbook.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| System | | contenttype_h5p | admin | historybook.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| System | | contenttype_h5p | admin | santvicenc.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
Scenario: Admins can search content in the content bank
Given I am on site homepage
And I turn editing mode on
And the following config values are set as admin:
| unaddableblocks | | theme_boost|
And I add the "Navigation" block if not present
And I expand "Site pages" node
And I click on "Content bank" "link"
And I should see "santjordi.h5p"
And "Clear search input" "button" should not be visible
And I should not see "items found"
When I set the field "Search" to "book"
# Waiting for the animation to show the button to finish.
And I wait "1" seconds
Then "Clear search input" "button" should be visible
And I should see "3 items found"
And I should see "SantJordi_book"
And I should see "mathsbook.h5p"
And I should see "historybook.h5p"
And I set the field "Search" to "sant"
And "Clear search input" "button" should be visible
And I should see "5 items found"
And I set the field "Search" to "santjordi"
And I should see "4 items found"
And I should see "santjordi.h5p"
And I should see "santjordi_rose.h5p"
And I should see "SantJordi_book"
And I should see "Dragon_santjordi.h5p"
And I click on "Clear search input" "button"
# Waiting for the animation to hide the button to finish.
And I wait "1" seconds
And "Clear search input" "button" should not be visible
And I should not see "items found"
And I set the field "Search" to ".h5p"
# Waiting for the animation to show the button to finish.
And I wait "1" seconds
And "Clear search input" "button" should be visible
And I should see "7 items found"
And I set the field "Search" to "friend"
And I should see "0 items found"
@@ -0,0 +1,59 @@
@core @core_contentbank @core_h5p @contentbank_h5p @_file_upload @javascript
Feature: Sort content in the content bank
In order to temporarily organise the content of the content bank
As an admin
I need to be able to sort the content bank in various ways
Background:
Given I log in as "admin"
And I navigate to "H5P > Manage H5P content types" in site administration
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "H5P content type" filemanager
And I click on "Upload H5P content types" "button" in the "#fitem_id_uploadlibraries" "css_element"
And the following "users" exist:
| username | firstname | lastname | email |
| manager | Max | Manager | man@example.com |
And the following "role assigns" exist:
| user | role | contextlevel | reference |
| manager | manager | System | |
And the following "contentbank content" exist:
| contextlevel | reference | contenttype | user | contentname | filepath |
| System | | contenttype_h5p | admin | Dragon_santjordi.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| System | | contenttype_h5p | admin | mathsbook.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| System | | contenttype_h5p | manager | historybook.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| System | | contenttype_h5p | admin | santjordi.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| System | | contenttype_h5p | admin | santjordi_rose.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
| System | | contenttype_h5p | admin | SantJordi_book | /h5p/tests/fixtures/filltheblanks.h5p |
Scenario: Admins can order content in the content bank
Given I am on site homepage
And I turn editing mode on
And the following config values are set as admin:
| unaddableblocks | | theme_boost|
And I add the "Navigation" block if not present
And I expand "Site pages" node
And I click on "Content bank" "link"
When I click on "Display content bank with file details" "button"
And I click on "Sort by Content name ascending" "button"
And "Dragon_santjordi.h5p" "text" should appear before "historybook.h5p" "text"
And "historybook.h5p" "text" should appear before "mathsbook.h5p" "text"
And "SantJordi_book" "text" should appear before "santjordi_rose.h5p" "text"
And I click on "Sort by Content name descending" "button"
And "historybook.h5p" "text" should appear before "Dragon_santjordi.h5p" "text"
And "mathsbook.h5p" "text" should appear before "historybook.h5p" "text"
Then "santjordi_rose.h5p" "text" should appear before "SantJordi_book" "text"
Scenario: Admins can order content depending on the author
Given I am on site homepage
And I turn editing mode on
And the following config values are set as admin:
| unaddableblocks | | theme_boost|
And I add the "Navigation" block if not present
And I expand "Site pages" node
And I click on "Content bank" "link"
When I click on "Display content bank with file details" "button"
Then I click on "Sort by Author ascending" "button"
And "Dragon_santjordi.h5p" "text" should appear before "historybook.h5p" "text"
And "santjordi_rose.h5p" "text" should appear before "historybook" "text"
And I click on "Sort by Author descending" "button"
And "historybook.h5p" "text" should appear before "Dragon_santjordi.h5p" "text"
And "historybook.h5p" "text" should appear before "santjordi_rose" "text"
@@ -0,0 +1,67 @@
@core @core_contentbank @core_h5p @contentbank_h5p @javascript
Feature: Store the content bank view preference
In order to consistantly view the content bank in icons or details view
As an admin
I need to be able to store my view preference
Background:
Given the following "user private files" exist:
| user | filepath |
| admin | h5p/tests/fixtures/filltheblanks.h5p |
| admin | h5p/tests/fixtures/greeting-card.h5p |
And I log in as "admin"
And I am on site homepage
And I turn editing mode on
And the following config values are set as admin:
| unaddableblocks | | theme_boost|
And I add the "Navigation" block if not present
And I configure the "Navigation" block
And I set the following fields to these values:
| Page contexts | Display throughout the entire site |
And I press "Save changes"
And I expand "Site pages" node
And I click on "Content bank" "link"
And I click on "Upload" "link"
And I click on "Choose a file..." "button"
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
And I click on "filltheblanks.h5p" "link"
And I set the field "Save as" to "fib.h5p"
And I click on "Select this file" "button"
And I click on "Save changes" "button"
And I click on "Content bank" "link"
And I click on "Upload" "link"
And I click on "Choose a file..." "button"
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
And I click on "greeting-card.h5p" "link"
And I set the field "Save as" to "greetingcard.h5p"
And I click on "Select this file" "button"
And I click on "Save changes" "button"
Scenario: There are several views for displaying contents into the content bank
Given I am on site homepage
And I expand "Site pages" node
And I click on "Content bank" "link"
When I click on "Display content bank with file details" "button"
Then I should see "Last modified"
And I follow "greetingcard.h5p"
And I click on "Content bank" "link"
And I should see "Last modified"
And I click on "Display content bank with icons" "button"
And I follow "greetingcard.h5p"
And I click on "Content bank" "link"
And I should not see "Last modified"
Scenario: Display the number of times a content is used in file details view
Given I am on the "My private files" page
And I click on "Add..." "button"
And I select "Content bank" repository in file picker
And I click on "fib.h5p" "file" in repository content area
And I click on "Link to the file" "radio"
And I click on "Select this file" "button"
And I click on "Save changes" "button"
When I am on site homepage
And I expand "Site pages" node
And I click on "Content bank" "link"
And I click on "Display content bank with file details" "button"
Then I should see "1" in the "[data-file='fib.h5p'] .cb-uses" "css_element"
And I should see "0" in the "[data-file='greetingcard.h5p'] .cb-uses" "css_element"
+153
View File
@@ -0,0 +1,153 @@
@core @core_contentbank @core_h5p @contentbank_h5p @_file_upload @javascript
Feature: Make content public or unlisted
In order to make content public or unlisted
As a user
I need to be able to access the edition options
Background:
Given I log in as "admin"
And I am on site homepage
And I turn editing mode on
And the following config values are set as admin:
| unaddableblocks | | theme_boost|
And I add the "Navigation" block if not present
And I configure the "Navigation" block
And I set the following fields to these values:
| Page contexts | Display throughout the entire site |
And I press "Save changes"
And I navigate to "H5P > Manage H5P content types" in site administration
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "H5P content type" filemanager
And I click on "Upload H5P content types" "button" in the "#fitem_id_uploadlibraries" "css_element"
Scenario: Users can make their content public or unlisted
Given the following "contentbank content" exist:
| contextlevel | reference | contenttype | user | contentname | filepath | visibility |
| System | | contenttype_h5p | admin | filltheblanks.h5p | /h5p/tests/fixtures/filltheblanks.h5p | 1 |
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
And I click on "filltheblanks.h5p" "link"
And I wait until the page is ready
And "filltheblanks.h5p (Unlisted)" "heading" should not exist
And I click on "More" "button"
And I should see "Make unlisted"
And I click on "Make unlisted" "link"
And I wait until the page is ready
Then "filltheblanks.h5p (Unlisted)" "heading" should exist
And I click on "More" "button"
And I should see "Make public"
Scenario: Unlisted content cannot be seen by other users
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| teacher2 | Teacher | 2 | teacher2@example.com |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| teacher2 | C1 | editingteacher |
And the following "contentbank content" exist:
| contextlevel | reference | contenttype | user | contentname | filepath | visibility |
| Course | C1 | contenttype_h5p | teacher1 | filltheblanks.h5p | /h5p/tests/fixtures/filltheblanks.h5p | 2 |
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
Then I should see "filltheblanks.h5p (Unlisted)"
And I log out
And I log in as "teacher2"
And I am on "Course 1" course homepage
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
Then I should not see "filltheblanks.h5p"
Scenario: Unlisted content is not found through search by other users
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| teacher2 | Teacher | 2 | teacher2@example.com |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| teacher2 | C1 | editingteacher |
And the following "contentbank content" exist:
| contextlevel | reference | contenttype | user | contentname | filepath | visibility |
| Course | C1 | contenttype_h5p | teacher1 | filltheblanks.h5p | /h5p/tests/fixtures/filltheblanks.h5p | 2 |
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
And I set the field "Search" to "filltheblanks.h5p"
And I should see "filltheblanks.h5p"
And I log out
And I log in as "teacher2"
And I am on "Course 1" course homepage
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
When I set the field "Search" to "filltheblanks.h5p"
Then I should not see "filltheblanks.h5p"
Scenario: Managers can see other users' unlisted content
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| manager1 | Manager | 1 | manager1@example.com |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| manager1 | C1 | manager |
And the following "contentbank content" exist:
| contextlevel | reference | contenttype | user | contentname | filepath | visibility |
| Course | C1 | contenttype_h5p | teacher1 | filltheblanks.h5p | /h5p/tests/fixtures/filltheblanks.h5p | 2 |
And I log out
And I log in as "manager1"
And I am on "Course 1" course homepage
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
And I should see "filltheblanks.h5p (Unlisted)"
And I set the field "Search" to "filltheblanks.h5p"
And I should see "filltheblanks.h5p (Unlisted)"
@_file_upload
Scenario: Default content visibility can be set to unlisted
Given the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And I set the following administration settings values:
| Default content visibility | 2 |
And I am on "Course 1" course homepage
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
And I click on "Upload" "link"
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "Upload content" filemanager
And I click on "Save changes" "button"
Then "filltheblanks.h5p (Unlisted)" "heading" should exist
@_file_upload
Scenario: User preference concerning content visibility overrides site-wide default content visibility
Given the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And I set the following administration settings values:
| Default content visibility | 2 |
And the following "user preferences" exist:
| user | preference | value |
| admin | core_contentbank_visibility | 1 |
And I am on "Course 1" course homepage
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
And I click on "Upload" "link"
And I upload "h5p/tests/fixtures/filltheblanks.h5p" file to "Upload content" filemanager
And I click on "Save changes" "button"
Then "filltheblanks.h5p" "heading" should exist
And "filltheblanks.h5p (Unlisted)" "heading" should not exist
+424
View File
@@ -0,0 +1,424 @@
<?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/>.
/**
* Test for content bank contenttype class.
*
* @package core_contentbank
* @category test
* @copyright 2020 Amaia Anabitarte <amaia@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_contentbank;
use stdClass;
use context_system;
use contenttype_testable\contenttype as contenttype;
/**
* Test for content bank contenttype class.
*
* @package core_contentbank
* @category test
* @copyright 2020 Amaia Anabitarte <amaia@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_contentbank\content
*
*/
class content_test extends \advanced_testcase {
/**
* Setup to ensure that fixtures are loaded.
*/
public static function setupBeforeClass(): void {
global $CFG;
require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_contenttype.php');
require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_content.php');
}
/**
* Tests for behaviour of get_name().
*
* @covers ::get_name
*/
public function test_get_name(): void {
$this->resetAfterTest();
// Create content.
$record = new stdClass();
$record->name = 'Test content';
$record->configdata = '';
$contenttype = new contenttype(context_system::instance());
$content = $contenttype->create_content($record);
$this->assertEquals($record->name, $content->get_name());
}
/**
* Data provider for test_set_name.
*
* @return array
*/
public function set_name_provider() {
return [
'Standard name' => ['New name', 'New name'],
'Name with digits' => ['Today is 17/04/2017', 'Today is 17/04/2017'],
'Name with symbols' => ['Follow us: @moodle', 'Follow us: @moodle'],
'Name with tags' => ['This is <b>bold</b>', 'This is bold'],
'Long name' => [str_repeat('a', 100), str_repeat('a', 100)],
'Too long name' => [str_repeat('a', 300), str_repeat('a', 255)],
'Empty name' => ['', 'Old name'],
'Blanks only' => [' ', 'Old name'],
];
}
/**
* Tests for 'set_name' behaviour.
*
* @dataProvider set_name_provider
* @param string $newname The name to set
* @param string $expected The name result
*
* @covers ::set_name
*/
public function test_set_name(string $newname, string $expected): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$oldname = "Old name";
$context = context_system::instance();
// Create content.
$record = new stdClass();
$record->name = $oldname;
$contenttype = new contenttype($context);
$content = $contenttype->create_content($record);
$this->assertEquals($oldname, $content->get_name());
$content->set_name($newname);
$this->assertEquals($expected, $content->get_name());
$record = $DB->get_record('contentbank_content', ['id' => $content->get_id()]);
$this->assertEquals($expected, $record->name);
}
/**
* Tests for behaviour of get_content_type().
*
* @covers ::get_content_type
*/
public function test_get_content_type(): void {
$this->resetAfterTest();
// Create content.
$record = new stdClass();
$record->name = 'Test content';
$record->configdata = '';
$contenttype = new contenttype(context_system::instance());
$content = $contenttype->create_content($record);
$this->assertEquals('contenttype_testable', $content->get_content_type());
}
/**
* Tests for 'configdata' behaviour.
*
* @covers ::set_configdata
*/
public function test_configdata_changes(): void {
$this->resetAfterTest();
$configdata = "{img: 'icon.svg'}";
// Create content.
$record = new stdClass();
$record->configdata = $configdata;
$contenttype = new contenttype(context_system::instance());
$content = $contenttype->create_content($record);
$this->assertEquals($configdata, $content->get_configdata());
$configdata = "{alt: 'Name'}";
$content->set_configdata($configdata);
$this->assertEquals($configdata, $content->get_configdata());
}
/**
* Tests for 'set_contextid' behaviour.
*
* @covers ::set_contextid
*/
public function test_set_contextid(): void {
$this->resetAfterTest();
$this->setAdminUser();
$context = context_system::instance();
$course = $this->getDataGenerator()->create_course();
$newcontext = \context_course::instance($course->id);
// Add some content to the content bank.
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$contents = $generator->generate_contentbank_data('contenttype_testable', 3, 0, $context);
$content = reset($contents);
$oldcontextid = $content->get_contextid();
$file = $content->get_file();
$this->assertEquals($oldcontextid, $file->get_contextid());
$this->assertEquals($context->id, $oldcontextid);
$this->assertNotEquals($newcontext->id, $oldcontextid);
$content->set_contextid($newcontext->id);
$file = $content->get_file();
$this->assertEquals($newcontext->id, $content->get_contextid());
$this->assertEquals($newcontext->id, $file->get_contextid());
}
/**
* Tests for set_visibility behaviour
*
* @covers ::set_visibility
*/
public function test_set_visibility(): void {
$this->resetAfterTest();
$this->setAdminUser();
$context = context_system::instance();
$oldvisibility = content::VISIBILITY_PUBLIC;
$newvisibility = content::VISIBILITY_UNLISTED;
$illegalvisibility = -1;
$record = new stdClass();
$record->visibility = $oldvisibility;
$contenttype = new contenttype($context);
$content = $contenttype->create_content($record);
$this->assertEquals($oldvisibility, $content->get_visibility());
$content->set_visibility($newvisibility);
$this->assertEquals($newvisibility, $content->get_visibility());
$content->set_visibility($illegalvisibility);
$this->assertEquals($newvisibility, $content->get_visibility());
}
/**
* Tests for 'import_file' behaviour when replacing a file.
*
* @covers ::import_file
*/
public function test_import_file_replace(): void {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
$context = context_system::instance();
// Add some content to the content bank.
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$contents = $generator->generate_contentbank_data('contenttype_testable', 3, 0, $context);
$content = reset($contents);
$originalfile = $content->get_file();
// Create a dummy file.
$filerecord = array(
'contextid' => $context->id,
'component' => 'contentbank',
'filearea' => 'draft',
'itemid' => $content->get_id(),
'filepath' => '/',
'filename' => 'example.txt'
);
$fs = get_file_storage();
$file = $fs->create_file_from_string($filerecord, 'Dummy content ');
$importedfile = $content->import_file($file);
$this->assertEquals($originalfile->get_filename(), $importedfile->get_filename());
$this->assertEquals($originalfile->get_filearea(), $importedfile->get_filearea());
$this->assertEquals($originalfile->get_filepath(), $importedfile->get_filepath());
$this->assertEquals($originalfile->get_mimetype(), $importedfile->get_mimetype());
$this->assertEquals($file->get_userid(), $importedfile->get_userid());
$this->assertEquals($file->get_contenthash(), $importedfile->get_contenthash());
}
/**
* Tests for 'import_file' behaviour when uploading a new file.
*
* @covers ::import_file
*/
public function test_import_file_upload(): void {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
$context = context_system::instance();
$type = new contenttype($context);
$record = (object)[
'name' => 'content name',
'usercreated' => $USER->id,
];
$content = $type->create_content($record);
// Create a dummy file.
$filerecord = array(
'contextid' => $context->id,
'component' => 'contentbank',
'filearea' => 'draft',
'itemid' => $content->get_id(),
'filepath' => '/',
'filename' => 'example.txt'
);
$fs = get_file_storage();
$file = $fs->create_file_from_string($filerecord, 'Dummy content ');
$importedfile = $content->import_file($file);
$this->assertEquals($file->get_filename(), $importedfile->get_filename());
$this->assertEquals($file->get_userid(), $importedfile->get_userid());
$this->assertEquals($file->get_mimetype(), $importedfile->get_mimetype());
$this->assertEquals($file->get_contenthash(), $importedfile->get_contenthash());
$this->assertEquals('public', $importedfile->get_filearea());
$this->assertEquals('/', $importedfile->get_filepath());
$contentfile = $content->get_file($file);
$this->assertEquals($importedfile->get_id(), $contentfile->get_id());
}
/**
* Tests for 'get_content_type_instance'
*
* @covers ::get_content_type_instance
*/
public function test_get_content_type_instance(): void {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
$context = context_system::instance();
$type = new contenttype($context);
$record = (object)[
'name' => 'content name',
'usercreated' => $USER->id,
];
$content = $type->create_content($record);
$contenttype = $content->get_content_type_instance();
$this->assertInstanceOf(get_class($type), $contenttype);
}
/**
* Tests for 'is_view_allowed'.
*
* @covers ::is_view_allowed
*/
public function test_is_view_allowed(): void {
$this->resetAfterTest();
$this->setAdminUser();
$context = context_system::instance();
$userauthor = $this->getDataGenerator()->create_user();
$userother = $this->getDataGenerator()->create_user();
$contenttype = new contenttype($context);
$unlistedrecord = new stdClass();
$unlistedrecord->visibility = content::VISIBILITY_UNLISTED;
$unlistedrecord->usercreated = $userauthor->id;
$unlistedcontent = $contenttype->create_content($unlistedrecord);
$publicrecord = new stdClass();
$publicrecord->visibility = content::VISIBILITY_PUBLIC;
$publicrecord->usercreated = $userauthor->id;
$publiccontent = $contenttype->create_content($publicrecord);
$this->setUser($userother);
$this->assertFalse($unlistedcontent->is_view_allowed());
$this->assertTrue($publiccontent->is_view_allowed());
$this->setUser($userauthor);
$this->assertTrue($unlistedcontent->is_view_allowed());
$this->assertTrue($publiccontent->is_view_allowed());
$this->setAdminUser();
$this->assertTrue($unlistedcontent->is_view_allowed());
$this->assertTrue($publiccontent->is_view_allowed());
}
/**
* Tests for 'get_uses' behaviour.
*
* @covers ::get_uses
*/
public function test_get_uses(): void {
$this->resetAfterTest();
$this->setAdminUser();
$context = context_system::instance();
// Add some content to the content bank.
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$contents = $generator->generate_contentbank_data('contenttype_testable', 3, 0, $context);
$content1 = array_shift($contents);
// Check content has no references for now.
$this->assertCount(0, $content1->get_uses());
// Add a link to the previous content.
$cbfile = $content1->get_file();
$cbrecord = array(
'contextid' => $cbfile->get_contextid(),
'component' => $cbfile->get_component(),
'filearea' => $cbfile->get_filearea(),
'itemid' => $cbfile->get_itemid(),
'filepath' => $cbfile->get_filepath(),
'filename' => $cbfile->get_filename(),
);
$fs = get_file_storage();
$ref = $fs->pack_reference($cbrecord);
$aliasrecord = new stdClass();
$aliasrecord->contextid = $context->id;
$aliasrecord->component = 'core';
$aliasrecord->filearea = 'phpunit';
$aliasrecord->filepath = '/foo/';
$aliasrecord->filename = 'one.txt';
$aliasrecord->itemid = 0;
$repos = \repository::get_instances(['type' => 'contentbank']);
$cbrepo = reset($repos);
$this->assertInstanceOf('repository', $cbrepo);
$alias = $fs->create_file_from_reference($aliasrecord, $cbrepo->id, $ref);
// Check content now has one reference (the previous alias).
$contentuses1 = $content1->get_uses();
$this->assertCount(1, $contentuses1);
$reffile = reset($contentuses1);
$this->assertEquals($alias, $reffile);
// Check a different content hasn't any reference.
$content2 = array_shift($contents);
$this->assertCount(0, $content2->get_uses());
}
}
+672
View File
@@ -0,0 +1,672 @@
<?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/>.
/**
* Test for extensions manager.
*
* @package core_contentbank
* @category test
* @copyright 2020 Amaia Anabitarte <amaia@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_contentbank;
defined('MOODLE_INTERNAL') || die();
use advanced_testcase;
use context_block;
use context_course;
use context_coursecat;
use context_module;
use context_system;
use context_user;
use Exception;
global $CFG;
require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_contenttype.php');
require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_content.php');
/**
* Test for extensions manager.
*
* @package core_contentbank
* @category test
* @copyright 2020 Amaia Anabitarte <amaia@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_contentbank\contentbank
*/
class contentbank_test extends advanced_testcase {
/**
* Setup to ensure that fixtures are loaded.
*/
public static function setupBeforeClass(): void {
global $CFG;
require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_contenttype.php');
}
/**
* Data provider for test_get_extension_supporter.
*
* @return array
*/
public function get_extension_provider() {
return [
'H5P file' => ['something.h5p', '.h5p'],
'PDF file' => ['something.pdf', '.pdf']
];
}
/**
* Tests for get_extension() function.
*
* @dataProvider get_extension_provider
* @param string $filename The filename given
* @param string $expected The extension of the file
*
* @covers ::get_extension
*/
public function test_get_extension(string $filename, string $expected): void {
$this->resetAfterTest();
$cb = new contentbank();
$extension = $cb->get_extension($filename);
$this->assertEquals($expected, $extension);
}
/**
* Data provider for test_load_context_supported_extensions.
*
* @return array
*/
public function get_extension_supporters_provider() {
return [
'H5P first' => [['.h5p' => ['h5p', 'testable']], '.h5p', 'h5p'],
'Testable first (but upload not implemented)' => [['.h5p' => ['testable', 'h5p']], '.h5p', 'h5p'],
];
}
/**
* Tests for get_extension_supporter() function with admin permissions.
*
* @dataProvider get_extension_supporters_provider
* @param array $supporters The content type plugin supporters for each extension
* @param string $extension The extension of the file given
* @param string $expected The supporter contenttype of the file
*
* @covers ::load_context_supported_extensions
*/
public function test_get_extension_supporter_for_admins(array $supporters, string $extension, string $expected): void {
$this->resetAfterTest();
$cb = new contentbank();
$systemcontext = context_system::instance();
// All contexts allowed for admins.
$this->setAdminUser();
$contextsupporters = $cb->load_context_supported_extensions($systemcontext);
$this->assertArrayHasKey($extension, $contextsupporters);
$this->assertEquals($expected, $contextsupporters[$extension]);
}
/**
* Tests for get_extension_supporter() function with user default permissions.
*
* @dataProvider get_extension_supporters_provider
* @param array $supporters The content type plugin supporters for each extension
* @param string $extension The extension of the file given
* @param string $expected The supporter contenttype of the file
*
* @covers ::load_context_supported_extensions
*/
public function test_get_extension_supporter_for_users(array $supporters, string $extension, string $expected): void {
$this->resetAfterTest();
$cb = new contentbank();
$systemcontext = context_system::instance();
// Set a user with no permissions.
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
// Users with no capabilities can't upload content.
$contextsupporters = $cb->load_context_supported_extensions($systemcontext);
$this->assertEquals([], $contextsupporters);
}
/**
* Tests for get_extension_supporter() function with teacher defaul permissions.
*
* @dataProvider get_extension_supporters_provider
* @param array $supporters The content type plugin supporters for each extension
* @param string $extension The extension of the file given
* @param string $expected The supporter contenttype of the file
*
* @covers ::load_context_supported_extensions
*/
public function test_get_extension_supporter_for_teachers(array $supporters, string $extension, string $expected): void {
$this->resetAfterTest();
$cb = new contentbank();
$course = $this->getDataGenerator()->create_course();
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
$this->setUser($teacher);
$coursecontext = context_course::instance($course->id);
// Teachers has permission in their context to upload supported by H5P content type.
$contextsupporters = $cb->load_context_supported_extensions($coursecontext);
$this->assertArrayHasKey($extension, $contextsupporters);
$this->assertEquals($expected, $contextsupporters[$extension]);
}
/**
* Tests for get_extension_supporter() function.
*
* @dataProvider get_extension_supporters_provider
* @param array $supporters The content type plugin supporters for each extension
* @param string $extension The extension of the file given
* @param string $expected The supporter contenttype of the file
*
* @covers ::get_extension_supporter
*/
public function test_get_extension_supporter(array $supporters, string $extension, string $expected): void {
$this->resetAfterTest();
$cb = new contentbank();
$systemcontext = context_system::instance();
$this->setAdminUser();
$supporter = $cb->get_extension_supporter($extension, $systemcontext);
$this->assertEquals($expected, $supporter);
}
/**
* Test the behaviour of search_contents().
*
* @dataProvider search_contents_provider
* @param string $search String to search.
* @param string $where Context where to search.
* @param int $expectedresult Expected result.
* @param array $contexts List of contexts where to create content.
*/
public function test_search_contents(?string $search, string $where, int $expectedresult, array $contexts = [],
array $contenttypes = null): void {
global $DB, $CFG;
$this->resetAfterTest();
$this->setAdminUser();
// Create users.
$managerroleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
$manager = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->role_assign($managerroleid, $manager->id);
// Create a category and a course.
$coursecat = $this->getDataGenerator()->create_category();
$course = $this->getDataGenerator()->create_course();
$existingcontexts = [];
$existingcontexts['system'] = \context_system::instance();
$existingcontexts['category'] = \context_coursecat::instance($coursecat->id);
$existingcontexts['course'] = \context_course::instance($course->id);
if (empty($where)) {
$contextid = 0;
} else {
$contextid = $existingcontexts[$where]->id;
}
// Add some content to the content bank.
$filepath = $CFG->dirroot . '/h5p/tests/fixtures/filltheblanks.h5p';
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
foreach ($contexts as $context) {
$contextinstance = $existingcontexts[$context];
$records = $generator->generate_contentbank_data('contenttype_h5p', 3,
$manager->id, $contextinstance, false, $filepath);
}
// Search for some content.
$cb = new contentbank();
$contents = $cb->search_contents($search, $contextid, $contenttypes);
$this->assertCount($expectedresult, $contents);
if (!empty($contents) && !empty($search)) {
foreach ($contents as $content) {
$this->assertStringContainsString($search, $content->get_name());
}
}
}
/**
* Data provider for test_search_contents().
*
* @return array
*/
public function search_contents_provider(): array {
return [
'Search all content in all contexts' => [
null,
'',
9,
['system', 'category', 'course']
],
'Search in all contexts for existing string in all contents' => [
'content',
'',
9,
['system', 'category', 'course']
],
'Search in all contexts for unexisting string in all contents' => [
'chocolate',
'',
0,
['system', 'category', 'course']
],
'Search in all contexts for existing string in some contents' => [
'1',
'',
3,
['system', 'category', 'course']
],
'Search in all contexts for existing string in some contents (create only 1 context)' => [
'1',
'',
1,
['system']
],
'Search in system context for existing string in all contents' => [
'content',
'system',
3,
['system', 'category', 'course']
],
'Search in category context for unexisting string in all contents' => [
'chocolate',
'category',
0,
['system', 'category', 'course']
],
'Search in course context for existing string in some contents' => [
'1',
'course',
1,
['system', 'category', 'course']
],
'Search in system context' => [
null,
'system',
3,
['system', 'category', 'course']
],
'Search in course context with existing content' => [
null,
'course',
3,
['system', 'category', 'course']
],
'Search in course context without existing content' => [
null,
'course',
0,
['system', 'category']
],
'Search in an empty contentbank' => [
null,
'',
0,
[]
],
'Search in a context in an empty contentbank' => [
null,
'system',
0,
[]
],
'Search for a string in an empty contentbank' => [
'content',
'',
0,
[]
],
'Search with unexisting content-type' => [
null,
'course',
0,
['system', 'category', 'course'],
['contenttype_unexisting'],
],
];
}
/**
* Test create_content_from_file function.
*
* @covers ::create_content_from_file
*/
public function test_create_content_from_file(): void {
global $USER, $CFG;
$this->resetAfterTest();
$this->setAdminUser();
$systemcontext = \context_system::instance();
$name = 'greeting-card.h5p';
// Create a dummy H5P file.
$dummyh5p = array(
'contextid' => $systemcontext->id,
'component' => 'contentbank',
'filearea' => 'public',
'itemid' => 1,
'filepath' => '/',
'filename' => $name,
'userid' => $USER->id
);
$path = $CFG->dirroot . '/h5p/tests/fixtures/' . $name;
$dummyh5pfile = \core_h5p\helper::create_fake_stored_file_from_path($path);
$cb = new contentbank();
$content = $cb->create_content_from_file($systemcontext, $USER->id, $dummyh5pfile);
$this->assertEquals('contenttype_h5p', $content->get_content_type());
$this->assertInstanceOf('\\contenttype_h5p\\content', $content);
$this->assertEquals($name, $content->get_name());
}
/**
* Test the behaviour of delete_contents().
*
* @covers ::delete_contents
*/
public function test_delete_contents(): void {
global $DB;
$this->resetAfterTest();
$cb = new \core_contentbank\contentbank();
// Create a category and two courses.
$systemcontext = context_system::instance();
$coursecat = $this->getDataGenerator()->create_category();
$coursecatcontext = context_coursecat::instance($coursecat->id);
$course1 = $this->getDataGenerator()->create_course();
$course1context = context_course::instance($course1->id);
$course2 = $this->getDataGenerator()->create_course();
$course2context = context_course::instance($course2->id);
// Add some content to the content bank.
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$systemcontent = $generator->generate_contentbank_data(null, 3, 0, $systemcontext);
$categorycontent = $generator->generate_contentbank_data(null, 3, 0, $coursecatcontext);
$course1content = $generator->generate_contentbank_data(null, 3, 0, $course1context);
$course2content = $generator->generate_contentbank_data(null, 3, 0, $course2context);
// Check the content has been created as expected.
$this->assertEquals(12, $DB->count_records('contentbank_content'));
// Check the system content is deleted as expected and the rest of the content is not.
$this->assertTrue($cb->delete_contents($systemcontext));
$this->assertEquals(0, $DB->count_records('contentbank_content', ['contextid' => $systemcontext->id]));
// And the rest of the context content exists.
$this->assertEquals(9, $DB->count_records('contentbank_content'));
// Check the course category content is deleted as expected and the rest of the content is not.
$this->assertTrue($cb->delete_contents($coursecatcontext));
$this->assertEquals(0, $DB->count_records('contentbank_content', ['contextid' => $coursecatcontext->id]));
// And the rest of the context content exists.
$this->assertEquals(6, $DB->count_records('contentbank_content'));
// Check the course content is deleted as expected and the rest of the content is not.
$this->assertTrue($cb->delete_contents($course1context));
$this->assertEquals(0, $DB->count_records('contentbank_content', ['contextid' => $course1context->id]));
// And the rest of the context content exists.
$this->assertEquals(3, $DB->count_records('contentbank_content'));
}
/**
* Test the behaviour of delete_contents() for empty content bank.
*
* @covers ::delete_contents
*/
public function test_delete_contents_for_empty_contentbank(): void {
$this->resetAfterTest();
$cb = new \core_contentbank\contentbank();
// Create a category and two courses.
$systemcontext = \context_system::instance();
$coursecat = $this->getDataGenerator()->create_category();
$coursecatcontext = \context_coursecat::instance($coursecat->id);
$course = $this->getDataGenerator()->create_course();
$coursecontext = \context_course::instance($course->id);
// Check there's no error when trying to delete content from an empty content bank.
$this->assertTrue($cb->delete_contents($systemcontext));
$this->assertTrue($cb->delete_contents($coursecatcontext));
$this->assertTrue($cb->delete_contents($coursecontext));
}
/**
* Test the behaviour of move_contents().
*
* @covers ::move_contents
*/
public function test_move_contents(): void {
global $DB;
$this->resetAfterTest();
$cb = new \core_contentbank\contentbank();
// Create a category and two courses.
$course1 = $this->getDataGenerator()->create_course();
$course1context = context_course::instance($course1->id);
$course2 = $this->getDataGenerator()->create_course();
$course2context = context_course::instance($course2->id);
// Add some content to the content bank.
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$course1content = $generator->generate_contentbank_data(null, 3, 0, $course1context);
$course2content = $generator->generate_contentbank_data(null, 3, 0, $course2context);
// Check the content has been created as expected.
$this->assertEquals(6, $DB->count_records('contentbank_content'));
$this->assertEquals(3, $DB->count_records('contentbank_content', ['contextid' => $course1context->id]));
// Check the content is moved to another context as expected and the rest of the content is not.
$this->assertTrue($cb->move_contents($course1context, $course2context));
$this->assertEquals(6, $DB->count_records('contentbank_content'));
$this->assertEquals(0, $DB->count_records('contentbank_content', ['contextid' => $course1context->id]));
$this->assertEquals(6, $DB->count_records('contentbank_content', ['contextid' => $course2context->id]));
}
/**
* Test the behaviour of move_contents() for empty content bank.
*
* @covers ::move_contents
*/
public function test_move_contents_for_empty_contentbank(): void {
$this->resetAfterTest();
$cb = new \core_contentbank\contentbank();
// Create a category and two courses.
$systemcontext = \context_system::instance();
$course = $this->getDataGenerator()->create_course();
$coursecontext = \context_course::instance($course->id);
// Check there's no error when trying to move content context from an empty content bank.
$this->assertTrue($cb->delete_contents($systemcontext, $coursecontext));
}
/**
* Data provider for get_contenttypes_with_capability_feature.
*
* @return array
*/
public function get_contenttypes_with_capability_feature_provider(): array {
return [
'no-contenttypes_enabled' => [
'contenttypesenabled' => [],
'contenttypescanfeature' => [],
],
'contenttype_enabled_noeditable' => [
'contenttypesenabled' => ['testable'],
'contenttypescanfeature' => [],
],
'contenttype_enabled_editable' => [
'contenttypesenabled' => ['testable'],
'contenttypescanfeature' => ['testable'],
],
'no-contenttype_enabled_editable' => [
'contenttypesenabled' => [],
'contenttypescanfeature' => ['testable'],
],
];
}
/**
* Tests for get_contenttypes_with_capability_feature() function.
*
* @dataProvider get_contenttypes_with_capability_feature_provider
* @param array $contenttypesenabled Content types enabled.
* @param array $contenttypescanfeature Content types the user has the permission to use the feature.
*
* @covers ::get_contenttypes_with_capability_feature
*/
public function test_get_contenttypes_with_capability_feature(array $contenttypesenabled, array $contenttypescanfeature): void {
$this->resetAfterTest();
$cb = new contentbank();
$plugins = [];
// Content types not enabled where the user has permission to use a feature.
if (empty($contenttypesenabled) && !empty($contenttypescanfeature)) {
$enabled = false;
// Mock core_plugin_manager class and the method get_plugins_of_type.
$pluginmanager = $this->getMockBuilder(\core_plugin_manager::class)
->disableOriginalConstructor()
->onlyMethods(['get_plugins_of_type'])
->getMock();
// Replace protected singletoninstance reference (core_plugin_manager property) with mock object.
$ref = new \ReflectionProperty(\core_plugin_manager::class, 'singletoninstance');
$ref->setValue(null, $pluginmanager);
// Return values of get_plugins_of_type method.
foreach ($contenttypescanfeature as $contenttypepluginname) {
$contenttypeplugin = new \stdClass();
$contenttypeplugin->name = $contenttypepluginname;
$contenttypeplugin->type = 'contenttype';
// Add the feature to the fake content type.
$classname = "\\contenttype_$contenttypepluginname\\contenttype";
$classname::$featurestotest = ['test2'];
$plugins[] = $contenttypeplugin;
}
// Set expectations and return values.
$pluginmanager->expects($this->once())
->method('get_plugins_of_type')
->with('contenttype')
->willReturn($plugins);
} else {
$enabled = true;
// Get access to private property enabledcontenttypes.
$rc = new \ReflectionClass(\core_contentbank\contentbank::class);
$rcp = $rc->getProperty('enabledcontenttypes');
foreach ($contenttypesenabled as $contenttypename) {
$plugins["\\contenttype_$contenttypename\\contenttype"] = $contenttypename;
// Add to the testable contenttype the feature to test.
if (in_array($contenttypename, $contenttypescanfeature)) {
$classname = "\\contenttype_$contenttypename\\contenttype";
$classname::$featurestotest = ['test2'];
}
}
// Set as enabled content types only those in the test.
$rcp->setValue($cb, $plugins);
}
$actual = $cb->get_contenttypes_with_capability_feature('test2', null, $enabled);
$this->assertEquals($contenttypescanfeature, array_values($actual));
}
/**
* Test the behaviour of get_content_from_id()
*
* @covers ::get_content_from_id
*/
public function test_get_content_from_id(): void {
$this->resetAfterTest();
$cb = new \core_contentbank\contentbank();
// Create a category and two courses.
$systemcontext = context_system::instance();
// Add some content to the content bank.
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$contents = $generator->generate_contentbank_data(null, 3, 0, $systemcontext);
$content = reset($contents);
// Get the content instance form id.
$newinstance = $cb->get_content_from_id($content->get_id());
$this->assertEquals($content->get_id(), $newinstance->get_id());
// Now produce and exception with an innexistent id.
$this->expectException(Exception::class);
$cb->get_content_from_id(0);
}
/**
* Test the behaviour of is_context_allowed().
*
* @covers ::is_context_allowed
*/
public function test_is_context_allowed(): void {
$this->resetAfterTest();
$cb = new contentbank();
// System context.
$this->assertTrue($cb->is_context_allowed(context_system::instance()));
// User context.
$user = $this->getDataGenerator()->create_user();
$this->assertFalse($cb->is_context_allowed(context_user::instance($user->id)));
// Category context.
$category = $this->getDataGenerator()->create_category();
$this->assertTrue($cb->is_context_allowed(context_coursecat::instance($category->id)));
// Course context.
$course = $this->getDataGenerator()->create_course(['category' => $category->id]);
$coursecontext = context_course::instance($course->id);
$this->assertTrue($cb->is_context_allowed($coursecontext));
// Module context.
$module = $this->getDataGenerator()->create_module('page', ['course' => $course->id]);
$this->assertFalse($cb->is_context_allowed(context_module::instance($module->cmid)));
// Block context.
$block = $this->getDataGenerator()->create_block('online_users', ['parentcontextid' => $coursecontext->id]);
$this->assertFalse($cb->is_context_allowed(context_block::instance($block->id)));
}
}
+669
View File
@@ -0,0 +1,669 @@
<?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/>.
namespace core_contentbank;
use stdClass;
use context_system;
use context_user;
use Exception;
use contenttype_testable\contenttype as contenttype;
/**
* Test for content bank contenttype class.
*
* @package core_contentbank
* @category test
* @copyright 2020 Amaia Anabitarte <amaia@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_contentbank\contenttype
*
*/
class contenttype_test extends \advanced_testcase {
/** @var int Identifier for the manager role. */
protected $managerroleid;
/** @var stdClass Manager user. */
protected $manager1;
/** @var stdClass Manager user. */
protected $manager2;
/** @var stdClass User. */
protected $user;
/** @var array List of contents created (every user has a key with contents created by her). */
protected $contents = [];
/** @var contenttype The contenttype instance. */
protected $contenttype;
/**
* Setup to ensure that fixtures are loaded.
*/
public static function setupBeforeClass(): void {
global $CFG;
require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_contenttype.php');
require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_content.php');
}
/**
* Tests get_contenttype_name result.
*
* @covers ::get_contenttype_name
*/
public function test_get_contenttype_name(): void {
$this->resetAfterTest();
$systemcontext = \context_system::instance();
$testable = new contenttype($systemcontext);
$this->assertEquals('contenttype_testable', $testable->get_contenttype_name());
}
/**
* Tests get_plugin_name result.
*
* @covers ::get_plugin_name
*/
public function test_get_plugin_name(): void {
$this->resetAfterTest();
$systemcontext = \context_system::instance();
$testable = new contenttype($systemcontext);
$this->assertEquals('testable', $testable->get_plugin_name());
}
/**
* Tests get_icon result.
*
* @covers ::get_icon
*/
public function test_get_icon(): void {
global $CFG;
$this->resetAfterTest();
$systemcontext = \context_system::instance();
$testable = new contenttype($systemcontext);
$record = new stdClass();
$record->name = 'New content';
$content = $testable->create_content($record);
$this->assertEquals(
"{$CFG->wwwroot}/theme/image.php/boost/core/1/f/unknown",
$testable->get_icon($content),
);
}
/**
* Tests is_feature_supported behavior .
*
* @covers ::is_feature_supported
*/
public function test_is_feature_supported(): void {
$this->resetAfterTest();
$systemcontext = \context_system::instance();
$testable = new contenttype($systemcontext);
$this->assertTrue($testable->is_feature_supported(contenttype::CAN_TEST));
$this->assertFalse($testable->is_feature_supported(contenttype::CAN_UPLOAD));
}
/**
* Tests can_upload behavior with no implemented upload feature.
*
* @covers ::can_upload
*/
public function test_no_upload_feature_supported(): void {
$this->resetAfterTest();
$systemcontext = \context_system::instance();
$testable = new contenttype($systemcontext);
$this->setAdminUser();
$this->assertFalse($testable->is_feature_supported(contenttype::CAN_UPLOAD));
$this->assertFalse($testable->can_upload());
}
/**
* Test create_content() with empty data.
*
* @covers ::create_content
*/
public function test_create_empty_content(): void {
$this->resetAfterTest();
// Create empty content.
$record = new stdClass();
$contenttype = new contenttype(context_system::instance());
$content = $contenttype->create_content($record);
$this->assertEquals('contenttype_testable', $content->get_content_type());
$this->assertInstanceOf('\\contenttype_testable\\content', $content);
}
/**
* Tests for behaviour of create_content() with data.
*
* @covers ::create_content
*/
public function test_create_content(): void {
$this->resetAfterTest();
// Create content.
$record = new stdClass();
$record->name = 'Test content';
$record->configdata = '';
$record->contenttype = '';
$contenttype = new contenttype(context_system::instance());
$content = $contenttype->create_content($record);
$this->assertEquals('contenttype_testable', $content->get_content_type());
$this->assertInstanceOf('\\contenttype_testable\\content', $content);
}
/**
* Tests for behaviour of upload_content() with a file and a record.
*
* @dataProvider upload_content_provider
* @param bool $userecord if a predefined record has to be used.
*
* @covers ::upload_content
*/
public function test_upload_content(bool $userecord): void {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
$dummy = [
'contextid' => context_user::instance($USER->id)->id,
'component' => 'user',
'filearea' => 'draft',
'itemid' => 1,
'filepath' => '/',
'filename' => 'file.h5p',
'userid' => $USER->id,
];
$fs = get_file_storage();
$dummyfile = $fs->create_file_from_string($dummy, 'Dummy content');
// Create content.
if ($userecord) {
$record = new stdClass();
$record->name = 'Test content';
$record->configdata = '';
$record->contenttype = '';
$checkname = $record->name;
} else {
$record = null;
$checkname = $dummyfile->get_filename();
}
$contenttype = new contenttype(context_system::instance());
$content = $contenttype->upload_content($dummyfile, $record);
$this->assertEquals('contenttype_testable', $content->get_content_type());
$this->assertEquals($checkname, $content->get_name());
$this->assertInstanceOf('\\contenttype_testable\\content', $content);
$file = $content->get_file();
$this->assertEquals($dummyfile->get_filename(), $file->get_filename());
$this->assertEquals($dummyfile->get_userid(), $file->get_userid());
$this->assertEquals($dummyfile->get_mimetype(), $file->get_mimetype());
$this->assertEquals($dummyfile->get_contenthash(), $file->get_contenthash());
$this->assertEquals('contentbank', $file->get_component());
$this->assertEquals('public', $file->get_filearea());
$this->assertEquals('/', $file->get_filepath());
}
/**
* Data provider for test_rename_content.
*
* @return array
*/
public function upload_content_provider() {
return [
'With record' => [true],
'Without record' => [false],
];
}
/**
* Tests for behaviour of upload_content() with a file wrong file.
*
* @covers ::upload_content
*/
public function test_upload_content_exception(): void {
global $USER, $DB;
$this->resetAfterTest();
$this->setAdminUser();
// The testing contenttype thows exception if filename is "error.*".
$dummy = [
'contextid' => context_user::instance($USER->id)->id,
'component' => 'user',
'filearea' => 'draft',
'itemid' => 1,
'filepath' => '/',
'filename' => 'error.txt',
'userid' => $USER->id,
];
$fs = get_file_storage();
$dummyfile = $fs->create_file_from_string($dummy, 'Dummy content');
$contenttype = new contenttype(context_system::instance());
$cbcontents = $DB->count_records('contentbank_content');
// We need to capture the exception to check no content is created.
try {
$content = $contenttype->upload_content($dummyfile);
$this->assertTrue(false);
} catch (Exception $e) {
$this->assertTrue(true);
}
$this->assertEquals($cbcontents, $DB->count_records('contentbank_content'));
$this->assertEquals(1, $DB->count_records('files', ['contenthash' => $dummyfile->get_contenthash()]));
}
/**
* Tests for behaviour of replace_content() using a dummy file.
*
* @covers ::replace_content
*/
public function test_replace_content(): void {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
$context = context_system::instance();
// Add some content to the content bank.
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$contents = $generator->generate_contentbank_data('contenttype_testable', 3, 0, $context);
$content = reset($contents);
$dummy = [
'contextid' => context_user::instance($USER->id)->id,
'component' => 'user',
'filearea' => 'draft',
'itemid' => 1,
'filepath' => '/',
'filename' => 'file.h5p',
'userid' => $USER->id,
];
$fs = get_file_storage();
$dummyfile = $fs->create_file_from_string($dummy, 'Dummy content');
$contenttype = new contenttype(context_system::instance());
$content = $contenttype->replace_content($dummyfile, $content);
$this->assertEquals('contenttype_testable', $content->get_content_type());
$this->assertInstanceOf('\\contenttype_testable\\content', $content);
$file = $content->get_file();
$this->assertEquals($dummyfile->get_userid(), $file->get_userid());
$this->assertEquals($dummyfile->get_contenthash(), $file->get_contenthash());
$this->assertEquals('contentbank', $file->get_component());
$this->assertEquals('public', $file->get_filearea());
$this->assertEquals('/', $file->get_filepath());
}
/**
* Tests for behaviour of replace_content() using an error file.
*
* @covers ::replace_content
*/
public function test_replace_content_exception(): void {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
$context = context_system::instance();
// Add some content to the content bank.
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$contents = $generator->generate_contentbank_data('contenttype_testable', 3, 0, $context);
$content = reset($contents);
$dummy = [
'contextid' => context_user::instance($USER->id)->id,
'component' => 'user',
'filearea' => 'draft',
'itemid' => 1,
'filepath' => '/',
'filename' => 'error.txt',
'userid' => $USER->id,
];
$fs = get_file_storage();
$dummyfile = $fs->create_file_from_string($dummy, 'Dummy content');
$contenttype = new contenttype(context_system::instance());
$this->expectException(Exception::class);
$content = $contenttype->replace_content($dummyfile, $content);
}
/**
* Test the behaviour of can_delete().
*/
public function test_can_delete(): void {
global $DB;
$this->resetAfterTest();
$this->contenttype_setup_scenario_data();
$managercontent = array_shift($this->contents[$this->manager1->id]);
$usercontent = array_shift($this->contents[$this->user->id]);
// Check the content has been created as expected.
$records = $DB->count_records('contentbank_content');
$this->assertEquals(4, $records);
// Check user can only delete records created by her.
$this->setUser($this->user);
$this->assertFalse($this->contenttype->can_delete($managercontent));
$this->assertTrue($this->contenttype->can_delete($usercontent));
// Check manager can delete records all the records created.
$this->setUser($this->manager1);
$this->assertTrue($this->contenttype->can_delete($managercontent));
$this->assertTrue($this->contenttype->can_delete($usercontent));
// Unassign capability to manager role and check not can only delete their own records.
unassign_capability('moodle/contentbank:deleteanycontent', $this->managerroleid);
$this->assertTrue($this->contenttype->can_delete($managercontent));
$this->assertFalse($this->contenttype->can_delete($usercontent));
$this->setUser($this->manager2);
$this->assertFalse($this->contenttype->can_delete($managercontent));
$this->assertFalse($this->contenttype->can_delete($usercontent));
}
/**
* Test the behaviour of delete_content().
*/
public function test_delete_content(): void {
global $DB;
$this->resetAfterTest();
$this->contenttype_setup_scenario_data();
// Check the content has been created as expected.
$this->assertEquals(4, $DB->count_records('contentbank_content'));
// Check the content is deleted as expected.
$this->setUser($this->manager1);
$content = array_shift($this->contents[$this->manager1->id]);
$deleted = $this->contenttype->delete_content($content);
$this->assertTrue($deleted);
$this->assertEquals(3, $DB->count_records('contentbank_content'));
}
/**
* Helper function to setup 3 users (manager1, manager2 and user) and 4 contents (3 created by manager1 and 1 by user).
*/
protected function contenttype_setup_scenario_data(string $contenttype = 'contenttype_testable'): void {
global $DB;
$systemcontext = context_system::instance();
// Create users.
$this->manager1 = $this->getDataGenerator()->create_user();
$this->manager2 = $this->getDataGenerator()->create_user();
$this->managerroleid = $DB->get_field('role', 'id', array('shortname' => 'manager'));
$this->getDataGenerator()->role_assign($this->managerroleid, $this->manager1->id);
$this->getDataGenerator()->role_assign($this->managerroleid, $this->manager2->id);
$editingteacherrolerid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher']);
$this->user = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->role_assign($editingteacherrolerid, $this->user->id);
// Add some content to the content bank.
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$this->contents[$this->manager1->id] = $generator->generate_contentbank_data($contenttype, 3, $this->manager1->id);
$this->contents[$this->user->id] = $generator->generate_contentbank_data($contenttype, 1, $this->user->id);
$contenttypeclass = "\\$contenttype\\contenttype";
$this->contenttype = new $contenttypeclass($systemcontext);
}
/**
* Data provider for test_rename_content.
*
* @return array
*/
public function rename_content_provider() {
return [
'Standard name' => ['New name', 'New name', true],
'Name with digits' => ['Today is 17/04/2017', 'Today is 17/04/2017', true],
'Name with symbols' => ['Follow us: @moodle', 'Follow us: @moodle', true],
'Name with tags' => ['This is <b>bold</b>', 'This is bold', true],
'Long name' => [str_repeat('a', 100), str_repeat('a', 100), true],
'Too long name' => [str_repeat('a', 300), str_repeat('a', 255), true],
'Empty name' => ['', 'Test content ', false],
'Blanks only' => [' ', 'Test content ', false],
'Zero name' => ['0', '0', true],
];
}
/**
* Test the behaviour of rename_content().
*
* @dataProvider rename_content_provider
* @param string $newname The name to set
* @param string $expected The name result
* @param bool $result The bolean result expected when renaming
*
* @covers ::rename_content
*/
public function test_rename_content(string $newname, string $expected, bool $result): void {
global $DB;
$this->resetAfterTest();
// Create course and teacher user.
$course = $this->getDataGenerator()->create_course();
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
$coursecontext = \context_course::instance($course->id);
$contenttype = new contenttype($coursecontext);
// Add some content to the content bank as teacher.
$this->setUser($teacher);
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$contents = $generator->generate_contentbank_data('contenttype_testable', 1, $teacher->id);
$content = array_shift($contents);
$oldname = $content->get_name();
// Check the content is renamed as expected by a user with permission.
$renamed = $contenttype->rename_content($content, $newname);
$this->assertEquals($result, $renamed);
$record = $DB->get_record('contentbank_content', ['id' => $content->get_id()]);
$this->assertEquals($expected, $record->name);
}
/**
* Test the behaviour of move_content().
*/
public function test_move_content(): void {
global $DB;
$this->resetAfterTest();
$systemcontext = context_system::instance();
$course = $this->getDataGenerator()->create_course();
$coursecontext = \context_course::instance($course->id);
// Add some content to the content bank.
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$systemcontents = $generator->generate_contentbank_data('contenttype_testable', 3, 0, $systemcontext);
$generator->generate_contentbank_data('contenttype_testable', 3, 0, $coursecontext);
$systemcontent = reset($systemcontents);
// Check the content has been created as expected.
$this->assertEquals(6, $DB->count_records('contentbank_content'));
$this->assertEquals(3, $DB->count_records('contentbank_content', ['contextid' => $systemcontext->id]));
$this->assertEquals(3, $DB->count_records('contentbank_content', ['contextid' => $coursecontext->id]));
// Check the content files has been created as expected.
$this->assertEquals(12, $DB->count_records('files', ['component' => 'contentbank']));
$this->assertEquals(6, $DB->count_records('files', ['component' => 'contentbank', 'contextid' => $systemcontext->id]));
$this->assertEquals(6, $DB->count_records('files', ['component' => 'contentbank', 'contextid' => $coursecontext->id]));
// Check the content is moved as expected.
$contenttype = new contenttype($systemcontext);
$this->assertTrue($contenttype->move_content($systemcontent, $coursecontext));
$this->assertEquals(6, $DB->count_records('contentbank_content'));
$this->assertEquals(2, $DB->count_records('contentbank_content', ['contextid' => $systemcontext->id]));
$this->assertEquals(4, $DB->count_records('contentbank_content', ['contextid' => $coursecontext->id]));
// Check the content files were moved as expected.
$this->assertEquals(12, $DB->count_records('files', ['component' => 'contentbank']));
$this->assertEquals(4, $DB->count_records('files', ['component' => 'contentbank', 'contextid' => $systemcontext->id]));
$this->assertEquals(8, $DB->count_records('files', ['component' => 'contentbank', 'contextid' => $coursecontext->id]));
}
/**
* Test the behaviour of can_manage().
*
* @covers ::can_manage
*/
public function test_can_manage(): void {
global $DB, $USER;
$this->resetAfterTest();
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
// Create course and teacher user.
$teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher']);
$course = $this->getDataGenerator()->create_course();
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
$manager = $this->getDataGenerator()->create_and_enrol($course, 'manager');
$coursecontext = \context_course::instance($course->id);
$contenttype = new contenttype($coursecontext);
// Add some content to the content bank as admin.
$this->setAdminUser();
$contentsbyadmin = $generator->generate_contentbank_data('contenttype_testable', 1, $USER->id, $coursecontext);
$contentbyadmin = array_shift($contentsbyadmin);
// Add some content to the content bank as teacher.
$contentsbyteacher = $generator->generate_contentbank_data('contenttype_testable', 1, $teacher->id, $coursecontext);
$contentbyteacher = array_shift($contentsbyteacher);
// Check the content has been created as expected.
$records = $DB->count_records('contentbank_content');
$this->assertEquals(2, $records);
// Check manager can manage by default all the contents created.
$this->setUser($manager);
$this->assertTrue($contenttype->can_manage($contentbyteacher));
$this->assertTrue($contenttype->can_manage($contentbyadmin));
// Check teacher can only edit their own content.
$this->setUser($teacher);
$this->assertTrue($contenttype->can_manage($contentbyteacher));
$this->assertFalse($contenttype->can_manage($contentbyadmin));
// Unassign capability to teacher role and check they not can not edit any content.
unassign_capability('moodle/contentbank:manageowncontent', $teacherroleid);
$this->assertFalse($contenttype->can_manage($contentbyteacher));
$this->assertFalse($contenttype->can_manage($contentbyadmin));
}
/**
* Test the behaviour of can_download().
*
* @covers ::can_download
*/
public function test_can_download(): void {
global $DB;
$this->resetAfterTest();
$this->contenttype_setup_scenario_data('contenttype_h5p');
$managercontent = array_shift($this->contents[$this->manager1->id]);
$usercontent = array_shift($this->contents[$this->user->id]);
// Check the content has been created as expected.
$records = $DB->count_records('contentbank_content');
$this->assertEquals(4, $records);
// Check user can download content created by anybody.
$this->setUser($this->user);
$this->assertTrue($this->contenttype->can_download($usercontent));
$this->assertTrue($this->contenttype->can_download($managercontent));
// Check manager can download all the content too.
$this->setUser($this->manager1);
$this->assertTrue($this->contenttype->can_download($managercontent));
$this->assertTrue($this->contenttype->can_download($usercontent));
// Unassign capability to manager role and check she cannot download content anymore.
unassign_capability('moodle/contentbank:downloadcontent', $this->managerroleid);
$this->assertFalse($this->contenttype->can_download($managercontent));
$this->assertFalse($this->contenttype->can_download($usercontent));
}
/**
* Tests get_download_url result.
*
* @covers ::get_download_url
*/
public function test_get_download_url(): void {
global $CFG;
$this->resetAfterTest();
$this->setAdminUser();
$systemcontext = context_system::instance();
// Add some content to the content bank.
$filename = 'filltheblanks.h5p';
$filepath = $CFG->dirroot . '/h5p/tests/fixtures/' . $filename;
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$contents = $generator->generate_contentbank_data('contenttype_testable', 1, 0, $systemcontext, true, $filepath);
$content = array_shift($contents);
// Check the URL is returned OK for a content with file.
$contenttype = new contenttype($systemcontext);
$url = $contenttype->get_download_url($content);
$this->assertNotEmpty($url);
$this->assertStringContainsString($filename, $url);
// Check the URL is empty when the content hasn't any file.
$record = new stdClass();
$content = $contenttype->create_content($record);
$url = $contenttype->get_download_url($content);
$this->assertEmpty($url);
}
/**
* Tests pluginfile result.
*
* @covers ::pluginfile
*/
public function test_pluginfile(): void {
$this->resetAfterTest();
$this->setAdminUser();
$systemcontext = context_system::instance();
$contenttype = new contenttype($systemcontext);
$this->assertIsCallable([$contenttype, 'pluginfile']);
}
}
+146
View File
@@ -0,0 +1,146 @@
<?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/>.
namespace core_contentbank\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_contenttype.php');
require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_content.php');
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
use core_external\external_api;
/**
* Content bank's copy content external function tests.
*
* @package core_contentbank
* @copyright 2023 Daniel Neis Araujo
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_contentbank\external\copy_content
*/
class copy_content_test extends \externallib_advanced_testcase {
/**
* Test the behaviour of copy_content() for users with permission.
*
* @covers ::execute
*/
public function test_copy_content_with_permission(): void {
global $CFG, $DB;
$this->resetAfterTest();
// Create users.
$roleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher']);
$teacher = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->role_assign($roleid, $teacher->id);
$this->setUser($teacher);
// Add some content to the content bank as teacher.
$filename = 'filltheblanks.h5p';
$filepath = $CFG->dirroot . '/h5p/tests/fixtures/' . $filename;
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$contents = $generator->generate_contentbank_data('contenttype_h5p', 1, $teacher->id, null, true, $filepath);
$content = array_shift($contents);
$oldname = $content->get_name();
$newname = 'New name';
// Call the WS and check the content is copied as expected.
$result = copy_content::execute($content->get_id(), $newname);
$result = external_api::clean_returnvalue(copy_content::execute_returns(), $result);
$this->assertNotEmpty($result['id']);
$record = $DB->get_record('contentbank_content', ['id' => $result['id']]);
$this->assertEquals($newname, $record->name);
$record = $DB->get_record('contentbank_content', ['id' => $content->get_id()]);
$this->assertEquals($oldname, $record->name);
// Call the WS using an unexisting contentid and check an error is thrown.
$this->expectException(\invalid_response_exception::class);
$result = copy_content::execute_returns($content->get_id() + 1, $oldname);
$result = external_api::clean_returnvalue(copy_content::execute_returns(), $result);
$this->assertNotEmpty($result['warnings']);
}
/**
* Test the behaviour of copy_content() for users with and without permission.
*
* @covers ::execute
*/
public function test_copy_content(): void {
global $CFG, $DB;
$this->resetAfterTest();
// Create users.
$course = $this->getDataGenerator()->create_course();
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
$teacher2 = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
$manager = $this->getDataGenerator()->create_and_enrol($course, 'manager');
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
// Add some content to the content bank as teacher.
$coursecontext = \context_course::instance($course->id);
$filename = 'filltheblanks.h5p';
$filepath = $CFG->dirroot . '/h5p/tests/fixtures/' . $filename;
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$contents = $generator->generate_contentbank_data('contenttype_h5p', 1, $teacher->id, $coursecontext, true, $filepath);
$content = array_shift($contents);
$oldname = $content->get_name();
$newname = 'New name';
// Call the WS and check the teacher can copy his/her own content.
$this->setUser($teacher);
$result = copy_content::execute($content->get_id(), $newname);
$result = external_api::clean_returnvalue(copy_content::execute_returns(), $result);
$this->assertEmpty($result['warnings']);
$record = $DB->get_record('contentbank_content', ['id' => $result['id']]);
$this->assertEquals($newname, $record->name);
// Call the WS and check the content has not been copied by the student.
$this->setUser($student);
$result = copy_content::execute($content->get_id(), $newname);
$result = external_api::clean_returnvalue(copy_content::execute_returns(), $result);
$this->assertNotEmpty($result['warnings']);
$record = $DB->get_record('contentbank_content', ['id' => $content->get_id()]);
$this->assertEquals($oldname, $record->name);
$this->assertNotEquals($newname, $record->name);
// Call the WS an check the content with empty name is not copied by the teacher.
$this->setUser($teacher);
$result = copy_content::execute($content->get_id(), '');
$result = external_api::clean_returnvalue(copy_content::execute_returns(), $result);
$this->assertNotEmpty($result['warnings']);
// Call the WS and check a teacher cannot copy content from another teacher by default.
$this->setUser($teacher2);
$result = copy_content::execute($content->get_id(), 'New name 2');
$result = external_api::clean_returnvalue(copy_content::execute_returns(), $result);
$this->assertNotEmpty($result['warnings']);
// Call the WS and check a manager can copy content from a teacher by default.
$this->setUser($manager);
$result = copy_content::execute($content->get_id(), $newname);
$result = external_api::clean_returnvalue(copy_content::execute_returns(), $result);
$this->assertEmpty($result['warnings']);
$record = $DB->get_record('contentbank_content', ['id' => $result['id']]);
$this->assertEquals($newname, $record->name);
}
}
+112
View File
@@ -0,0 +1,112 @@
<?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/>.
/**
* External function test for delete_content.
*
* @package core_contentbank
* @category external
* @since Moodle 3.9
* @copyright 2020 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_contentbank\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_content.php');
use dml_missing_record_exception;
use core_external\external_api;
use externallib_advanced_testcase;
/**
* External function test for delete_content.
*
* @package core_contentbank
* @copyright 2020 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class delete_content_test extends externallib_advanced_testcase {
/**
* Test the behaviour of delete_content().
*/
public function test_delete_content(): void {
global $DB;
$this->resetAfterTest();
$records = [];
// Create users.
$user = $this->getDataGenerator()->create_user();
$roleid = $DB->get_field('role', 'id', array('shortname' => 'manager'));
$manager = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->role_assign($roleid, $manager->id);
// Add some content to the content bank.
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$records[$manager->id] = $generator->generate_contentbank_data('contenttype_testable', 4, $manager->id, null, false);
$records[$user->id] = $generator->generate_contentbank_data('contenttype_testable', 2, $user->id, null, false);
// Check the content has been created as expected.
$this->assertEquals(6, $DB->count_records('contentbank_content'));
// Check the content is deleted as expected by the user when the content has been created by herself.
$this->setUser($user);
$userrecord = array_shift($records[$user->id]);
$result = delete_content::execute([$userrecord->id]);
$result = external_api::clean_returnvalue(delete_content::execute_returns(), $result);
$this->assertTrue($result['result']);
$this->assertCount(0, $result['warnings']);
$this->assertEquals(5, $DB->count_records('contentbank_content'));
// Check the content is not deleted if the user hasn't created it and has only permission to delete her own content.
$userrecord = array_shift($records[$user->id]);
$managerrecord1 = array_shift($records[$manager->id]);
$result = delete_content::execute([$managerrecord1->id, $userrecord->id]);
$result = external_api::clean_returnvalue(delete_content::execute_returns(), $result);
$this->assertFalse($result['result']);
$this->assertCount(1, $result['warnings']);
$warning = array_shift($result['warnings']);
$this->assertEquals('nopermissiontodelete', $warning['warningcode']);
$this->assertEquals($managerrecord1->id, $warning['item']);
$this->assertEquals(4, $DB->count_records('contentbank_content'));
// Check the content is deleted as expected by the manager.
$this->setUser($manager);
$managerrecord2 = array_shift($records[$manager->id]);
$result = delete_content::execute([$managerrecord1->id, $managerrecord2->id]);
$result = external_api::clean_returnvalue(delete_content::execute_returns(), $result);
$this->assertTrue($result['result']);
$this->assertCount(0, $result['warnings']);
$this->assertEquals(2, $DB->count_records('contentbank_content'));
// Check an exception warning is returned if an unexisting contentid is deleted.
// Check also the other content is deleted (so the process continues after the exception is thrown).
$managerrecord3 = array_shift($records[$manager->id]);
$result = delete_content::execute([$managerrecord1->id, $managerrecord3->id]);
$result = external_api::clean_returnvalue(delete_content::execute_returns(), $result);
$this->assertFalse($result['result']);
$this->assertCount(1, $result['warnings']);
$warning = array_shift($result['warnings']);
$this->assertEquals('exception', $warning['warningcode']);
$this->assertEquals($managerrecord1->id, $warning['item']);
$this->assertEquals(1, $DB->count_records('contentbank_content'));
}
}
+140
View File
@@ -0,0 +1,140 @@
<?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/>.
/**
* Core content bank external functions tests.
*
* @package core_contentbank
* @category external
* @copyright 2020 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.9
*/
namespace core_contentbank\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_contenttype.php');
require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_content.php');
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
use core_external\external_api;
/**
* Core content bank external functions tests.
*
* @package core_contentbank
* @copyright 2020 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_contentbank\external\rename_content
*/
class rename_content_test extends \externallib_advanced_testcase {
/**
* Data provider for test_rename_content.
*
* @return array
*/
public function rename_content_provider() {
return [
'Standard name' => ['New name', 'New name', true],
'Name with digits' => ['Today is 17/04/2017', 'Today is 17/04/2017', true],
'Name with symbols' => ['Follow us: @moodle', 'Follow us: @moodle', true],
'Name with tags' => ['This is <b>bold</b>', 'This is bold', true],
'Long name' => [str_repeat('a', 100), str_repeat('a', 100), true],
'Too long name' => [str_repeat('a', 300), str_repeat('a', 255), true],
'Empty name' => ['', 'Test content ', false],
'Blanks only' => [' ', 'Test content ', false],
'Zero name' => ['0', '0', true],
];
}
/**
* Test the behaviour of rename_content() for users with permission.
*
* @dataProvider rename_content_provider
* @param string $newname The name to set
* @param string $expectedname The name result
* @param bool $expectedresult The bolean result expected when renaming
*
* @covers ::execute
*/
public function test_rename_content_with_permission(string $newname, string $expectedname, bool $expectedresult): void {
global $DB;
$this->resetAfterTest();
// Create users.
$roleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher']);
$teacher = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->role_assign($roleid, $teacher->id);
$this->setUser($teacher);
// Add some content to the content bank as teacher.
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$contents = $generator->generate_contentbank_data('contenttype_testable', 1, $teacher->id);
$content = array_shift($contents);
$oldname = $content->get_name();
// Call the WS and check the content is renamed as expected.
$result = rename_content::execute($content->get_id(), $newname);
$result = external_api::clean_returnvalue(rename_content::execute_returns(), $result);
$this->assertEquals($expectedresult, $result['result']);
$record = $DB->get_record('contentbank_content', ['id' => $content->get_id()]);
$this->assertEquals($expectedname, $record->name);
// Call the WS using an unexisting contentid and check an error is thrown.
$this->expectException(\invalid_response_exception::class);
$result = rename_content::execute_returns($content->get_id() + 1, $oldname);
$result = external_api::clean_returnvalue(rename_content::execute_returns(), $result);
$this->assertFalse($result['result']);
}
/**
* Test the behaviour of rename_content() for users with permission.
*
* @covers ::execute
*/
public function test_rename_content_without_permission(): void {
global $DB;
$this->resetAfterTest();
// Create users.
$course = $this->getDataGenerator()->create_course();
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
// Add some content to the content bank as teacher.
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
$contents = $generator->generate_contentbank_data('contenttype_testable', 1, $teacher->id);
$content = array_shift($contents);
$oldname = $content->get_name();
$newname = 'New name';
// Call the WS and check the content has not been renamed by the student.
$this->setUser($student);
$result = rename_content::execute($content->get_id(), $newname);
$result = external_api::clean_returnvalue(rename_content::execute_returns(), $result);
$this->assertFalse($result['result']);
$record = $DB->get_record('contentbank_content', ['id' => $content->get_id()]);
$this->assertEquals($oldname, $record->name);
$this->assertNotEquals($newname, $record->name);
}
}
+56
View File
@@ -0,0 +1,56 @@
<?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/>.
/**
* Testable content plugin class.
*
* @package core_contentbank
* @category test
* @copyright 2020 Amaia Anabitarte <amaia@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace contenttype_testable;
use file_exception;
use stored_file;
/**
* Testable content plugin class.
*
* @package core_contentbank
* @copyright 2020 Amaia Anabitarte <amaia@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class content extends \core_contentbank\content {
/**
* Import a file as a valid content.
*
* This method will thow an error if the filename is "error.*"
*
* @param stored_file $file File to store in the content file area.
* @return stored_file|null the stored content file or null if the file is discarted.
* @throws file_exception if the filename contains the word "error"
*/
public function import_file(stored_file $file): ?stored_file {
$filename = $file->get_filename();
if (strrpos($filename, 'error') !== false) {
throw new file_exception('yourerrorthanks', 'contenttype_test');
}
return parent::import_file($file);
}
}
+98
View File
@@ -0,0 +1,98 @@
<?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/>.
namespace contenttype_testable;
/**
* Testable contenttype plugin class.
*
* @package core_contentbank
* @copyright 2020 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class contenttype extends \core_contentbank\contenttype {
/** Feature for testing */
const CAN_TEST = 'test';
/** @var array Additional features for testing */
public static $featurestotest;
/**
* Return an array of implemented features by this plugin.
*
* @return array
*/
protected function get_implemented_features(): array {
$features = [self::CAN_TEST];
if (!empty(self::$featurestotest)) {
$features = array_merge($features, self::$featurestotest);
}
return $features;
}
/**
* Return an array of extensions this plugin could manage.
*
* @return array
*/
public function get_manageable_extensions(): array {
return ['.txt', '.png', '.h5p'];
}
/**
* Returns the list of different types of the given content type.
*
* @return array
*/
public function get_contenttype_types(): array {
$type = new \stdClass();
$type->typename = 'testable';
return [$type];
}
/**
* Returns true, so the user has permission on the feature.
*
* @return bool True if content could be edited or created. False otherwise.
*/
final public function can_test2(): bool {
if (!$this->is_feature_supported('test2')) {
return false;
}
return true;
}
/**
* This implements custom file serving.
*
* @param stdClass $course the course object
* @param stdClass $cm the course module object
* @param \context $context the context
* @param string $filearea the name of the file area
* @param array $args extra arguments (itemid, path)
* @param bool $forcedownload whether or not force download
* @param array $options additional options affecting the file serving
* @return void
*/
public static function pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options = []): void {
return;
}
}
+110
View File
@@ -0,0 +1,110 @@
<?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/>.
/**
* Generator for the core_contentbank subsystem.
*
* @package core_contentbank
* @category test
* @copyright 2020 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use core_contentbank\content;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_contenttype.php');
/**
* Generator for the core_contentbank subsystem.
*
* @package core_contentbank
* @copyright 2020 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_contentbank_generator extends \component_generator_base {
/**
* Populate contentbank database tables with relevant data to simulate the process of adding items to the content bank.
*
* @param string $contenttype Content bank plugin type to add. If none is defined, contenttype_testable is used.
* @param int $itemstocreate Number of items to add to the content bank.
* @param int $userid The user identifier creating the content.
* @param context $context The context where the content will be created.
* @param bool $convert2class Whether the class should return stdClass or plugin instance.
* @param string $filepath The filepath of the file associated to the content to create.
* @param string $contentname The name of the content that will be created.
* @param int $visibility The visibility of the content that will be created.
* @return array An array with all the records added to the content bank.
*/
public function generate_contentbank_data(?string $contenttype, int $itemstocreate = 1, int $userid = 0,
?\context $context = null, bool $convert2class = true, string $filepath = 'contentfile.h5p',
string $contentname = 'Test content ', int $visibility = content::VISIBILITY_PUBLIC): array {
global $DB, $USER;
$records = [];
$contenttype = $contenttype ?? 'contenttype_testable';
$contenttypeclass = "\\$contenttype\\contenttype";
if (!class_exists($contenttypeclass)) {
// Early return with empty array because the contenttype doesn't exist.
return $records;
}
if (empty($context)) {
$context = \context_system::instance();
}
$type = new $contenttypeclass($context);
$fs = get_file_storage();
for ($i = 0; $i < $itemstocreate; $i++) {
// Create content.
$record = new stdClass();
// If only 1 item is being created, do not add a number suffix to the content name.
$record->name = ($itemstocreate === 1) ? $contentname : $contentname . $i;
$record->configdata = '';
$record->usercreated = $userid ?? $USER->id;
$record->visibility = $visibility;
$content = $type->create_content($record);
$record = $content->get_content();
// Create a dummy file.
$filerecord = array(
'contextid' => $context->id,
'component' => 'contentbank',
'filearea' => 'public',
'itemid' => $record->id,
'filepath' => '/',
'filename' => basename($filepath)
);
if (file_exists($filepath)) {
$fs->create_file_from_pathname($filerecord, $filepath);
} else {
$fs->create_file_from_string($filerecord, 'Dummy content ' . $i);
}
// Prepare the return value.
if ($convert2class) {
$records[$record->id] = $content;
} else {
$records[$record->id] = $record;
}
}
return $records;
}
}
+411
View File
@@ -0,0 +1,411 @@
<?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/>.
/**
* Base class for unit tests for core_contentbank.
*
* @package core_contentbank
* @category test
* @copyright 2020 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_contentbank\privacy;
use stdClass;
use context_system;
use context_coursecat;
use context_course;
use context_user;
use core_contentbank\privacy\provider;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\writer;
use core_privacy\tests\provider_testcase;
use core_privacy\local\request\userlist;
use core_privacy\local\request\approved_userlist;
/**
* Unit tests for contentbank\classes\privacy\provider.php
*
* @copyright 2020 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider_test extends provider_testcase {
/**
* Setup to ensure that fixtures are loaded.
*/
public static function setupBeforeClass(): void {
global $CFG;
require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_content.php');
}
/**
* Test for provider::get_contexts_for_userid().
*/
public function test_get_contexts_for_userid(): void {
$this->resetAfterTest();
// Setup scenario.
$scenario = $this->setup_scenario();
// Testing againts Manager who has content in the three contexts.
$contextlist = provider::get_contexts_for_userid($scenario->manager->id);
// There are three contexts in the list.
$contextlistids = $contextlist->get_contextids();
$this->assertCount(3, $contextlistids);
// Check the list against the expected list of contexts.
$this->assertContainsEquals($scenario->systemcontext->id, $contextlistids);
$this->assertContainsEquals($scenario->coursecategorycontext->id,
$contextlistids);
$this->assertContainsEquals($scenario->coursecontext->id, $contextlistids);
// Testing againts Teacher who has content in the one context.
$contextlist = provider::get_contexts_for_userid($scenario->teacher->id);
// There are only one context in the list.
$contextlistids = $contextlist->get_contextids();
$this->assertCount(1, $contextlistids);
// Check the againts Course Context.
$this->assertContainsEquals($scenario->coursecontext->id, $contextlistids);
// And there is not a System and Course Category Context.
$this->assertNotContainsEquals($scenario->systemcontext->id, $contextlistids);
$this->assertNotContainsEquals($scenario->coursecategorycontext->id, $contextlistids);
}
/**
* Test for provider::get_users_in_context().
*/
public function test_get_users_in_context(): void {
$this->resetAfterTest();
// Setup scenario.
$scenario = $this->setup_scenario();
// Get the userlist to Context System, only Manager will be there.
$userlist = new userlist($scenario->systemcontext, 'core_contentbank');
provider::get_users_in_context($userlist);
$this->assertEquals([$scenario->manager->id], $userlist->get_userids());
// Teacher will not be there.
$this->assertNotEquals([$scenario->teacher->id], $userlist->get_userids());
// Get the userlist to Context Course, Manager and Teacher will be there.
$userlist = new userlist($scenario->coursecontext, 'core_contentbank');
provider::get_users_in_context($userlist);
$expected = [$scenario->manager->id, $scenario->teacher->id];
sort($expected);
$actual = $userlist->get_userids();
sort($actual);
$this->assertEquals($expected, $actual);
}
/**
* Test for provider::test_export_user_data().
*/
public function test_export_user_data(): void {
$this->resetAfterTest();
// Setup scenario.
$scenario = $this->setup_scenario();
$subcontexts = [
get_string('name', 'core_contentbank')
];
// Get the data for the System Context.
$writer = writer::with_context($scenario->systemcontext);
$this->assertFalse($writer->has_any_data());
// Export data for Manager.
$this->export_context_data_for_user($scenario->manager->id,
$scenario->systemcontext, 'core_contentbank');
$data = $writer->get_data($subcontexts);
$this->assertCount(3, (array) $data);
$this->assertCount(3, $writer->get_files($subcontexts));
// Get the data for the Course Categoy Context.
$writer = writer::with_context($scenario->coursecategorycontext);
// Export data for Manager.
$this->export_context_data_for_user($scenario->manager->id,
$scenario->coursecategorycontext, 'core_contentbank');
$data = $writer->get_data($subcontexts);
$this->assertCount(2, (array) $data);
$this->assertCount(2, $writer->get_files($subcontexts));
// Get the data for the Course Context.
$writer = writer::with_context($scenario->coursecontext);
// Export data for Manager.
$this->export_context_data_for_user($scenario->manager->id,
$scenario->coursecontext, 'core_contentbank');
$data = $writer->get_data($subcontexts);
$this->assertCount(2, (array) $data);
$this->assertCount(2, $writer->get_files($subcontexts));
// Export data for Teacher.
$writer = writer::reset();
$writer = writer::with_context($scenario->coursecontext);
$this->export_context_data_for_user($scenario->teacher->id,
$scenario->coursecontext, 'core_contentbank');
$data = $writer->get_data($subcontexts);
$this->assertCount(3, (array) $data);
$this->assertCount(3, $writer->get_files($subcontexts));
}
/**
* Test for provider::delete_data_for_all_users_in_context().
*/
public function test_delete_data_for_all_users_in_context(): void {
global $DB;
$this->resetAfterTest();
// Setup scenario.
$scenario = $this->setup_scenario();
// Before delete data, we have 4 contents.
// - 3 in a system context.
// - 2 in a course category context.
// - 5 in a course context (2 by manager and 3 by teacher).
// Delete data based on system context.
provider::delete_data_for_all_users_in_context($scenario->systemcontext);
$count = $DB->count_records('contentbank_content');
// 3 content should be deleted.
// 7 contents should be remain.
$this->assertEquals(7, $count);
// Delete data based on course category context.
provider::delete_data_for_all_users_in_context($scenario->coursecategorycontext);
$count = $DB->count_records('contentbank_content');
// 2 contents should be deleted.
// 5 content should be remain.
$this->assertEquals(5, $count);
// Delete data based on course context.
provider::delete_data_for_all_users_in_context($scenario->coursecontext);
$count = $DB->count_records('contentbank_content');
// 5 content should be deleted.
// 0 content should be remain.
$this->assertEquals(0, $count);
}
/**
* Test for provider::test_delete_data_for_users().
*/
public function test_delete_data_for_users(): void {
global $DB;
$this->resetAfterTest();
// Setup scenario.
$scenario = $this->setup_scenario();
// Before delete data, we have 4 contents.
// - 3 in a system context.
// - 2 in a course category context.
// - 5 in a course context (2 by manager and 3 by teacher).
// A list of users who has created content in Course Category Context.
$userlist1 = new userlist($scenario->coursecategorycontext,
'core_contentbank');
provider::get_users_in_context($userlist1);
$this->assertCount(1, $userlist1);
// Only Manager should be.
$this->assertEquals([$scenario->manager->id], $userlist1->get_userids());
// A list of users who has created content in Course Context.
$userlist2 = new userlist($scenario->coursecontext, 'core_contentbank');
provider::get_users_in_context($userlist2);
$this->assertCount(2, $userlist2);
// Manager and Teacher should be.
$expected = [$scenario->manager->id, $scenario->teacher->id];
sort($expected);
$actual = $userlist2->get_userids();
sort($actual);
$this->assertEquals($expected, $actual);
// Convert $userlist1 into an approved_contextlist.
$approvedlist1 = new approved_userlist($scenario->coursecategorycontext, 'core_contentbank', $userlist1->get_userids());
// Delete data for users in course category context.
provider::delete_data_for_users($approvedlist1);
// Re-fetch users in course category context.
$userlist1 = new userlist($scenario->coursecategorycontext,
'core_contentbank');
provider::get_users_in_context($userlist1);
// The user data in course category context should be deleted.
$this->assertCount(0, $userlist1);
// Re-fetch users in course category context.
$userlist2 = new userlist($scenario->coursecontext, 'core_contentbank');
provider::get_users_in_context($userlist2);
// The user data in course context should be still present.
$this->assertCount(2, $userlist2);
// Convert $userlist2 into an approved_contextlist.
$approvedlist2 = new approved_userlist($scenario->coursecontext,
'core_contentbank', $userlist2->get_userids());
// Delete data for users in course context.
provider::delete_data_for_users($approvedlist2);
$userlist2 = new userlist($scenario->coursecontext, 'core_contentbank');
provider::get_users_in_context($userlist2);
// The user data in course context should be deleted.
$this->assertCount(0, $userlist2);
}
/**
* Test for provider::delete_data_for_user().
*/
public function test_delete_data_for_user(): void {
global $DB;
$this->resetAfterTest();
// Setup scenario.
$scenario = $this->setup_scenario();
// Before delete data, we have 4 contents.
// - 3 in a system context.
// - 2 in a course category context.
// - 5 in a course context (2 by manager and 3 by teacher).
// Get all the context for Manager.
$contextlist = provider::get_contexts_for_userid($scenario->manager->id);
$approvedcontextlist = new approved_contextlist($scenario->manager,
'core_contentbank', $contextlist->get_contextids());
// Delete all the data created by the Manager in all the contexts.
provider::delete_data_for_user($approvedcontextlist);
// After deletion, only 3 content for teacher should be present.
$count = $DB->count_records('contentbank_content');
$this->assertEquals(3, $count);
// Confirm that the remaining content was created by the teacher.
$count = $DB->count_records('contentbank_content',
['usercreated' => $scenario->teacher->id]);
$this->assertEquals(3, $count);
// Get all the context for Teacher.
$contextlist = provider::get_contexts_for_userid($scenario->teacher->id);
$approvedcontextlist = new approved_contextlist($scenario->teacher,
'core_contentbank', $contextlist->get_contextids());
// Delete all the data created by the Teacher in all the contexts.
provider::delete_data_for_user($approvedcontextlist);
// After deletion, no content should be present.
$count = $DB->count_records('contentbank_content');
$this->assertEquals(0, $count);
}
/**
* Create a complex scenario to use into the tests.
*
* @return stdClass $scenario
*/
protected function setup_scenario() {
global $DB;
$systemcontext = context_system::instance();
$manager = $this->getDataGenerator()->create_user();
$managerroleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
$this->getDataGenerator()->role_assign($managerroleid, $manager->id);
$coursecategory = $this->getDataGenerator()->create_category();
$coursecategorycontext = context_coursecat::instance($coursecategory->id);
$course = $this->getDataGenerator()->create_course();
$coursecontext = context_course::instance($course->id);
$teacher = $this->getDataGenerator()->create_and_enrol($course,
'editingteacher');
// Add some content to the content bank.
$generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
// Add contents by Manager in Context System.
$records = $generator->generate_contentbank_data('contenttype_testable',
1, $manager->id, $systemcontext, false, 'systemtestfile1.h5p');
$records = $generator->generate_contentbank_data('contenttype_testable',
1, $manager->id, $systemcontext, false, 'systemtestfile2.h5p');
$records = $generator->generate_contentbank_data('contenttype_testable',
1, $manager->id, $systemcontext, false, 'systemtestfile3.h5p');
// Add contents by Manager in Context Course Category.
$records = $generator->generate_contentbank_data('contenttype_testable',
1, $manager->id, $coursecategorycontext, false, 'coursecattestfile1.h5p');
$records = $generator->generate_contentbank_data('contenttype_testable',
1, $manager->id, $coursecategorycontext, false, 'coursecattestfile2.h5p');
// Add contents by Manager in Context Course.
$records = $generator->generate_contentbank_data('contenttype_testable',
1, $manager->id, $coursecontext, false, 'coursetestfile1.h5p');
$records = $generator->generate_contentbank_data('contenttype_testable',
1, $manager->id, $coursecontext, false, 'coursetestfile2.h5p');
// Add contents by Teacher.
$records = $generator->generate_contentbank_data('contenttype_testable',
1, $teacher->id, $coursecontext, false, 'courseteacherfile1.h5p');
$records = $generator->generate_contentbank_data('contenttype_testable',
1, $teacher->id, $coursecontext, false, 'courseteacherfile2.h5p');
$records = $generator->generate_contentbank_data('contenttype_testable',
1, $teacher->id, $coursecontext, false, 'courseteacherfile3.h5p');
$scenario = new stdClass();
$scenario->systemcontext = $systemcontext;
$scenario->coursecategorycontext = $coursecategorycontext;
$scenario->coursecontext = $coursecontext;
$scenario->manager = $manager;
$scenario->teacher = $teacher;
return $scenario;
}
/**
* Ensure that export_user_preferences returns no data if the user has not visited any content bank.
*/
public function test_export_user_preferences_no_pref(): void {
global $DB;
$this->resetAfterTest();
$user = $this->getDataGenerator()->create_user();
$managerroleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
$this->getDataGenerator()->role_assign($managerroleid, $user->id);
provider::export_user_preferences($user->id);
$writer = writer::with_context(context_system::instance());
$this->assertFalse($writer->has_any_data());
}
/**
* Test for provider::test_export_user_preferences().
*/
public function test_export_user_preferences(): void {
global $DB;
// Test setup.
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
set_user_preference('core_contentbank_view_list', 1);
// Test the user preferences export contains 1 user preference record for the User.
provider::export_user_preferences($user->id);
$contextuser = context_user::instance($user->id);
$writer = writer::with_context($contextuser);
$this->assertTrue($writer->has_any_data());
$prefs = $writer->get_user_preferences('core_contentbank');
$this->assertCount(1, (array) $prefs);
$this->assertEquals(1, $prefs->core_contentbank_view_list->value);
$this->assertEquals(
get_string('privacy:request:preference:set', 'core_contentbank', (object) [
'name' => 'core_contentbank_view_list',
'value' => $prefs->core_contentbank_view_list->value,
]),
$prefs->core_contentbank_view_list->description
);
}
}