Commit 39cae56e authored by ilya's avatar ilya
Browse files

Merge branch 'MDL-69092-master_lti_pagination' of https://github.com/andrewmadden/moodle

parents 83c69cdf 1c781870
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
......@@ -73,7 +73,7 @@ function(
var getDefaultPagingBarTemplateContext = function() {
return {
showitemsperpageselector: false,
itemsperpage: 35,
itemsperpage: [{value: 35, active: true}],
previous: true,
next: true,
activepagenumber: 1,
......@@ -127,7 +127,7 @@ function(
}
var context = getDefaultPagingBarTemplateContext();
context.itemsperpage = itemsPerPage;
context.itemsperpage = buildItemsPerPagePagingBarContext(itemsPerPage);
var numberOfPages = calculateNumberOfPages(numberOfItems, itemsPerPage);
for (var i = 1; i <= numberOfPages; i++) {
......@@ -347,6 +347,10 @@ function(
context.pagingdropdown = buildPagingDropdownTemplateContext(itemsPerPage, config);
} else {
context.pagingbar = buildPagingBarTemplateContext(numberOfItems, itemsPerPage);
if (config.hasOwnProperty('showFirstLast') && config.showFirstLast) {
context.pagingbar.first = true;
context.pagingbar.last = true;
}
}
return context;
......
......@@ -92,6 +92,34 @@ class behat_data_generators extends behat_base {
$this->get_instance_for_component($component)->generate_items($entity, $data);
}
/**
* Create multiple entities of one entity type.
*
* @Given :count :entitytype exist with the following data:
*
* @param string $entitytype The name of the type entity to add
* @param int $count
* @param TableNode $data
*/
public function the_following_repeated_entities_exist(string $entitytype, int $count, TableNode $data): void {
$rows = $data->getRowsHash();
$tabledata = [array_keys($rows)];
for ($current = 1; $current < $count + 1; $current++) {
$rowdata = [];
foreach ($rows as $fieldname => $fieldtemplate) {
$rowdata[$fieldname] = str_replace('[count]', $current, $fieldtemplate);
}
$tabledata[] = $rowdata;
}
if (isset($this->movedentitytypes[$entitytype])) {
$entitytype = $this->movedentitytypes[$entitytype];
}
list($component, $entity) = $this->parse_entity_type($entitytype);
$this->get_instance_for_component($component)->generate_items($entity, new TableNode($tabledata), false);
}
/**
* Creates the specified element.
*
......
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
......@@ -23,9 +23,11 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since 3.1
*/
define(['jquery', 'core/ajax', 'core/notification', 'core/templates', 'mod_lti/events', 'mod_lti/keys', 'mod_lti/tool_type',
'mod_lti/tool_proxy', 'core/str', 'core/config'],
function($, ajax, notification, templates, ltiEvents, KEYS, toolType, toolProxy, str, config) {
define(['jquery', 'core/ajax', 'core/paged_content_factory', 'core/notification', 'core/templates', 'mod_lti/events',
'mod_lti/keys', 'mod_lti/tool_types_and_proxies', 'mod_lti/tool_type', 'mod_lti/tool_proxy', 'core/str', 'core/config'],
function($, ajax,
pagedContentFactory, notification, templates, ltiEvents, KEYS,
toolTypesAndProxies, toolType, toolProxy, str, config) {
var SELECTORS = {
EXTERNAL_REGISTRATION_CONTAINER: '#external-registration-container',
......@@ -34,6 +36,7 @@ define(['jquery', 'core/ajax', 'core/notification', 'core/templates', 'mod_lti/e
CARTRIDGE_REGISTRATION_CONTAINER: '#cartridge-registration-container',
CARTRIDGE_REGISTRATION_FORM: '#cartridge-registration-form',
ADD_TOOL_FORM: '#add-tool-form',
TOOL_CARD_CONTAINER: '#tool-card-container',
TOOL_LIST_CONTAINER: '#tool-list-container',
TOOL_CREATE_BUTTON: '#tool-create-button',
TOOL_CREATE_LTILEGACY_BUTTON: '#tool-createltilegacy-button',
......@@ -52,6 +55,17 @@ define(['jquery', 'core/ajax', 'core/notification', 'core/templates', 'mod_lti/e
return $(SELECTORS.TOOL_LIST_CONTAINER);
};
/**
* Get the tool card container element.
*
* @method getToolCardContainer
* @private
* @return {Object} jQuery object
*/
const getToolCardContainer = function() {
return $(SELECTORS.TOOL_CARD_CONTAINER);
};
/**
* Get the external registration container element.
*
......@@ -285,29 +299,99 @@ define(['jquery', 'core/ajax', 'core/notification', 'core/templates', 'mod_lti/e
* @private
*/
var reloadToolList = function() {
var promise = $.Deferred();
var container = getToolListContainer();
startLoading(container);
$.when(
toolType.query(),
toolProxy.query({'orphanedonly': true})
)
.done(function(types, proxies) {
templates.render('mod_lti/tool_list', {tools: types, proxies: proxies})
.done(function(html, js) {
container.empty();
container.append(html);
templates.runTemplateJS(js);
promise.resolve();
}).fail(promise.reject);
const cardContainer = getToolCardContainer();
const listContainer = getToolListContainer();
const limit = 60;
// Get initial data with zero limit and offset.
fetchToolCount().done(function(data) {
pagedContentFactory.createWithTotalAndLimit(
data.count,
limit,
function(pagesData) {
return pagesData.map(function(pageData) {
return fetchToolData(pageData.limit, pageData.offset)
.then(function(data) {
return renderToolData(data);
});
});
},
{
'showFirstLast': true
})
.done(function(html, js) {
// Add the paged content into the page.
templates.replaceNodeContents(cardContainer, html, js);
})
.fail(promise.reject);
.always(stopLoading(listContainer));
});
startLoading(listContainer);
};
promise.fail(notification.exception)
.always(function() {
stopLoading(container);
});
/**
* Fetch the count of tool type and proxy datasets.
*
* @return {*|void}
*/
const fetchToolCount = function() {
return toolTypesAndProxies.count({'orphanedonly': true})
.done(function(data) {
return data;
}).catch(function(error) {
// Add debug message, then return empty data.
notification.exception(error);
return {
'count': 0
};
});
};
/**
* Fetch the data for tool type and proxy cards.
*
* @param {number} limit Maximum number of datasets to get.
* @param {number} offset Offset count for fetching the data.
* @return {*|void}
*/
const fetchToolData = function(limit, offset) {
const args = {'orphanedonly': true};
// Only add limit and offset to args if they are integers and not null, otherwise defaults will be used.
if (limit !== null && !Number.isNaN(limit)) {
args.limit = limit;
}
if (offset !== null && !Number.isNaN(offset)) {
args.offset = offset;
}
return toolTypesAndProxies.query(args)
.done(function(data) {
return data;
}).catch(function(error) {
// Add debug message, then return empty data.
notification.exception(error);
return {
'types': [],
'proxies': [],
'limit': limit,
'offset': offset
};
});
};
/**
* Render Tool and Proxy cards from data.
*
* @param {Object} data Contains arrays of data objects to populate cards.
* @return {*}
*/
const renderToolData = function(data) {
const context = {
tools: data.types,
proxies: data.proxies,
};
return templates.render('mod_lti/tool_list', context)
.done(function(html, js) {
return {html, js};
}
);
};
/**
......
// 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/>.
/**
* Provides an interface for external tools in the Moodle server.
*
* @module mod_lti/tool_types_and_proxies
* @class tool_types_and_proxies
* @copyright 2020 Andrew Madden <andrewmadden@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since 4.0
*/
import ajax from 'core/ajax';
/**
* Get a list of LTI tool types and tool proxies from Moodle for the given
* search args.
*
* See also:
* mod/lti/classes/external.php get_tool_types_and_proxies()
*
* @method query
* @public
* @param {Object} args Search parameters
* @return {Promise} Promise that will be resolved when the ajax call returns.
*/
export const query = (args) => {
const request = {
methodname: 'mod_lti_get_tool_types_and_proxies',
args: args || {}
};
return ajax.call([request])[0];
};
/**
* Get a count of LTI tool types and tool proxies from Moodle for the given
* search args.
*
* See also:
* mod/lti/classes/external.php get_tool_types_and_proxies_count()
*
* @method count
* @public
* @param {Object} args Search parameters
* @return {Promise} Promise that will be resolved when the ajax call returns.
*/
export const count = (args) => {
const request = {
methodname: 'mod_lti_get_tool_types_and_proxies_count',
args: args || {}
};
return ajax.call([request])[0];
};
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_lti\external;
defined('MOODLE_INTERNAL') || die();
/**
* External function for fetching all tool types and proxies.
*
* @package mod_lti
* @author Andrew Madden <andrewmadden@catalyst-au.net>
* @copyright 2021 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class get_tool_types_and_proxies extends \external_api {
/**
* Get parameter definition for get_tool_types_and_proxies().
*
* @return \external_function_parameters
*/
public static function execute_parameters(): \external_function_parameters {
return new \external_function_parameters(
[
'toolproxyid' => new \external_value(PARAM_INT, 'Tool proxy id',
VALUE_DEFAULT, 0),
'orphanedonly' => new \external_value(PARAM_BOOL, 'Orphaned tool types only',
VALUE_DEFAULT, 0),
'limit' => new \external_value(PARAM_INT, 'How many tool types displayed per page',
VALUE_DEFAULT, 60, NULL_NOT_ALLOWED),
'offset' => new \external_value(PARAM_INT, 'Current offset of tool elements',
VALUE_DEFAULT, 0, NULL_NOT_ALLOWED),
]
);
}
/**
* Get data for all tool types and tool proxies.
*
* @param int $toolproxyid The tool proxy id
* @param bool $orphanedonly Whether to get orphaned proxies only.
* @param int $limit How many elements to return if using pagination.
* @param int $offset Which chunk of elements to return is using pagination.
* @return array
*/
public static function execute($toolproxyid, $orphanedonly, $limit, $offset): array {
$params = self::validate_parameters(self::execute_parameters(),
[
'toolproxyid' => $toolproxyid,
'orphanedonly' => $orphanedonly,
'limit' => $limit,
'offset' => $offset,
]);
$toolproxyid = $params['toolproxyid'] !== null ? $params['toolproxyid'] : 0;
$orphanedonly = $params['orphanedonly'] !== null ? $params['orphanedonly'] : false;
$limit = $params['limit'] !== null ? $params['limit'] : 0;
$offset = $params['offset'] !== null ? $params['offset'] : 0;
$context = \context_system::instance();
self::validate_context($context);
require_capability('moodle/site:config', $context);
list($proxies, $types) = lti_get_lti_types_and_proxies($limit, $offset, $orphanedonly, $toolproxyid);
return [
'types' => $types,
'proxies' => $proxies,
'limit' => $limit,
'offset' => $offset,
];
}
/**
* Get return definition for get_tool_types_and_proxies.
*
* @return \external_single_structure
*/
public static function execute_returns(): \external_single_structure {
return new \external_single_structure([
'types' => \mod_lti_external::get_tool_types_returns(),
'proxies' => \mod_lti_external::get_tool_proxies_returns(),
'limit' => new \external_value(PARAM_INT, 'Limit of how many tool types to show', VALUE_OPTIONAL),
'offset' => new \external_value(PARAM_INT, 'Offset of tool types', VALUE_OPTIONAL),
]);
}
}
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_lti\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/lti/locallib.php');
/**
* External function for fetching the count of all tool types and proxies.
*
* @package mod_lti
* @author Andrew Madden <andrewmadden@catalyst-au.net>
* @copyright 2021 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class get_tool_types_and_proxies_count extends \external_api {
/**
* Get parameter definition for get_tool_types_and_proxies_count().
*
* @return \external_function_parameters
*/
public static function execute_parameters(): \external_function_parameters {
return new \external_function_parameters(
[
'toolproxyid' => new \external_value(PARAM_INT, 'Tool proxy id', VALUE_DEFAULT, 0),
'orphanedonly' => new \external_value(PARAM_BOOL, 'Orphaned tool types only', VALUE_DEFAULT, 0),
]
);
}
/**
* Get count of every tool type and tool proxy.
*
* @param int $toolproxyid The tool proxy id
* @param bool $orphanedonly Whether to get orphaned proxies only.
* @return array
*/
public static function execute($toolproxyid, $orphanedonly): array {
$params = self::validate_parameters(self::execute_parameters(),
[
'toolproxyid' => $toolproxyid,
'orphanedonly' => $orphanedonly,
]);
$toolproxyid = $params['toolproxyid'];
$orphanedonly = $params['orphanedonly'];
$context = \context_system::instance();
self::validate_context($context);
require_capability('moodle/site:config', $context);
return [
'count' => lti_get_lti_types_and_proxies_count($orphanedonly, $toolproxyid),
];
}
/**
* Get return definition for get_tool_types_and_proxies_count.
*
* @return \external_single_structure
*/
public static function execute_returns(): \external_single_structure {
return new \external_single_structure([
'count' => new \external_value(PARAM_INT, 'Total number of tool types and proxies', VALUE_REQUIRED),
]);
}
}
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_lti;
defined('MOODLE_INTERNAL') || die();
/**
* Helper class for LTI activity.
*
* @package mod_lti
* @author Andrew Madden <andrewmadden@catalyst-au.net>
* @copyright 2020 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class helper {
/**
* Get SQL to query DB for LTI tool proxy records.
*
* @param bool $orphanedonly If true, return SQL to get orphaned proxies only.
* @param bool $count If true, return SQL to get the count of the records instead of the records themselves.
* @return string SQL.
*/
public static function get_tool_proxy_sql(bool $orphanedonly = false, bool $count = false): string {
if ($count) {
$select = "SELECT count(*) as type_count";
$sort = "";
} else {
// We only want the fields from lti_tool_proxies table. Must define every column to be compatible with mysqli.
$select = "SELECT ltp.id, ltp.name, ltp.regurl, ltp.state, ltp.guid, ltp.secret, ltp.vendorcode,
ltp.capabilityoffered, ltp.serviceoffered, ltp.toolproxy, ltp.createdby,
ltp.timecreated, ltp.timemodified";
$sort = " ORDER BY ltp.name ASC, ltp.state DESC, ltp.timemodified DESC";
}
$from = " FROM {lti_tool_proxies} ltp";
if ($orphanedonly) {
$join = " LEFT JOIN {lti_types} lt ON ltp.id = lt.toolproxyid";
$where = " WHERE lt.toolproxyid IS null";
} else {
$join = "";
$where = "";
}
return $select . $from . $join . $where . $sort;
}
}
......@@ -101,6 +101,24 @@ $functions = array(
'ajax' => true
),
'mod_lti_get_tool_types_and_proxies' => [
'classname' => 'mod_lti\external\get_tool_types_and_proxies',
'methodname' => 'execute',
'description' => 'Get a list of the tool types and tool proxies',
'type' => 'read',
'capabilities' => 'moodle/site:config',
'ajax' => true
],
'mod_lti_get_tool_types_and_proxies_count' => [
'classname' => 'mod_lti\external\get_tool_types_and_proxies_count',
'methodname' => 'execute',
'description' => 'Get total number of the tool types and tool proxies',
'type' => 'read',
'capabilities' => 'moodle/site:config',
'ajax' => true
],
'mod_lti_create_tool_type' => array(
'classname' => 'mod_lti_external',
'methodname' => 'create_tool_type',
......
......@@ -51,6 +51,7 @@
defined('MOODLE_INTERNAL') || die;
// TODO: Switch to core oauthlib once implemented - MDL-30149.
use mod_lti\helper;
use moodle\mod\lti as lti;
use Firebase\JWT\JWT;
use Firebase\JWT\JWK;
......@@ -3095,6 +3096,73 @@ function lti_delete_tool_proxy($id) {
$DB->delete_records('lti_tool_proxies', array('id' => $id));
}
/**
* Get both LTI tool proxies and tool types.
*
* If limit and offset are not zero, a subset of the tools will be returned. Tool proxies will be counted before tool
* types.
* For example: If 10 tool proxies and 10 tool types exist, and the limit is set to 15, then 10 proxies and 5 types
* will be returned.
*
* @param int $limit Maximum number of tools returned.
* @param int $offset Do not return tools before offset index.
* @param bool $orphanedonly If true, only return orphaned proxies.
* @param int $toolproxyid If not 0, only return tool types that have this tool proxy id.
* @return array list(proxies[], types[]) List containing array of tool proxies and array of tool types.
*/
function lti_get_lti_types_and_proxies(int $limit = 0, int $offset = 0, bool $orphanedonly = false, int $toolproxyid = 0): array {
global $DB;