This commit is contained in:
Jun Pataleta 2022-07-29 14:32:37 +08:00
commit 0fb9cdedbb
11 changed files with 244 additions and 14 deletions

View file

@ -2781,6 +2781,12 @@ $functions = array(
'type' => 'write', 'type' => 'write',
'ajax' => true, 'ajax' => true,
], ],
'core_reportbuilder_set_filters' => [
'classname' => 'core_reportbuilder\external\filters\set',
'description' => 'Set filter values for given report',
'type' => 'write',
'ajax' => true,
],
'core_dynamic_tabs_get_content' => [ 'core_dynamic_tabs_get_content' => [
'classname' => 'core\external\dynamic_tabs_get_content', 'classname' => 'core\external\dynamic_tabs_get_content',
'description' => 'Returns the content for a dynamic tab', 'description' => 'Returns the content for a dynamic tab',

View file

@ -5,6 +5,6 @@ define("core_reportbuilder/local/repository/filters",["exports","core/ajax"],(fu
* @module core_reportbuilder/local/repository/filters * @module core_reportbuilder/local/repository/filters
* @copyright 2021 Paul Holden <paulh@moodle.com> * @copyright 2021 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.resetFilters=_exports.reorderFilter=_exports.deleteFilter=_exports.addFilter=void 0,_ajax=(obj=_ajax)&&obj.__esModule?obj:{default:obj};_exports.resetFilters=reportId=>{const request={methodname:"core_reportbuilder_filters_reset",args:{reportid:reportId}};return _ajax.default.call([request])[0]};_exports.addFilter=(reportId,uniqueIdentifier)=>{const request={methodname:"core_reportbuilder_filters_add",args:{reportid:reportId,uniqueidentifier:uniqueIdentifier}};return _ajax.default.call([request])[0]};_exports.deleteFilter=(reportId,filterId)=>{const request={methodname:"core_reportbuilder_filters_delete",args:{reportid:reportId,filterid:filterId}};return _ajax.default.call([request])[0]};_exports.reorderFilter=(reportId,filterId,position)=>{const request={methodname:"core_reportbuilder_filters_reorder",args:{reportid:reportId,filterid:filterId,position:position}};return _ajax.default.call([request])[0]}})); */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.setFilters=_exports.resetFilters=_exports.reorderFilter=_exports.deleteFilter=_exports.addFilter=void 0,_ajax=(obj=_ajax)&&obj.__esModule?obj:{default:obj};_exports.resetFilters=reportId=>{const request={methodname:"core_reportbuilder_filters_reset",args:{reportid:reportId}};return _ajax.default.call([request])[0]};_exports.setFilters=(reportId,reportParameters,filterValues)=>{const request={methodname:"core_reportbuilder_set_filters",args:{reportid:reportId,parameters:reportParameters,values:filterValues}};return _ajax.default.call([request])[0]};_exports.addFilter=(reportId,uniqueIdentifier)=>{const request={methodname:"core_reportbuilder_filters_add",args:{reportid:reportId,uniqueidentifier:uniqueIdentifier}};return _ajax.default.call([request])[0]};_exports.deleteFilter=(reportId,filterId)=>{const request={methodname:"core_reportbuilder_filters_delete",args:{reportid:reportId,filterid:filterId}};return _ajax.default.call([request])[0]};_exports.reorderFilter=(reportId,filterId,position)=>{const request={methodname:"core_reportbuilder_filters_reorder",args:{reportid:reportId,filterid:filterId,position:position}};return _ajax.default.call([request])[0]}}));
//# sourceMappingURL=filters.min.js.map //# sourceMappingURL=filters.min.js.map

View file

@ -1 +1 @@
{"version":3,"file":"filters.min.js","sources":["../../../src/local/repository/filters.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Module to handle filter AJAX requests\n *\n * @module core_reportbuilder/local/repository/filters\n * @copyright 2021 Paul Holden <paulh@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\n\n/**\n * Reset all filters for given report\n *\n * @method\n * @param {Number} reportId\n * @return {Promise}\n */\nexport const resetFilters = reportId => {\n const request = {\n methodname: 'core_reportbuilder_filters_reset',\n args: {reportid: reportId}\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Add a filter to the given report\n *\n * @param {Number} reportId\n * @param {String} uniqueIdentifier\n * @return {Promise}\n */\nexport const addFilter = (reportId, uniqueIdentifier) => {\n const request = {\n methodname: 'core_reportbuilder_filters_add',\n args: {reportid: reportId, uniqueidentifier: uniqueIdentifier}\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Remove filter from given report\n *\n * @param {Number} reportId\n * @param {Number} filterId\n * @return {Promise}\n */\nexport const deleteFilter = (reportId, filterId) => {\n const request = {\n methodname: 'core_reportbuilder_filters_delete',\n args: {reportid: reportId, filterid: filterId}\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Reorder a filter in a given report\n *\n * @param {Number} reportId\n * @param {Number} filterId\n * @param {Number} position\n * @return {Promise}\n */\nexport const reorderFilter = (reportId, filterId, position) => {\n const request = {\n methodname: 'core_reportbuilder_filters_reorder',\n args: {reportid: reportId, filterid: filterId, position: position}\n };\n\n return Ajax.call([request])[0];\n};\n"],"names":["reportId","request","methodname","args","reportid","Ajax","call","uniqueIdentifier","uniqueidentifier","filterId","filterid","position"],"mappings":";;;;;;;oOAgC4BA,iBAClBC,QAAU,CACZC,WAAY,mCACZC,KAAM,CAACC,SAAUJ,kBAGdK,cAAKC,KAAK,CAACL,UAAU,uBAUP,CAACD,SAAUO,0BAC1BN,QAAU,CACZC,WAAY,iCACZC,KAAM,CAACC,SAAUJ,SAAUQ,iBAAkBD,0BAG1CF,cAAKC,KAAK,CAACL,UAAU,0BAUJ,CAACD,SAAUS,kBAC7BR,QAAU,CACZC,WAAY,oCACZC,KAAM,CAACC,SAAUJ,SAAUU,SAAUD,kBAGlCJ,cAAKC,KAAK,CAACL,UAAU,2BAWH,CAACD,SAAUS,SAAUE,kBACxCV,QAAU,CACZC,WAAY,qCACZC,KAAM,CAACC,SAAUJ,SAAUU,SAAUD,SAAUE,SAAUA,kBAGtDN,cAAKC,KAAK,CAACL,UAAU"} {"version":3,"file":"filters.min.js","sources":["../../../src/local/repository/filters.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Module to handle filter AJAX requests\n *\n * @module core_reportbuilder/local/repository/filters\n * @copyright 2021 Paul Holden <paulh@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Ajax from 'core/ajax';\n\n/**\n * Reset all filters for given report\n *\n * @method\n * @param {Number} reportId\n * @return {Promise}\n */\nexport const resetFilters = reportId => {\n const request = {\n methodname: 'core_reportbuilder_filters_reset',\n args: {reportid: reportId}\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Set filter values for given report\n *\n * @method\n * @param {Number} reportId\n * @param {String} reportParameters\n * @param {String} filterValues\n * @return {Promise}\n */\nexport const setFilters = (reportId, reportParameters, filterValues) => {\n const request = {\n methodname: 'core_reportbuilder_set_filters',\n args: {reportid: reportId, parameters: reportParameters, values: filterValues}\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Add a filter to the given report\n *\n * @param {Number} reportId\n * @param {String} uniqueIdentifier\n * @return {Promise}\n */\nexport const addFilter = (reportId, uniqueIdentifier) => {\n const request = {\n methodname: 'core_reportbuilder_filters_add',\n args: {reportid: reportId, uniqueidentifier: uniqueIdentifier}\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Remove filter from given report\n *\n * @param {Number} reportId\n * @param {Number} filterId\n * @return {Promise}\n */\nexport const deleteFilter = (reportId, filterId) => {\n const request = {\n methodname: 'core_reportbuilder_filters_delete',\n args: {reportid: reportId, filterid: filterId}\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Reorder a filter in a given report\n *\n * @param {Number} reportId\n * @param {Number} filterId\n * @param {Number} position\n * @return {Promise}\n */\nexport const reorderFilter = (reportId, filterId, position) => {\n const request = {\n methodname: 'core_reportbuilder_filters_reorder',\n args: {reportid: reportId, filterid: filterId, position: position}\n };\n\n return Ajax.call([request])[0];\n};\n"],"names":["reportId","request","methodname","args","reportid","Ajax","call","reportParameters","filterValues","parameters","values","uniqueIdentifier","uniqueidentifier","filterId","filterid","position"],"mappings":";;;;;;;wPAgC4BA,iBAClBC,QAAU,CACZC,WAAY,mCACZC,KAAM,CAACC,SAAUJ,kBAGdK,cAAKC,KAAK,CAACL,UAAU,wBAYN,CAACD,SAAUO,iBAAkBC,sBAC7CP,QAAU,CACZC,WAAY,iCACZC,KAAM,CAACC,SAAUJ,SAAUS,WAAYF,iBAAkBG,OAAQF,sBAG9DH,cAAKC,KAAK,CAACL,UAAU,uBAUP,CAACD,SAAUW,0BAC1BV,QAAU,CACZC,WAAY,iCACZC,KAAM,CAACC,SAAUJ,SAAUY,iBAAkBD,0BAG1CN,cAAKC,KAAK,CAACL,UAAU,0BAUJ,CAACD,SAAUa,kBAC7BZ,QAAU,CACZC,WAAY,oCACZC,KAAM,CAACC,SAAUJ,SAAUc,SAAUD,kBAGlCR,cAAKC,KAAK,CAACL,UAAU,2BAWH,CAACD,SAAUa,SAAUE,kBACxCd,QAAU,CACZC,WAAY,qCACZC,KAAM,CAACC,SAAUJ,SAAUc,SAAUD,SAAUE,SAAUA,kBAGtDV,cAAKC,KAAK,CAACL,UAAU"}

View file

@ -39,6 +39,24 @@ export const resetFilters = reportId => {
return Ajax.call([request])[0]; return Ajax.call([request])[0];
}; };
/**
* Set filter values for given report
*
* @method
* @param {Number} reportId
* @param {String} reportParameters
* @param {String} filterValues
* @return {Promise}
*/
export const setFilters = (reportId, reportParameters, filterValues) => {
const request = {
methodname: 'core_reportbuilder_set_filters',
args: {reportid: reportId, parameters: reportParameters, values: filterValues}
};
return Ajax.call([request])[0];
};
/** /**
* Add a filter to the given report * Add a filter to the given report
* *

View file

@ -0,0 +1,93 @@
<?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/>.
declare(strict_types=1);
namespace core_reportbuilder\external\filters;
use external_api;
use external_function_parameters;
use external_value;
use core_reportbuilder\manager;
use core_reportbuilder\permission;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once("{$CFG->libdir}/externallib.php");
/**
* External method for setting report filter values
*
* @package core_reportbuilder
* @copyright 2022 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class set extends external_api {
/**
* External method parameters
*
* @return external_function_parameters
*/
public static function execute_parameters(): external_function_parameters {
return new external_function_parameters([
'reportid' => new external_value(PARAM_INT, 'Report ID'),
'parameters' => new external_value(PARAM_RAW, 'JSON encoded report parameters', VALUE_DEFAULT, ''),
'values' => new external_value(PARAM_RAW, 'JSON encoded filter values'),
]);
}
/**
* External method execution
*
* @param int $reportid
* @param string $parameters
* @param string $values
* @return bool
*/
public static function execute(int $reportid, string $parameters, string $values): bool {
[
'reportid' => $reportid,
'parameters' => $parameters,
'values' => $values,
] = self::validate_parameters(self::execute_parameters(), [
'reportid' => $reportid,
'parameters' => $parameters,
'values' => $values,
]);
$report = manager::get_report_from_id($reportid, (array) json_decode($parameters));
self::validate_context($report->get_context());
// System report permission is implicitly handled, we need to make sure custom report can be viewed.
$persistent = $report->get_report_persistent();
if ($persistent->get('type') === $report::TYPE_CUSTOM_REPORT) {
permission::require_can_view_report($persistent);
}
return $report->set_filter_values((array) json_decode($values));
}
/**
* External method return value
*
* @return external_value
*/
public static function execute_returns(): external_value {
return new external_value(PARAM_BOOL, 'Success');
}
}

View file

@ -21,9 +21,9 @@ namespace core_reportbuilder\external;
use core\external\persistent_exporter; use core\external\persistent_exporter;
use core_table\local\filter\integer_filter; use core_table\local\filter\integer_filter;
use core_table\local\filter\string_filter; use core_table\local\filter\string_filter;
use core_reportbuilder\system_report;
use core_reportbuilder\form\filter; use core_reportbuilder\form\filter;
use core_reportbuilder\local\models\report; use core_reportbuilder\local\models\report;
use core_reportbuilder\local\report\base;
use core_reportbuilder\table\system_report_table; use core_reportbuilder\table\system_report_table;
use core_reportbuilder\table\system_report_table_filterset; use core_reportbuilder\table\system_report_table_filterset;
use renderer_base; use renderer_base;
@ -53,7 +53,7 @@ class system_report_exporter extends persistent_exporter {
*/ */
protected static function define_related(): array { protected static function define_related(): array {
return [ return [
'source' => base::class, 'source' => system_report::class,
'parameters' => 'string', 'parameters' => 'string',
]; ];
} }
@ -85,7 +85,7 @@ class system_report_exporter extends persistent_exporter {
* @return array * @return array
*/ */
protected function get_other_values(renderer_base $output): array { protected function get_other_values(renderer_base $output): array {
/** @var base $source */ /** @var system_report $source */
$source = $this->related['source']; $source = $this->related['source'];
/** @var string $parameters */ /** @var string $parameters */
@ -102,8 +102,8 @@ class system_report_exporter extends persistent_exporter {
$table = system_report_table::create($reportid, (array) json_decode($parameters, true)); $table = system_report_table::create($reportid, (array) json_decode($parameters, true));
$table->set_filterset($filterset); $table->set_filterset($filterset);
// Generate filters form if report contains any filters. // Generate filters form if report uses the default form, and contains any filters.
$filterspresent = !empty($source->get_active_filters()); $filterspresent = $source->get_filter_form_default() && !empty($source->get_active_filters());
if ($filterspresent) { if ($filterspresent) {
$filtersform = new filter(null, null, 'post', '', [], true, [ $filtersform = new filter(null, null, 'post', '', [], true, [
'reportid' => $reportid, 'reportid' => $reportid,

View file

@ -22,9 +22,9 @@ use renderable;
use renderer_base; use renderer_base;
use stdClass; use stdClass;
use templatable; use templatable;
use core_reportbuilder\system_report as system_report_base;
use core_reportbuilder\external\system_report_exporter; use core_reportbuilder\external\system_report_exporter;
use core_reportbuilder\local\models\report; use core_reportbuilder\local\models\report;
use core_reportbuilder\local\report\base;
/** /**
* System report output class * System report output class
@ -38,7 +38,7 @@ class system_report implements renderable, templatable {
/** @var report $report */ /** @var report $report */
protected $report; protected $report;
/** @var base $source */ /** @var system_report_base $source */
protected $source; protected $source;
/** @var array $parameters */ /** @var array $parameters */
@ -48,10 +48,10 @@ class system_report implements renderable, templatable {
* Class constructor * Class constructor
* *
* @param report $report * @param report $report
* @param base $source * @param system_report_base $source
* @param array $parameters * @param array $parameters
*/ */
public function __construct(report $report, base $source, array $parameters) { public function __construct(report $report, system_report_base $source, array $parameters) {
$this->report = $report; $this->report = $report;
$this->source = $source; $this->source = $source;
$this->parameters = $parameters; $this->parameters = $parameters;

View file

@ -40,6 +40,9 @@ abstract class system_report extends base {
/** @var string[] $basefields List of base fields */ /** @var string[] $basefields List of base fields */
private $basefields = []; private $basefields = [];
/** @var bool $filterformdefault Whether to use the default filters form */
private $filterformdefault = true;
/** @var action[] $actions */ /** @var action[] $actions */
private $actions = []; private $actions = [];
@ -119,6 +122,25 @@ abstract class system_report extends base {
return $this->basefields; return $this->basefields;
} }
/**
* Override whether to use the default system report filters form, for instance this can be disabled if the UI requires
* it's own custom filter management form for a specific report
*
* @param bool $filterformdefault
*/
final public function set_filter_form_default(bool $filterformdefault = true): void {
$this->filterformdefault = $filterformdefault;
}
/**
* Whether to use the default filters form
*
* @return bool
*/
final public function get_filter_form_default(): bool {
return $this->filterformdefault;
}
/** /**
* Adds an action to the report * Adds an action to the report
* *

View file

@ -0,0 +1,86 @@
<?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/>.
declare(strict_types=1);
namespace core_reportbuilder\external\filters;
use core_reportbuilder_generator;
use core_reportbuilder\manager;
use core_reportbuilder\report_access_exception;
use external_api;
use externallib_advanced_testcase;
use core_user\reportbuilder\datasource\users;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once("{$CFG->dirroot}/webservice/tests/helpers.php");
/**
* Unit tests external filters set class
*
* @package core_reportbuilder
* @covers \core_reportbuilder\external\filters\set
* @copyright 2022 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class set_test extends externallib_advanced_testcase {
/**
* Text execute method
*/
public function test_execute(): 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]);
$values = [
'entity:filter_operator' => 'something',
'entity:filter_value' => 42,
];
$result = set::execute($report->get('id'), '', json_encode($values));
$result = external_api::clean_returnvalue(set::execute_returns(), $result);
$this->assertTrue($result);
// We should get our original filter values back.
$instance = manager::get_report_from_persistent($report);
$this->assertEquals($values, $instance->get_filter_values());
}
/**
* Test execute method for a user without permission to view the report
*/
public function test_execute_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 view this report');
set::execute($report->get('id'), '', json_encode(['foo' => 1]));
}
}

View file

@ -2,11 +2,16 @@ This file describes API changes in /reportbuilder/*
Information provided here is intended especially for developers. Information provided here is intended especially for developers.
=== 4.1 === === 4.1 ===
* New external method `core_reportbuilder_set_filters` for setting report filter values (plus `setFilters` AJAX repository
export for calling from Javascript modules)
* New method `set_filter_form_default` in base system report class, to override whether the default filters form
should be shown for a report
* 'set_default_per_page' and 'get_default_per_page' methods have been added to \local\report\base class * 'set_default_per_page' and 'get_default_per_page' methods have been added to \local\report\base class
to manage the default displayed rows per page. to manage the default displayed rows per page.
* Added two new methods in the datasource class: * Added two new methods in the datasource class:
- add_all_from_entity() to add all columns/filters/conditions from the given entity to the report at once - add_all_from_entity() to add all columns/filters/conditions from the given entity to the report at once
- add_all_from_entities() to add all columns/filters/conditions from all the entities added to the report at once - add_all_from_entities() to add all columns/filters/conditions from all the entities added to the report at once
* New database helper methods for generating multiple unique values: `generate_aliases` and `generate_param_names` * New database helper methods for generating multiple unique values: `generate_aliases` and `generate_param_names`
* The base aggregation `format_value` method has a `$columntype` argument in order to preserve type during aggregation. When * The base aggregation `format_value` method has a `$columntype` argument in order to preserve type during aggregation. When
defining column callbacks, strict typing will now be preserved in your callback methods when the column is being aggregated defining column callbacks, strict typing will now be preserved in your callback methods when the column is being aggregated

View file

@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die(); defined('MOODLE_INTERNAL') || die();
$version = 2022072900.00; // YYYYMMDD = weekly release date of this DEV branch. $version = 2022072900.01; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches. // RR = release increments - 00 in DEV branches.
// .XX = incremental changes. // .XX = incremental changes.
$release = '4.1dev (Build: 20220729)'; // Human-friendly version name $release = '4.1dev (Build: 20220729)'; // Human-friendly version name