diff --git a/lib/editor/tiny/classes/manager.php b/lib/editor/tiny/classes/manager.php index 61a483b133a..4174f06a449 100644 --- a/lib/editor/tiny/classes/manager.php +++ b/lib/editor/tiny/classes/manager.php @@ -61,6 +61,8 @@ class manager { continue; } + $options['pluginname'] = $pluginname; + if (!$classname::is_enabled($context, $options, $fpoptions, $editor)) { // This plugin has disabled itself for some reason. // This is typical for media plugins where there is no file storage. diff --git a/lib/editor/tiny/classes/plugin.php b/lib/editor/tiny/classes/plugin.php index 678907eedb1..861e3784e01 100644 --- a/lib/editor/tiny/classes/plugin.php +++ b/lib/editor/tiny/classes/plugin.php @@ -34,7 +34,7 @@ use context; */ abstract class plugin { /** - * Whether the plugin is enabled + * Whether the plugin is enabled and accessible (e.g. capability checks). * * @param context $context The context that the editor is used within * @param array $options The options passed in when requesting the editor @@ -48,7 +48,18 @@ abstract class plugin { array $fpoptions, ?editor $editor = null ): bool { - return true; + $plugin = $options['pluginname']; + $capability = "tiny/$plugin:use"; + if (!get_capability_info($capability)) { + // Debug warning that the capability does not exist. + debugging( + 'The tiny ' . $plugin . ' plugin does not define the standard capability ' . $capability , + DEBUG_DEVELOPER + ); + return true; + } + + return has_capability($capability, $context); } /** diff --git a/lib/editor/tiny/plugins/accessibilitychecker/db/access.php b/lib/editor/tiny/plugins/accessibilitychecker/db/access.php new file mode 100644 index 00000000000..538f8b88154 --- /dev/null +++ b/lib/editor/tiny/plugins/accessibilitychecker/db/access.php @@ -0,0 +1,35 @@ +. + +/** + * Capabilities for the tiny_accessibilitychecker plugin. + * + * @package tiny_accessibilitychecker + * @copyright 2025 David Woloszyn + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$capabilities = [ + 'tiny/accessibilitychecker:use' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], +]; diff --git a/lib/editor/tiny/plugins/accessibilitychecker/lang/en/tiny_accessibilitychecker.php b/lib/editor/tiny/plugins/accessibilitychecker/lang/en/tiny_accessibilitychecker.php index e110639c96b..c98e0d119a5 100644 --- a/lib/editor/tiny/plugins/accessibilitychecker/lang/en/tiny_accessibilitychecker.php +++ b/lib/editor/tiny/plugins/accessibilitychecker/lang/en/tiny_accessibilitychecker.php @@ -22,6 +22,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +$string['accessibilitychecker:use'] = 'Use TinyMCE accessibility checker'; $string['emptytext'] = 'Empty text'; $string['entiredocument'] = 'Entire document'; $string['imagesmissingalt'] = 'Images require alternative text. To fix this warning, add an alt attribute to your img tags. An empty alt attribute may be used, but only when the image is purely decorative and carries no information.'; diff --git a/lib/editor/tiny/plugins/accessibilitychecker/tests/behat/accessibilitychecker.feature b/lib/editor/tiny/plugins/accessibilitychecker/tests/behat/accessibilitychecker.feature index dfc3d068e09..f5cc262e80a 100644 --- a/lib/editor/tiny/plugins/accessibilitychecker/tests/behat/accessibilitychecker.feature +++ b/lib/editor/tiny/plugins/accessibilitychecker/tests/behat/accessibilitychecker.feature @@ -52,3 +52,39 @@ Feature: Tiny editor accessibility checker When I set the field "Description" to "

Some plain text

Some more text

" And I click on the "Tools > Accessibility checker" menu item for the "Description" TinyMCE editor Then I should see "Congratulations, no accessibility issues found!" in the "Accessibility checker" "dialogue" + + @javascript + Scenario: Permissions can be configured to control access to accessibility checker + 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 | format | + | Course 1 | C1 | topics | + And the following "roles" exist: + | name | shortname | description | archetype | + | Custom teacher | custom1 | Limited permissions | editingteacher | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | teacher2 | C1 | custom1 | + And the following "activity" exists: + | activity | assign | + | course | C1 | + | name | Test assignment | + And the following "permission overrides" exist: + | capability | permission | role | contextlevel | reference | + | tiny/accessibilitychecker:use | Prohibit | custom1 | Course | C1 | + # Check plugin access as a role with prohibited permissions. + And I log in as "teacher2" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + When I click on the "Tools" menu item for the "Activity instructions" TinyMCE editor + Then I should not see "Accessibility checker" + # Check plugin access as a role with allowed permissions. + And I log in as "teacher1" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + And I click on the "Tools" menu item for the "Activity instructions" TinyMCE editor + And I should see "Accessibility checker" diff --git a/lib/editor/tiny/plugins/accessibilitychecker/version.php b/lib/editor/tiny/plugins/accessibilitychecker/version.php index c9366a5f5fe..e8001d3acdb 100644 --- a/lib/editor/tiny/plugins/accessibilitychecker/version.php +++ b/lib/editor/tiny/plugins/accessibilitychecker/version.php @@ -24,6 +24,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2024121800; +$plugin->version = 2025012300; $plugin->requires = 2024100100; $plugin->component = 'tiny_accessibilitychecker'; diff --git a/lib/editor/tiny/plugins/autosave/db/access.php b/lib/editor/tiny/plugins/autosave/db/access.php new file mode 100644 index 00000000000..ea0bcb2a9ba --- /dev/null +++ b/lib/editor/tiny/plugins/autosave/db/access.php @@ -0,0 +1,35 @@ +. + +/** + * Capabilities for the tiny_autosave plugin. + * + * @package tiny_autosave + * @copyright 2025 David Woloszyn + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$capabilities = [ + 'tiny/autosave:use' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], +]; diff --git a/lib/editor/tiny/plugins/autosave/lang/en/tiny_autosave.php b/lib/editor/tiny/plugins/autosave/lang/en/tiny_autosave.php index 3fa628aa83a..ce1cf1b0e14 100644 --- a/lib/editor/tiny/plugins/autosave/lang/en/tiny_autosave.php +++ b/lib/editor/tiny/plugins/autosave/lang/en/tiny_autosave.php @@ -22,6 +22,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +$string['autosave:use'] = 'Use TinyMCE autosave'; $string['pluginname'] = 'Autosave'; $string['privacy:metadata:database:tiny_autosave:userid'] = 'The user ID of the user who created the autosave session'; $string['privacy:metadata:database:tiny_autosave:drafttext'] = 'The text content of the autosave session'; diff --git a/lib/editor/tiny/plugins/autosave/tests/behat/autosave.feature b/lib/editor/tiny/plugins/autosave/tests/behat/autosave.feature index 4c5c05cd710..ff1a3d1500f 100644 --- a/lib/editor/tiny/plugins/autosave/tests/behat/autosave.feature +++ b/lib/editor/tiny/plugins/autosave/tests/behat/autosave.feature @@ -78,3 +78,42 @@ Feature: Tiny editor autosave And I click on "New event" "button" When I click on "Show more..." "link" in the "New event" "dialogue" Then the field "Description" matches value "" + + @javascript + Scenario: Permissions can be configured to control access to autosave + Given the following "roles" exist: + | name | shortname | description | archetype | + | Custom teacher | custom1 | Limited permissions | editingteacher | + And the following "users" exist: + | username | firstname | lastname | email | + | teacher3 | Teacher | 3 | teacher3@example.com | + And the following "course enrolments" exist: + | user | course | role | + | teacher3 | C1 | custom1 | + And the following "activity" exists: + | activity | assign | + | course | C1 | + | name | Test assignment | + And the following "permission overrides" exist: + | capability | permission | role | contextlevel | reference | + | tiny/autosave:use | Prohibit | custom1 | Course | C1 | + # Check plugin access as a role with prohibited permissions. + And I log in as "teacher3" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + And I set the field "Activity instructions" to "This is my draft" + And I log out + And I log in as "teacher3" + And I am on the "Test assignment" Activity page + When I navigate to "Settings" in current page administration + Then the field "Activity instructions" matches value "" + # Check plugin access as a role with allowed permissions. + And I log in as "teacher1" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + And I set the field "Activity instructions" to "This is my draft" + And I log out + And I log in as "teacher1" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + And the field "Activity instructions" matches value "This is my draft" diff --git a/lib/editor/tiny/plugins/autosave/version.php b/lib/editor/tiny/plugins/autosave/version.php index 1a3fddd39f7..c275f85aa67 100644 --- a/lib/editor/tiny/plugins/autosave/version.php +++ b/lib/editor/tiny/plugins/autosave/version.php @@ -24,6 +24,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2024121800; +$plugin->version = 2025012300; $plugin->requires = 2024100100; $plugin->component = 'tiny_autosave'; diff --git a/lib/editor/tiny/plugins/equation/db/access.php b/lib/editor/tiny/plugins/equation/db/access.php new file mode 100644 index 00000000000..025b275a00e --- /dev/null +++ b/lib/editor/tiny/plugins/equation/db/access.php @@ -0,0 +1,35 @@ +. + +/** + * Capabilities for the tiny_equation plugin. + * + * @package tiny_equation + * @copyright 2025 David Woloszyn + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$capabilities = [ + 'tiny/equation:use' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], +]; diff --git a/lib/editor/tiny/plugins/equation/lang/en/tiny_equation.php b/lib/editor/tiny/plugins/equation/lang/en/tiny_equation.php index 15344fe3311..4ca40eb86c7 100644 --- a/lib/editor/tiny/plugins/equation/lang/en/tiny_equation.php +++ b/lib/editor/tiny/plugins/equation/lang/en/tiny_equation.php @@ -25,6 +25,7 @@ $string['buttontitle'] = 'Equation editor'; $string['cursorinfo'] = 'An arrow indicates the position that new elements from the element library will be inserted.'; $string['editequation'] = 'Edit equation using TeX'; +$string['equation:use'] = 'Use TinyMCE equation editor'; $string['librarygroup1'] = 'Operators'; $string['librarygroup1_desc'] = 'TeX commands listed on the operators tab.'; $string['librarygroup2'] = 'Arrows'; diff --git a/lib/editor/tiny/plugins/equation/tests/behat/equation.feature b/lib/editor/tiny/plugins/equation/tests/behat/equation.feature index 9db1640761c..e6f7acd9313 100644 --- a/lib/editor/tiny/plugins/equation/tests/behat/equation.feature +++ b/lib/editor/tiny/plugins/equation/tests/behat/equation.feature @@ -34,3 +34,39 @@ Feature: Equation editor Then the field "Edit equation using" matches value " \pi " And I click on "Save equation" "button" And the field "Description" matches value "

\( \pi \)

" + + @javascript + Scenario: Permissions can be configured to control access to equation editor + 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 | format | + | Course 1 | C1 | topics | + And the following "roles" exist: + | name | shortname | description | archetype | + | Custom teacher | custom1 | Limited permissions | editingteacher | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | teacher2 | C1 | custom1 | + And the following "activity" exists: + | activity | assign | + | course | C1 | + | name | Test assignment | + And the following "permission overrides" exist: + | capability | permission | role | contextlevel | reference | + | tiny/equation:use | Prohibit | custom1 | Course | C1 | + # Check plugin access as a role with prohibited permissions. + And I log in as "teacher2" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + When I click on the "Insert" menu item for the "Activity instructions" TinyMCE editor + Then I should not see "Equation editor" + # Check plugin access as a role with allowed permissions. + And I log in as "teacher1" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + And I click on the "Insert" menu item for the "Activity instructions" TinyMCE editor + And I should see "Equation editor" diff --git a/lib/editor/tiny/plugins/equation/version.php b/lib/editor/tiny/plugins/equation/version.php index eebc0be8b18..abfa0496b27 100644 --- a/lib/editor/tiny/plugins/equation/version.php +++ b/lib/editor/tiny/plugins/equation/version.php @@ -24,6 +24,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2024121800; +$plugin->version = 2025012300; $plugin->requires = 2024100100; $plugin->component = 'tiny_equation'; diff --git a/lib/editor/tiny/plugins/h5p/classes/plugininfo.php b/lib/editor/tiny/plugins/h5p/classes/plugininfo.php index df42dbd3a1a..421610f9ae0 100644 --- a/lib/editor/tiny/plugins/h5p/classes/plugininfo.php +++ b/lib/editor/tiny/plugins/h5p/classes/plugininfo.php @@ -34,16 +34,6 @@ class plugininfo extends plugin implements plugin_with_menuitems, plugin_with_configuration { - public static function is_enabled( - context $context, - array $options, - array $fpoptions, - ?\editor_tiny\editor $editor = null - ): bool { - // Users must have permission to embed content. - return has_capability('tiny/h5p:addembed', $context); - } - public static function get_available_buttons(): array { return [ 'tiny_h5p/h5p', diff --git a/lib/editor/tiny/plugins/h5p/db/access.php b/lib/editor/tiny/plugins/h5p/db/access.php index feaf1df12e2..80f8d0db614 100644 --- a/lib/editor/tiny/plugins/h5p/db/access.php +++ b/lib/editor/tiny/plugins/h5p/db/access.php @@ -32,5 +32,12 @@ $capabilities = [ 'editingteacher' => CAP_ALLOW, ], 'clonepermissionsfrom' => 'atto/h5p:addembed', + ], + 'tiny/h5p:use' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'editingteacher' => CAP_ALLOW, + ], ] ]; diff --git a/lib/editor/tiny/plugins/h5p/lang/en/tiny_h5p.php b/lib/editor/tiny/plugins/h5p/lang/en/tiny_h5p.php index 0249cf76e22..294900308cf 100644 --- a/lib/editor/tiny/plugins/h5p/lang/en/tiny_h5p.php +++ b/lib/editor/tiny/plugins/h5p/lang/en/tiny_h5p.php @@ -32,6 +32,7 @@ $string['displayoptions'] = 'Display options'; $string['downloadbutton'] = 'Allow download'; $string['embedbutton'] = 'Embed button'; $string['h5p:addembed'] = 'Add embedded H5P'; +$string['h5p:use'] = 'Use TinyMCE H5P'; $string['h5pfile'] = 'H5P file upload'; $string['h5pfileorurl'] = 'H5P URL or file upload'; $string['h5poptions'] = 'H5P options'; diff --git a/lib/editor/tiny/plugins/h5p/tests/behat/h5p.feature b/lib/editor/tiny/plugins/h5p/tests/behat/h5p.feature index 3349af91fa4..c1bb1ef5c7a 100644 --- a/lib/editor/tiny/plugins/h5p/tests/behat/h5p.feature +++ b/lib/editor/tiny/plugins/h5p/tests/behat/h5p.feature @@ -50,12 +50,35 @@ Feature: Use the TinyMCE editor to upload an h5p package Then ".h5p-placeholder" "css_element" should exist @javascript - Scenario: When a user does not have any H5P capabilities, they cannot embed H5P content with TinyMCE - Given the following "permission overrides" exist: - | capability | permission | role | contextlevel | reference | - | tiny/h5p:addembed | Prohibit | editingteacher | Course | C1 | - When I am on the PageName1 "page activity editing" page logged in as teacher1 - Then "Insert H5P content" "button" should not exist + Scenario: Permissions can be configured to control access to H5P + Given the following "users" exist: + | username | firstname | lastname | email | + | teacher2 | Teacher | 2 | teacher2@example.com | + And the following "roles" exist: + | name | shortname | description | archetype | + | Custom teacher | custom1 | Limited permissions | editingteacher | + And the following "course enrolments" exist: + | user | course | role | + | teacher2 | C1 | custom1 | + And the following "activity" exists: + | activity | assign | + | course | C1 | + | name | Test assignment | + And the following "permission overrides" exist: + | capability | permission | role | contextlevel | reference | + | tiny/h5p:use | Prohibit | custom1 | Course | C1 | + # Check plugin access as a role with prohibited permissions. + And I log in as "teacher2" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + When I click on the "Insert" menu item for the "Activity instructions" TinyMCE editor + Then I should not see "Insert H5P content" + # Check plugin access as a role with allowed permissions. + And I log in as "teacher1" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + And I click on the "Insert" menu item for the "Activity instructions" TinyMCE editor + And I should see "Insert H5P content" @javascript Scenario: When a user does not have the Upload H5P capability, they can embed but not upload H5P content with TinyMCE diff --git a/lib/editor/tiny/plugins/h5p/version.php b/lib/editor/tiny/plugins/h5p/version.php index e402ae04520..c6a161f9515 100644 --- a/lib/editor/tiny/plugins/h5p/version.php +++ b/lib/editor/tiny/plugins/h5p/version.php @@ -24,6 +24,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2024121800; +$plugin->version = 2025021700; $plugin->requires = 2024100100; $plugin->component = 'tiny_h5p'; diff --git a/lib/editor/tiny/plugins/html/db/access.php b/lib/editor/tiny/plugins/html/db/access.php new file mode 100644 index 00000000000..47562f4925d --- /dev/null +++ b/lib/editor/tiny/plugins/html/db/access.php @@ -0,0 +1,35 @@ +. + +/** + * Capabilities for the tiny_html plugin. + * + * @package tiny_html + * @copyright 2025 David Woloszyn + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$capabilities = [ + 'tiny/html:use' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], +]; diff --git a/lib/editor/tiny/plugins/html/lang/en/tiny_html.php b/lib/editor/tiny/plugins/html/lang/en/tiny_html.php index 82af602d5a1..6c98d6580e3 100644 --- a/lib/editor/tiny/plugins/html/lang/en/tiny_html.php +++ b/lib/editor/tiny/plugins/html/lang/en/tiny_html.php @@ -25,6 +25,7 @@ defined('MOODLE_INTERNAL') || die(); +$string['html:use'] = 'Use TinyMCE HTML'; $string['pluginname'] = 'HTML'; $string['privacy:metadata'] = 'The HTML formatter plugin for TinyMCE does not store any personal data.'; diff --git a/lib/editor/tiny/plugins/html/tests/behat/html.feature b/lib/editor/tiny/plugins/html/tests/behat/html.feature index d9337eae70c..920e921c8f7 100644 --- a/lib/editor/tiny/plugins/html/tests/behat/html.feature +++ b/lib/editor/tiny/plugins/html/tests/behat/html.feature @@ -22,3 +22,40 @@ Feature: Edit HTML in TinyMCE

This is my draft

""" + + Scenario: Permissions can be configured to control access to HTML features + 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 | format | + | Course 1 | C1 | topics | + And the following "roles" exist: + | name | shortname | description | archetype | + | Custom teacher | custom1 | Limited permissions | editingteacher | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | teacher2 | C1 | custom1 | + And the following "activity" exists: + | activity | assign | + | course | C1 | + | name | Test assignment | + And the following "permission overrides" exist: + | capability | permission | role | contextlevel | reference | + | tiny/html:use | Prohibit | custom1 | Course | C1 | + # Check plugin access as a role with prohibited permissions. + And I log in as "teacher2" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + And I set the field "Activity instructions" to "

This is my draft

" + When I click on the "View > Source code" menu item for the "Activity instructions" TinyMCE editor + Then "#id_activityeditor_codeMirrorContainer" "css_element" should not exist + # Check plugin access as a role with allowed permissions. + And I log in as "teacher1" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + And I set the field "Activity instructions" to "

This is my draft

" + And I click on the "View > Source code" menu item for the "Activity instructions" TinyMCE editor + And "#id_activityeditor_codeMirrorContainer" "css_element" should exist diff --git a/lib/editor/tiny/plugins/html/version.php b/lib/editor/tiny/plugins/html/version.php index 7467bc90895..e98ac693ddc 100644 --- a/lib/editor/tiny/plugins/html/version.php +++ b/lib/editor/tiny/plugins/html/version.php @@ -25,6 +25,6 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'tiny_html'; -$plugin->version = 2024121800; +$plugin->version = 2025012300; $plugin->requires = 2024100100; $plugin->maturity = MATURITY_STABLE; diff --git a/lib/editor/tiny/plugins/link/classes/plugininfo.php b/lib/editor/tiny/plugins/link/classes/plugininfo.php index 65b5aca9343..4fe999eeb61 100644 --- a/lib/editor/tiny/plugins/link/classes/plugininfo.php +++ b/lib/editor/tiny/plugins/link/classes/plugininfo.php @@ -25,7 +25,6 @@ namespace tiny_link; use context; -use context_system; use editor_tiny\editor; use editor_tiny\plugin; use editor_tiny\plugin_with_buttons; diff --git a/lib/editor/tiny/plugins/link/db/access.php b/lib/editor/tiny/plugins/link/db/access.php new file mode 100644 index 00000000000..63259e1be07 --- /dev/null +++ b/lib/editor/tiny/plugins/link/db/access.php @@ -0,0 +1,35 @@ +. + +/** + * Capabilities for the tiny_link plugin. + * + * @package tiny_link + * @copyright 2025 David Woloszyn + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$capabilities = [ + 'tiny/link:use' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], +]; diff --git a/lib/editor/tiny/plugins/link/lang/en/tiny_link.php b/lib/editor/tiny/plugins/link/lang/en/tiny_link.php index 53597824876..e1514eb5a34 100644 --- a/lib/editor/tiny/plugins/link/lang/en/tiny_link.php +++ b/lib/editor/tiny/plugins/link/lang/en/tiny_link.php @@ -28,6 +28,7 @@ $string['enterurl'] = 'Enter a URL'; $string['openinnewwindow'] = 'Open in new window'; $string['pluginname'] = 'Link'; $string['link'] = 'Link'; +$string['link:use'] = 'Use TinyMCE link'; $string['unlink'] = 'Unlink'; $string['updatelink'] = 'Update link'; $string['privacy:metadata'] = 'The link plugin for TinyMCE does not store any personal data.'; diff --git a/lib/editor/tiny/plugins/link/tests/behat/link.feature b/lib/editor/tiny/plugins/link/tests/behat/link.feature index a08c529319a..76c1907cc5e 100644 --- a/lib/editor/tiny/plugins/link/tests/behat/link.feature +++ b/lib/editor/tiny/plugins/link/tests/behat/link.feature @@ -153,3 +153,39 @@ Feature: Add links to TinyMCE And I select the "a" element in position "0" of the "Description" TinyMCE editor When I click on the "Unlink" button for the "Description" TinyMCE editor Then the field "Description" matches value "

Moodle - Open-source learning platform

" + + @javascript + Scenario: Permissions can be configured to control access to link + 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 | format | + | Course 1 | C1 | topics | + And the following "roles" exist: + | name | shortname | description | archetype | + | Custom teacher | custom1 | Limited permissions | editingteacher | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | teacher2 | C1 | custom1 | + And the following "activity" exists: + | activity | assign | + | course | C1 | + | name | Test assignment | + And the following "permission overrides" exist: + | capability | permission | role | contextlevel | reference | + | tiny/link:use | Prohibit | custom1 | Course | C1 | + # Check plugin access as a role with prohibited permissions. + And I log in as "teacher2" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + When I click on the "Insert" menu item for the "Activity instructions" TinyMCE editor + Then I should not see "Link" + # Check plugin access as a role with allowed permissions. + And I log in as "teacher1" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + And I click on the "Insert" menu item for the "Activity instructions" TinyMCE editor + And I should see "Link" diff --git a/lib/editor/tiny/plugins/link/version.php b/lib/editor/tiny/plugins/link/version.php index 31461bb6b1e..d14249dc7de 100644 --- a/lib/editor/tiny/plugins/link/version.php +++ b/lib/editor/tiny/plugins/link/version.php @@ -24,6 +24,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2024121800; +$plugin->version = 2025012300; $plugin->requires = 2024100100; $plugin->component = 'tiny_link'; diff --git a/lib/editor/tiny/plugins/media/classes/plugininfo.php b/lib/editor/tiny/plugins/media/classes/plugininfo.php index 0085b48dc07..9d24abea173 100644 --- a/lib/editor/tiny/plugins/media/classes/plugininfo.php +++ b/lib/editor/tiny/plugins/media/classes/plugininfo.php @@ -31,15 +31,8 @@ use editor_tiny\plugin_with_menuitems; * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class plugininfo extends plugin implements plugin_with_buttons, plugin_with_menuitems, plugin_with_configuration { - /** - * Whether the plugin is enabled - * - * @param context $context The context that the editor is used within - * @param array $options The options passed in when requesting the editor - * @param array $fpoptions The filepicker options passed in when requesting the editor - * @param editor $editor The editor instance in which the plugin is initialised - * @return boolean - */ + + #[\Override] public static function is_enabled( context $context, array $options, @@ -50,10 +43,12 @@ class plugininfo extends plugin implements plugin_with_buttons, plugin_with_menu // - Not logged in or guest. // - Files are not allowed. // - Only URL are supported. + // - Don't have the correct capability. $canhavefiles = !empty($options['maxfiles']); $canhaveexternalfiles = !empty($options['return_types']) && ($options['return_types'] & FILE_EXTERNAL); - return isloggedin() && !isguestuser() && ($canhavefiles || $canhaveexternalfiles); + return isloggedin() && !isguestuser() && ($canhavefiles || $canhaveexternalfiles) && + has_capability('tiny/media:use', $context); } public static function get_available_buttons(): array { diff --git a/lib/editor/tiny/plugins/media/db/access.php b/lib/editor/tiny/plugins/media/db/access.php new file mode 100644 index 00000000000..eb29848fb57 --- /dev/null +++ b/lib/editor/tiny/plugins/media/db/access.php @@ -0,0 +1,35 @@ +. + +/** + * Capabilities for the tiny_media plugin. + * + * @package tiny_media + * @copyright 2025 David Woloszyn + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$capabilities = [ + 'tiny/media:use' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], +]; diff --git a/lib/editor/tiny/plugins/media/lang/en/tiny_media.php b/lib/editor/tiny/plugins/media/lang/en/tiny_media.php index 04f3055d2bc..8164186d326 100644 --- a/lib/editor/tiny/plugins/media/lang/en/tiny_media.php +++ b/lib/editor/tiny/plugins/media/lang/en/tiny_media.php @@ -75,6 +75,7 @@ $string['link'] = 'Link'; $string['loading'] = 'Preparing the image'; $string['loop'] = 'Loop'; $string['managefiles'] = 'Manage files'; +$string['media:use'] = 'Use TinyMCE insert media'; $string['mediabuttontitle'] = 'Multimedia'; $string['mediamanagerbuttontitle'] = 'Media manager'; $string['mediamanagerproperties'] = 'Media manager'; diff --git a/lib/editor/tiny/plugins/media/tests/behat/image.feature b/lib/editor/tiny/plugins/media/tests/behat/image.feature index 89a460d8387..dda9b229b6b 100644 --- a/lib/editor/tiny/plugins/media/tests/behat/image.feature +++ b/lib/editor/tiny/plugins/media/tests/behat/image.feature @@ -84,3 +84,39 @@ Feature: Use the TinyMCE editor to upload an image Then I should see "750" in the "#currentcount" "css_element" And I set the field "How would you describe this image to someone who can't see it?" to "Lorem ipsum dolor sit amet." And I should see "27" in the "#currentcount" "css_element" + + @javascript + Scenario: Permissions can be configured to control access to media + 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 | format | + | Course 1 | C1 | topics | + And the following "roles" exist: + | name | shortname | description | archetype | + | Custom teacher | custom1 | Limited permissions | editingteacher | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | teacher2 | C1 | custom1 | + And the following "activity" exists: + | activity | assign | + | course | C1 | + | name | Test assignment | + And the following "permission overrides" exist: + | capability | permission | role | contextlevel | reference | + | tiny/media:use | Prohibit | custom1 | Course | C1 | + # Check plugin access as a role with prohibited permissions. + And I log in as "teacher2" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + When I click on the "Insert" menu item for the "Activity instructions" TinyMCE editor + Then I should not see "Multimedia" + # Check plugin access as a role with allowed permissions. + And I log in as "teacher1" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + And I click on the "Insert" menu item for the "Activity instructions" TinyMCE editor + And I should see "Multimedia" diff --git a/lib/editor/tiny/plugins/media/version.php b/lib/editor/tiny/plugins/media/version.php index 604e1ea7217..9df8d23756f 100644 --- a/lib/editor/tiny/plugins/media/version.php +++ b/lib/editor/tiny/plugins/media/version.php @@ -24,6 +24,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2024121800; +$plugin->version = 2025012300; $plugin->requires = 2024100100; $plugin->component = 'tiny_media'; diff --git a/lib/editor/tiny/plugins/noautolink/db/access.php b/lib/editor/tiny/plugins/noautolink/db/access.php new file mode 100644 index 00000000000..cfc1326acb9 --- /dev/null +++ b/lib/editor/tiny/plugins/noautolink/db/access.php @@ -0,0 +1,35 @@ +. + +/** + * Capabilities for the tiny_noautolink plugin. + * + * @package tiny_noautolink + * @copyright 2025 David Woloszyn + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$capabilities = [ + 'tiny/noautolink:use' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], +]; diff --git a/lib/editor/tiny/plugins/noautolink/lang/en/tiny_noautolink.php b/lib/editor/tiny/plugins/noautolink/lang/en/tiny_noautolink.php index 9003d6a5c52..9251aa038e5 100644 --- a/lib/editor/tiny/plugins/noautolink/lang/en/tiny_noautolink.php +++ b/lib/editor/tiny/plugins/noautolink/lang/en/tiny_noautolink.php @@ -26,6 +26,7 @@ $string['buttontitle'] = 'No auto-link'; $string['infoaddsuccess'] = 'Auto-link prevention added.'; $string['infoemptyselection'] = 'Select text and try again.'; $string['inforemovesuccess'] = 'Auto-link prevention removed.'; +$string['noautolink:use'] = 'Use TinyMCE no auto-link'; $string['pluginname'] = 'No auto-link'; $string['privacy:metadata'] = 'The tiny_noautolink plugin does not store any personal data.'; diff --git a/lib/editor/tiny/plugins/noautolink/tests/behat/noautolink.feature b/lib/editor/tiny/plugins/noautolink/tests/behat/noautolink.feature index 74b4a2e387d..a8bc15d453e 100644 --- a/lib/editor/tiny/plugins/noautolink/tests/behat/noautolink.feature +++ b/lib/editor/tiny/plugins/noautolink/tests/behat/noautolink.feature @@ -36,3 +36,39 @@ Feature: Tiny noautolink And I select the "span" element in position "0" of the "Description" TinyMCE editor And I click on the "No auto-link" button for the "Description" TinyMCE editor And the field "Description" matches value "

Some text

" + + @javascript + Scenario: Permissions can be configured to control access to no auto-link + 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 | format | + | Course 1 | C1 | topics | + And the following "roles" exist: + | name | shortname | description | archetype | + | Custom teacher | custom1 | Limited permissions | editingteacher | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | teacher2 | C1 | custom1 | + And the following "activity" exists: + | activity | assign | + | course | C1 | + | name | Test assignment | + And the following "permission overrides" exist: + | capability | permission | role | contextlevel | reference | + | tiny/noautolink:use | Prohibit | custom1 | Course | C1 | + # Check plugin access as a role with prohibited permissions. + And I log in as "teacher2" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + When I click on the "Format" menu item for the "Activity instructions" TinyMCE editor + Then I should not see "No auto-link" + # Check plugin access as a role with allowed permissions. + And I log in as "teacher1" + And I am on the "Test assignment" Activity page + And I navigate to "Settings" in current page administration + And I click on the "Format" menu item for the "Activity instructions" TinyMCE editor + And I should see "No auto-link" diff --git a/lib/editor/tiny/plugins/noautolink/version.php b/lib/editor/tiny/plugins/noautolink/version.php index 856b485a3ab..b71c0fb6032 100644 --- a/lib/editor/tiny/plugins/noautolink/version.php +++ b/lib/editor/tiny/plugins/noautolink/version.php @@ -24,6 +24,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2024121800; // The current plugin version (Date: YYYYMMDDXX). +$plugin->version = 2025012300; // The current plugin version (Date: YYYYMMDDXX). $plugin->requires = 2024100100; // Requires this Moodle version. $plugin->component = 'tiny_noautolink'; // Full name of the plugin (used for diagnostics). diff --git a/lib/editor/tiny/plugins/premium/classes/plugininfo.php b/lib/editor/tiny/plugins/premium/classes/plugininfo.php index 17634a81df8..b62dc0867de 100644 --- a/lib/editor/tiny/plugins/premium/classes/plugininfo.php +++ b/lib/editor/tiny/plugins/premium/classes/plugininfo.php @@ -31,22 +31,14 @@ use tiny_premium\manager; */ class plugininfo extends plugin implements plugin_with_configuration { - /** - * Determine if the plugin should be enabled by checking the capability and if the Tiny Premium API key is set. - * - * @param context $context The context that the editor is used within - * @param array $options The options passed in when requesting the editor - * @param array $fpoptions The filepicker options passed in when requesting the editor - * @param editor $editor The editor instance in which the plugin is initialised - * @return bool - */ + #[\Override] public static function is_enabled( context $context, array $options, array $fpoptions, ?editor $editor = null ): bool { - return has_capability('tiny/premium:accesspremium', $context) && (get_config('tiny_premium', 'apikey') != false); + return has_capability('tiny/premium:use', $context) && (get_config('tiny_premium', 'apikey') != false); } /** @@ -64,8 +56,16 @@ class plugininfo extends plugin implements plugin_with_configuration { array $fpoptions, ?editor $editor = null ): array { + $allowedplugins = []; + + foreach (manager::get_enabled_plugins() as $plugin) { + if (has_capability("tiny/premium:use{$plugin}", $context)) { + $allowedplugins[] = $plugin; + } + } + return [ - 'premiumplugins' => implode(',', manager::get_enabled_plugins()), + 'premiumplugins' => implode(',', $allowedplugins), ]; } } diff --git a/lib/editor/tiny/plugins/premium/db/access.php b/lib/editor/tiny/plugins/premium/db/access.php index 4de2001eac4..912831ca65b 100644 --- a/lib/editor/tiny/plugins/premium/db/access.php +++ b/lib/editor/tiny/plugins/premium/db/access.php @@ -25,11 +25,138 @@ defined('MOODLE_INTERNAL') || die(); $capabilities = [ - 'tiny/premium:accesspremium' => [ - 'captype' => 'read', + 'tiny/premium:use' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + 'clonepermissionsfrom' => 'tiny/premium:accesspremium', + ], + 'tiny/premium:useadvtable' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], + 'tiny/premium:usetypography' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], + 'tiny/premium:usecasechange' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], + 'tiny/premium:usechecklist' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], + 'tiny/premium:useeditimage' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], + 'tiny/premium:useexport' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], + 'tiny/premium:usefootnotes' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], + 'tiny/premium:useformatpainter' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], + 'tiny/premium:uselinkchecker' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], + 'tiny/premium:usepageembed' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], + 'tiny/premium:usepermanentpen' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], + 'tiny/premium:usepowerpaste' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], + 'tiny/premium:usetinymcespellchecker' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], + 'tiny/premium:useautocorrect' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], + 'tiny/premium:usetableofcontents' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], + 'tiny/premium:usemath' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_USER, + 'archetypes' => [ + 'user' => CAP_ALLOW, + ], + ], + 'tiny/premium:useaccessibilitychecker' => [ + 'captype' => 'read', 'contextlevel' => CONTEXT_USER, 'archetypes' => [ 'user' => CAP_ALLOW, ], ], ]; + +$deprecatedcapabilities = [ + 'tiny/premium:accesspremium' => [ + 'replacement' => 'tiny/premium:use', + 'message' => 'This capability has been renamed', + ], +]; diff --git a/lib/editor/tiny/plugins/premium/lang/en/deprecated.txt b/lib/editor/tiny/plugins/premium/lang/en/deprecated.txt index 2c4f4c00099..08d8afb9289 100644 --- a/lib/editor/tiny/plugins/premium/lang/en/deprecated.txt +++ b/lib/editor/tiny/plugins/premium/lang/en/deprecated.txt @@ -1 +1,2 @@ helplinktext,tiny_premium +premium:accesspremium,tiny_premium diff --git a/lib/editor/tiny/plugins/premium/lang/en/tiny_premium.php b/lib/editor/tiny/plugins/premium/lang/en/tiny_premium.php index ef10836afc4..c8ef73e3c67 100644 --- a/lib/editor/tiny/plugins/premium/lang/en/tiny_premium.php +++ b/lib/editor/tiny/plugins/premium/lang/en/tiny_premium.php @@ -31,7 +31,24 @@ $string['apikey_desc'] = 'Your API key is available on your