From f1a800bb7c69f7486a6cd43fefd42b3cd9cf356c Mon Sep 17 00:00:00 2001 From: Paul Holden Date: Sat, 12 Feb 2022 09:33:00 +0000 Subject: [PATCH] MDL-73867 reportbuilder: improve performance of the editable classes. When instantiating classes that extend `inplace_editable` we can improve performance by passing persistent instances we already have, rather than re-requesting them. Add test coverage to relevant classes. --- .../custom_report_filters_exporter.php | 2 +- .../local/systemreports/report_schedules.php | 7 +- .../local/systemreports/reports_list.php | 17 ++- .../output/audience_heading_editable.php | 5 + .../output/column_aggregation_editable.php | 5 + .../output/column_heading_editable.php | 5 + .../classes/output/dynamictabs/audience.php | 2 +- .../output/filter_heading_editable.php | 5 + .../classes/output/report_name_editable.php | 8 +- .../classes/output/schedule_name_editable.php | 9 +- .../tests/behat/customreports.feature | 30 +++++ reportbuilder/tests/generator_test.php | 126 ++++++++++++++++++ .../output/audience_heading_editable_test.php | 105 +++++++++++++++ .../column_aggregation_editable_test.php | 101 ++++++++++++++ .../output/column_heading_editable_test.php | 101 ++++++++++++++ .../output/filter_heading_editable_test.php | 101 ++++++++++++++ .../output/report_name_editable_test.php | 95 +++++++++++++ .../output/schedule_name_editable_test.php | 101 ++++++++++++++ 18 files changed, 812 insertions(+), 13 deletions(-) create mode 100644 reportbuilder/tests/generator_test.php create mode 100644 reportbuilder/tests/output/audience_heading_editable_test.php create mode 100644 reportbuilder/tests/output/column_aggregation_editable_test.php create mode 100644 reportbuilder/tests/output/column_heading_editable_test.php create mode 100644 reportbuilder/tests/output/filter_heading_editable_test.php create mode 100644 reportbuilder/tests/output/report_name_editable_test.php create mode 100644 reportbuilder/tests/output/schedule_name_editable_test.php diff --git a/reportbuilder/classes/external/custom_report_filters_exporter.php b/reportbuilder/classes/external/custom_report_filters_exporter.php index d94bcaaf4f7..a61b9b453e3 100644 --- a/reportbuilder/classes/external/custom_report_filters_exporter.php +++ b/reportbuilder/classes/external/custom_report_filters_exporter.php @@ -146,7 +146,7 @@ class custom_report_filters_exporter extends exporter { $entityname = $filterinstance->get_entity_name(); $displayvalue = $filterinstance->get_header(); - $editable = new filter_heading_editable($filter->get('id')); + $editable = new filter_heading_editable(0, $filter); $activefilters[] = [ 'id' => $filter->get('id'), diff --git a/reportbuilder/classes/local/systemreports/report_schedules.php b/reportbuilder/classes/local/systemreports/report_schedules.php index c42dce210cf..b25b564c193 100644 --- a/reportbuilder/classes/local/systemreports/report_schedules.php +++ b/reportbuilder/classes/local/systemreports/report_schedules.php @@ -147,12 +147,13 @@ class report_schedules extends system_report { $this->get_schedule_entity_name() )) ->set_type(column::TYPE_TEXT) - ->add_fields("{$tablealias}.name, {$tablealias}.id") - ->set_is_sortable(true) + // We need enough fields to re-create the persistent and pass to the editable component. + ->add_fields("{$tablealias}.id, {$tablealias}.name, {$tablealias}.reportid") + ->set_is_sortable(true, ["{$tablealias}.name"]) ->add_callback(function(string $value, stdClass $schedule): string { global $PAGE; - $editable = new schedule_name_editable((int) $schedule->id); + $editable = new schedule_name_editable(0, new schedule(0, $schedule)); return $editable->render($PAGE->get_renderer('core')); }) ); diff --git a/reportbuilder/classes/local/systemreports/reports_list.php b/reportbuilder/classes/local/systemreports/reports_list.php index 58c32722398..55f9c3b9751 100644 --- a/reportbuilder/classes/local/systemreports/reports_list.php +++ b/reportbuilder/classes/local/systemreports/reports_list.php @@ -126,14 +126,19 @@ class reports_list extends system_report { $this->get_report_entity_name() )) ->set_type(column::TYPE_TEXT) - ->add_fields("{$tablealias}.name, {$tablealias}.id") - ->set_is_sortable(true) - ->add_callback(function(string $value, stdClass $row) { + // We need enough fields to re-create the persistent and pass to the editable component. + ->add_fields(implode(', ', [ + "{$tablealias}.id", + "{$tablealias}.name", + "{$tablealias}.contextid", + "{$tablealias}.type", + "{$tablealias}.usercreated", + ])) + ->set_is_sortable(true, ["{$tablealias}.name"]) + ->add_callback(static function(string $value, stdClass $report): string { global $PAGE; - $reportid = (int) $row->id; - - $editable = new report_name_editable($reportid); + $editable = new report_name_editable(0, new report(0, $report)); return $editable->render($PAGE->get_renderer('core')); }) ); diff --git a/reportbuilder/classes/output/audience_heading_editable.php b/reportbuilder/classes/output/audience_heading_editable.php index cbb119e0539..c2e0b122dd0 100644 --- a/reportbuilder/classes/output/audience_heading_editable.php +++ b/reportbuilder/classes/output/audience_heading_editable.php @@ -24,6 +24,11 @@ use core_reportbuilder\permission; use core_reportbuilder\local\audiences\base; use core_reportbuilder\local\models\audience; +defined('MOODLE_INTERNAL') || die; + +global $CFG; +require_once("{$CFG->libdir}/external/externallib.php"); + /** * Audience heading editable component * diff --git a/reportbuilder/classes/output/column_aggregation_editable.php b/reportbuilder/classes/output/column_aggregation_editable.php index 2631e72292c..7de8314d00b 100644 --- a/reportbuilder/classes/output/column_aggregation_editable.php +++ b/reportbuilder/classes/output/column_aggregation_editable.php @@ -25,6 +25,11 @@ use core_reportbuilder\permission; use core_reportbuilder\local\helpers\aggregation; use core_reportbuilder\local\models\column; +defined('MOODLE_INTERNAL') || die; + +global $CFG; +require_once("{$CFG->libdir}/external/externallib.php"); + /** * Column aggregation editable component * diff --git a/reportbuilder/classes/output/column_heading_editable.php b/reportbuilder/classes/output/column_heading_editable.php index aa70507a199..e892890b760 100644 --- a/reportbuilder/classes/output/column_heading_editable.php +++ b/reportbuilder/classes/output/column_heading_editable.php @@ -24,6 +24,11 @@ use core_reportbuilder\manager; use core_reportbuilder\permission; use core_reportbuilder\local\models\column; +defined('MOODLE_INTERNAL') || die; + +global $CFG; +require_once("{$CFG->libdir}/external/externallib.php"); + /** * Column heading editable component * diff --git a/reportbuilder/classes/output/dynamictabs/audience.php b/reportbuilder/classes/output/dynamictabs/audience.php index 15f9f59e26f..f52d98e4d22 100644 --- a/reportbuilder/classes/output/dynamictabs/audience.php +++ b/reportbuilder/classes/output/dynamictabs/audience.php @@ -106,7 +106,7 @@ class audience extends base { $persistent = $reportaudience->get_persistent(); $canedit = $reportaudience->user_can_edit(); - $editable = new audience_heading_editable($persistent->get('id')); + $editable = new audience_heading_editable(0, $persistent); $params = [ 'instanceid' => $persistent->get('id'), diff --git a/reportbuilder/classes/output/filter_heading_editable.php b/reportbuilder/classes/output/filter_heading_editable.php index ec7d8273163..9114c2e6a47 100644 --- a/reportbuilder/classes/output/filter_heading_editable.php +++ b/reportbuilder/classes/output/filter_heading_editable.php @@ -24,6 +24,11 @@ use core_reportbuilder\manager; use core_reportbuilder\permission; use core_reportbuilder\local\models\filter; +defined('MOODLE_INTERNAL') || die; + +global $CFG; +require_once("{$CFG->libdir}/external/externallib.php"); + /** * Filter heading editable component * diff --git a/reportbuilder/classes/output/report_name_editable.php b/reportbuilder/classes/output/report_name_editable.php index 882865df7d2..ab29172e012 100644 --- a/reportbuilder/classes/output/report_name_editable.php +++ b/reportbuilder/classes/output/report_name_editable.php @@ -25,6 +25,11 @@ use core\output\inplace_editable; use core_reportbuilder\permission; use core_reportbuilder\local\models\report; +defined('MOODLE_INTERNAL') || die; + +global $CFG; +require_once("{$CFG->libdir}/external/externallib.php"); + /** * Report name editable component * @@ -38,7 +43,8 @@ class report_name_editable extends inplace_editable { * Class constructor * * @param int $reportid - * @param report|null $report + * @param report|null $report The report persistent, note that in addition to id/name properties being present we also + * require the following to be correctly set in order to perform permission checks: contextid/type/usercreated */ public function __construct(int $reportid, ?report $report = null) { if ($report === null) { diff --git a/reportbuilder/classes/output/schedule_name_editable.php b/reportbuilder/classes/output/schedule_name_editable.php index 336eb70fe88..88e80d53ef4 100644 --- a/reportbuilder/classes/output/schedule_name_editable.php +++ b/reportbuilder/classes/output/schedule_name_editable.php @@ -23,6 +23,11 @@ use core\output\inplace_editable; use core_reportbuilder\permission; use core_reportbuilder\local\models\schedule; +defined('MOODLE_INTERNAL') || die; + +global $CFG; +require_once("{$CFG->libdir}/external/externallib.php"); + /** * Schedule name editable component * @@ -46,7 +51,9 @@ class schedule_name_editable extends inplace_editable { $report = $schedule->get_report(); $editable = permission::can_edit_report($report); - parent::__construct('core_reportbuilder', 'schedulename', $schedule->get('id'), $editable, $schedule->get_formatted_name(), + $displayvalue = $schedule->get_formatted_name($report->get_context()); + + parent::__construct('core_reportbuilder', 'schedulename', $schedule->get('id'), $editable, $displayvalue, $schedule->get('name'), get_string('editschedulename', 'core_reportbuilder')); } diff --git a/reportbuilder/tests/behat/customreports.feature b/reportbuilder/tests/behat/customreports.feature index 4f223119564..6fa5df5bf85 100644 --- a/reportbuilder/tests/behat/customreports.feature +++ b/reportbuilder/tests/behat/customreports.feature @@ -66,6 +66,36 @@ Feature: Manage custom reports | Name | Report source | | My report | Users | + Scenario: Create custom report as a manager + # Create a report that our manager can access, but not edit. + Given the following "core_reportbuilder > Report" exists: + | name | My report | + | source | core_user\reportbuilder\datasource\users | + And the following "core_reportbuilder > Audience" exists: + | report | My report | + | classname | core_reportbuilder\reportbuilder\audience\allusers | + | configdata | | + And the following "users" exist: + | username | firstname | lastname | + | manager1 | Manager | One | + And the following "role assigns" exist: + | user | role | contextlevel | reference | + | manager1 | manager | System | | + And I log in as "manager1" + When I navigate to "Reports > Report builder > Custom reports" in site administration + And I click on "New report" "button" + And I set the following fields in the "New report" "dialogue" to these values: + | Name | Manager report | + | Report source | Users | + And I click on "Save" "button" in the "New report" "dialogue" + And I click on "Close 'Manager report' editor" "button" + # Manager can edit their own report, but not those of other users. + And I set the field "Edit report name" in the "Manager report" "table_row" to "Manager report (renamed)" + And I open the action menu in "Manager report (renamed)" "table_row" + Then "Edit report content" "link" should be visible + And "Edit report name" "link" should not exist in the "My report" "table_row" + And ".dropdown-toggle" "css_element" should not exist in the "My report" "table_row" + Scenario: Rename custom report Given the following "core_reportbuilder > Reports" exist: | name | source | diff --git a/reportbuilder/tests/generator_test.php b/reportbuilder/tests/generator_test.php new file mode 100644 index 00000000000..77cf29f918d --- /dev/null +++ b/reportbuilder/tests/generator_test.php @@ -0,0 +1,126 @@ +. + +declare(strict_types=1); + +namespace core_reportbuilder; + +use advanced_testcase; +use core_reportbuilder_generator; +use core_reportbuilder\local\models\{audience, column, filter, report, schedule}; +use core_user\reportbuilder\datasource\users; + +/** + * Unit tests for the test data generator + * + * Note that assertions of created data content is performed in other testcases of the relevant classes, in the majority of cases + * here we just want to assert that the thing we created actually exists + * + * @package core_reportbuilder + * @covers \core_reportbuilder_generator + * @copyright 2022 Paul Holden + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class generator_test extends advanced_testcase { + + /** + * Test creating a report + */ + public function test_create_report(): void { + $this->resetAfterTest(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + + $this->assertTrue(report::record_exists($report->get('id'))); + } + + /** + * Test creating a column + */ + public function test_create_column(): void { + $this->resetAfterTest(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $column = $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:lastname']); + + $this->assertTrue(column::record_exists($column->get('id'))); + } + + /** + * Test creating a filter + */ + public function test_create_filter(): void { + $this->resetAfterTest(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $filter = $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:lastname']); + + $this->assertTrue(filter::record_exists($filter->get('id'))); + } + + /** + * Test creating a condition + */ + public function test_create_condition(): void { + $this->resetAfterTest(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $condition = $generator->create_condition(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:lastname']); + + $this->assertTrue(filter::record_exists($condition->get('id'))); + } + + /** + * Test creating an audience + */ + public function test_create_audience(): void { + $this->resetAfterTest(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $audience = $generator->create_audience(['reportid' => $report->get('id'), 'configdata' => []]); + + $this->assertTrue(audience::record_exists($audience->get_persistent()->get('id'))); + } + + /** + * Test creating a schedule + */ + public function test_create_schedule(): void { + $this->resetAfterTest(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $schedule = $generator->create_schedule(['reportid' => $report->get('id'), 'name' => 'My schedule']); + + $this->assertTrue(schedule::record_exists($schedule->get('id'))); + } +} diff --git a/reportbuilder/tests/output/audience_heading_editable_test.php b/reportbuilder/tests/output/audience_heading_editable_test.php new file mode 100644 index 00000000000..266cb49b99a --- /dev/null +++ b/reportbuilder/tests/output/audience_heading_editable_test.php @@ -0,0 +1,105 @@ +. + +declare(strict_types=1); + +namespace core_reportbuilder\output; + +use advanced_testcase; +use core_reportbuilder_generator; +use core_reportbuilder\report_access_exception; +use core_user\reportbuilder\datasource\users; + +/** + * Unit tests for the audience heading editable class + * + * @package core_reportbuilder + * @covers \core_reportbuilder\output\audience_heading_editable + * @copyright 2022 Paul Holden + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class audience_heading_editable_test extends advanced_testcase { + + /** + * Test update method + */ + public function test_update(): void { + global $PAGE; + + $this->resetAfterTest(); + $this->setAdminUser(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $audience = $generator->create_audience(['reportid' => $report->get('id'), 'configdata' => []]); + + $persistent = $audience->get_persistent(); + + $editable = audience_heading_editable::update($persistent->get('id'), 'New name'); + $result = $editable->export_for_template($PAGE->get_renderer('core')); + $this->assertEquals('New name', $result['value']); + + // Reload persistent, assert update. + $this->assertEquals('New name', $persistent->read()->get('heading')); + } + + /** + * Test update method for a user without permission to edit reports + */ + public function test_update_access_exception(): void { + $this->resetAfterTest(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $audience = $generator->create_audience(['reportid' => $report->get('id'), 'configdata' => []]); + + $user = $this->getDataGenerator()->create_user(); + $this->setUser($user); + + $this->expectException(report_access_exception::class); + $this->expectExceptionMessage('You cannot edit this report'); + audience_heading_editable::update($audience->get_persistent()->get('id'), 'New name'); + } + + /** + * Test update method via component callback + * + * @covers ::core_reportbuilder_inplace_editable + */ + public function test_update_callback(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $audience = $generator->create_audience(['reportid' => $report->get('id'), 'configdata' => []]); + + $persistent = $audience->get_persistent(); + + $params = ['audienceheading', $persistent->get('id'), 'New name']; + $editable = component_callback('core_reportbuilder', 'inplace_editable', $params); + $this->assertInstanceOf(audience_heading_editable::class, $editable); + + // Reload persistent, assert update. + $this->assertEquals('New name', $persistent->read()->get('heading')); + } +} diff --git a/reportbuilder/tests/output/column_aggregation_editable_test.php b/reportbuilder/tests/output/column_aggregation_editable_test.php new file mode 100644 index 00000000000..1c7bf1dbd87 --- /dev/null +++ b/reportbuilder/tests/output/column_aggregation_editable_test.php @@ -0,0 +1,101 @@ +. + +declare(strict_types=1); + +namespace core_reportbuilder\output; + +use advanced_testcase; +use core_reportbuilder_generator; +use core_reportbuilder\report_access_exception; +use core_user\reportbuilder\datasource\users; + +/** + * Unit tests for the column aggregation editable class + * + * @package core_reportbuilder + * @covers \core_reportbuilder\output\column_aggregation_editable + * @copyright 2022 Paul Holden + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class column_aggregation_editable_test extends advanced_testcase { + + /** + * Test update method + */ + public function test_update(): void { + global $PAGE; + + $this->resetAfterTest(); + $this->setAdminUser(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $column = $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:lastname']); + + $editable = column_aggregation_editable::update($column->get('id'), 'count'); + $result = $editable->export_for_template($PAGE->get_renderer('core')); + $this->assertEquals('count', $result['value']); + + // Reload persistent, assert update. + $this->assertEquals('count', $column->read()->get('aggregation')); + } + + /** + * Test update method for a user without permission to edit reports + */ + public function test_update_access_exception(): void { + $this->resetAfterTest(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $column = $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:lastname']); + + $user = $this->getDataGenerator()->create_user(); + $this->setUser($user); + + $this->expectException(report_access_exception::class); + $this->expectExceptionMessage('You cannot edit this report'); + column_aggregation_editable::update($column->get('id'), 'New name'); + } + + /** + * Test update method via component callback + * + * @covers ::core_reportbuilder_inplace_editable + */ + public function test_update_callback(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $column = $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:lastname']); + + $params = ['columnaggregation', $column->get('id'), 'count']; + $editable = component_callback('core_reportbuilder', 'inplace_editable', $params); + $this->assertInstanceOf(column_aggregation_editable::class, $editable); + + // Reload persistent, assert update. + $this->assertEquals('count', $column->read()->get('aggregation')); + } +} diff --git a/reportbuilder/tests/output/column_heading_editable_test.php b/reportbuilder/tests/output/column_heading_editable_test.php new file mode 100644 index 00000000000..9f02bb10109 --- /dev/null +++ b/reportbuilder/tests/output/column_heading_editable_test.php @@ -0,0 +1,101 @@ +. + +declare(strict_types=1); + +namespace core_reportbuilder\output; + +use advanced_testcase; +use core_reportbuilder_generator; +use core_reportbuilder\report_access_exception; +use core_user\reportbuilder\datasource\users; + +/** + * Unit tests for the column heading editable class + * + * @package core_reportbuilder + * @covers \core_reportbuilder\output\column_heading_editable + * @copyright 2022 Paul Holden + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class column_heading_editable_test extends advanced_testcase { + + /** + * Test update method + */ + public function test_update(): void { + global $PAGE; + + $this->resetAfterTest(); + $this->setAdminUser(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $column = $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:lastname']); + + $editable = column_heading_editable::update($column->get('id'), 'New name'); + $result = $editable->export_for_template($PAGE->get_renderer('core')); + $this->assertEquals('New name', $result['value']); + + // Reload persistent, assert update. + $this->assertEquals('New name', $column->read()->get('heading')); + } + + /** + * Test update method for a user without permission to edit reports + */ + public function test_update_access_exception(): void { + $this->resetAfterTest(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $column = $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:lastname']); + + $user = $this->getDataGenerator()->create_user(); + $this->setUser($user); + + $this->expectException(report_access_exception::class); + $this->expectExceptionMessage('You cannot edit this report'); + column_heading_editable::update($column->get('id'), 'New name'); + } + + /** + * Test update method via component callback + * + * @covers ::core_reportbuilder_inplace_editable + */ + public function test_update_callback(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $column = $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:lastname']); + + $params = ['columnheading', $column->get('id'), 'New name']; + $editable = component_callback('core_reportbuilder', 'inplace_editable', $params); + $this->assertInstanceOf(column_heading_editable::class, $editable); + + // Reload persistent, assert update. + $this->assertEquals('New name', $column->read()->get('heading')); + } +} diff --git a/reportbuilder/tests/output/filter_heading_editable_test.php b/reportbuilder/tests/output/filter_heading_editable_test.php new file mode 100644 index 00000000000..f4d5d5af5e4 --- /dev/null +++ b/reportbuilder/tests/output/filter_heading_editable_test.php @@ -0,0 +1,101 @@ +. + +declare(strict_types=1); + +namespace core_reportbuilder\output; + +use advanced_testcase; +use core_reportbuilder_generator; +use core_reportbuilder\report_access_exception; +use core_user\reportbuilder\datasource\users; + +/** + * Unit tests for the filter heading editable class + * + * @package core_reportbuilder + * @covers \core_reportbuilder\output\filter_heading_editable + * @copyright 2022 Paul Holden + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class filter_heading_editable_test extends advanced_testcase { + + /** + * Test update method + */ + public function test_update(): void { + global $PAGE; + + $this->resetAfterTest(); + $this->setAdminUser(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $filter = $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:lastname']); + + $editable = filter_heading_editable::update($filter->get('id'), 'New name'); + $result = $editable->export_for_template($PAGE->get_renderer('core')); + $this->assertEquals('New name', $result['value']); + + // Reload persistent, assert update. + $this->assertEquals('New name', $filter->read()->get('heading')); + } + + /** + * Test update method for a user without permission to edit reports + */ + public function test_update_access_exception(): void { + $this->resetAfterTest(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $filter = $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:lastname']); + + $user = $this->getDataGenerator()->create_user(); + $this->setUser($user); + + $this->expectException(report_access_exception::class); + $this->expectExceptionMessage('You cannot edit this report'); + filter_heading_editable::update($filter->get('id'), 'New name'); + } + + /** + * Test update method via component callback + * + * @covers ::core_reportbuilder_inplace_editable + */ + public function test_update_callback(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $filter = $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:lastname']); + + $params = ['filterheading', $filter->get('id'), 'New name']; + $editable = component_callback('core_reportbuilder', 'inplace_editable', $params); + $this->assertInstanceOf(filter_heading_editable::class, $editable); + + // Reload persistent, assert update. + $this->assertEquals('New name', $filter->read()->get('heading')); + } +} diff --git a/reportbuilder/tests/output/report_name_editable_test.php b/reportbuilder/tests/output/report_name_editable_test.php new file mode 100644 index 00000000000..78aac9d72c9 --- /dev/null +++ b/reportbuilder/tests/output/report_name_editable_test.php @@ -0,0 +1,95 @@ +. + +declare(strict_types=1); + +namespace core_reportbuilder\output; + +use advanced_testcase; +use core_reportbuilder_generator; +use core_reportbuilder\report_access_exception; +use core_user\reportbuilder\datasource\users; + +/** + * Unit tests for the report name editable class + * + * @package core_reportbuilder + * @covers \core_reportbuilder\output\report_name_editable + * @copyright 2022 Paul Holden + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class report_name_editable_test extends advanced_testcase { + + /** + * Test update method + */ + public function test_update(): void { + global $PAGE; + + $this->resetAfterTest(); + $this->setAdminUser(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + + $editable = report_name_editable::update($report->get('id'), 'New name'); + $result = $editable->export_for_template($PAGE->get_renderer('core')); + $this->assertEquals('New name', $result['value']); + + // Reload persistent, assert update. + $this->assertEquals('New name', $report->read()->get('name')); + } + + /** + * Test update method for a user without permission to edit reports + */ + public function test_update_access_exception(): void { + $this->resetAfterTest(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + + $user = $this->getDataGenerator()->create_user(); + $this->setUser($user); + + $this->expectException(report_access_exception::class); + $this->expectExceptionMessage('You cannot edit this report'); + report_name_editable::update($report->get('id'), 'New name'); + } + + /** + * Test update method via component callback + * + * @covers ::core_reportbuilder_inplace_editable + */ + public function test_update_callback(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + + $params = ['reportname', $report->get('id'), 'New name']; + $editable = component_callback('core_reportbuilder', 'inplace_editable', $params); + $this->assertInstanceOf(report_name_editable::class, $editable); + + // Reload persistent, assert update. + $this->assertEquals('New name', $report->read()->get('name')); + } +} diff --git a/reportbuilder/tests/output/schedule_name_editable_test.php b/reportbuilder/tests/output/schedule_name_editable_test.php new file mode 100644 index 00000000000..639626de94a --- /dev/null +++ b/reportbuilder/tests/output/schedule_name_editable_test.php @@ -0,0 +1,101 @@ +. + +declare(strict_types=1); + +namespace core_reportbuilder\output; + +use advanced_testcase; +use core_reportbuilder_generator; +use core_reportbuilder\report_access_exception; +use core_user\reportbuilder\datasource\users; + +/** + * Unit tests for the schedule name editable class + * + * @package core_reportbuilder + * @covers \core_reportbuilder\output\schedule_name_editable + * @copyright 2022 Paul Holden + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class schedule_name_editable_test extends advanced_testcase { + + /** + * Test update method + */ + public function test_update(): void { + global $PAGE; + + $this->resetAfterTest(); + $this->setAdminUser(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $schedule = $generator->create_schedule(['reportid' => $report->get('id'), 'name' => 'My schedule']); + + $editable = schedule_name_editable::update($schedule->get('id'), 'New name'); + $result = $editable->export_for_template($PAGE->get_renderer('core')); + $this->assertEquals('New name', $result['value']); + + // Reload persistent, assert update. + $this->assertEquals('New name', $schedule->read()->get('name')); + } + + /** + * Test update method for a user without permission to edit reports + */ + public function test_update_access_exception(): void { + $this->resetAfterTest(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $schedule = $generator->create_schedule(['reportid' => $report->get('id'), 'name' => 'My schedule']); + + $user = $this->getDataGenerator()->create_user(); + $this->setUser($user); + + $this->expectException(report_access_exception::class); + $this->expectExceptionMessage('You cannot edit this report'); + schedule_name_editable::update($schedule->get('id'), 'New name'); + } + + /** + * Test update method via component callback + * + * @covers ::core_reportbuilder_inplace_editable + */ + public function test_update_callback(): void { + $this->resetAfterTest(); + $this->setAdminUser(); + + /** @var core_reportbuilder_generator $generator */ + $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); + + $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); + $schedule = $generator->create_schedule(['reportid' => $report->get('id'), 'name' => 'My schedule']); + + $params = ['schedulename', $schedule->get('id'), 'New name']; + $editable = component_callback('core_reportbuilder', 'inplace_editable', $params); + $this->assertInstanceOf(schedule_name_editable::class, $editable); + + // Reload persistent, assert update. + $this->assertEquals('New name', $schedule->read()->get('name')); + } +}