MDL-75492 mod_data: Show mapping dialog

This commit is contained in:
Amaia Anabitarte 2022-11-07 16:23:56 +01:00
parent b755cfa544
commit 81b761bab0
24 changed files with 939 additions and 32 deletions

View File

@ -0,0 +1,10 @@
define("mod_data/importmappingdialogue",["exports","core/notification","core/ajax","core/url","core/templates","core/modal_factory","core/prefetch","core/str"],(function(_exports,_notification,_ajax,_url,_templates,_modal_factory,_prefetch,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
/**
* Javascript module for deleting a database as a preset.
*
* @module mod_data/importmappingdialogue
* @copyright 2022 Amaia Anabitarte <amaia@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_notification=_interopRequireDefault(_notification),_ajax=_interopRequireDefault(_ajax),_url=_interopRequireDefault(_url),_templates=_interopRequireDefault(_templates),_modal_factory=_interopRequireDefault(_modal_factory),(0,_prefetch.prefetchStrings)("mod_data",["mapping:dialogtitle:usepreset"]);const selectors_selectPresetButton='input[name="selectpreset"]';_exports.init=()=>{registerEventListeners()};const registerEventListeners=()=>{document.addEventListener("click",(event=>{const usepreset=event.target.closest(selectors_selectPresetButton);usepreset&&(event.preventDefault(),showMappingDialogue(usepreset))}))},showMappingDialogue=usepreset=>{const presetName=usepreset.dataset.presetname,cmId=usepreset.dataset.cmid;getMappingInformation(cmId,presetName).then((result=>(result.data&&result.data.needsmapping?buildModal({title:(0,_str.get_string)("mapping:dialogtitle:usepreset","mod_data",result.data.presetname),body:_templates.default.render("mod_data/fields_mapping_body",result.data),footer:_templates.default.render("mod_data/fields_mapping_footer",getMappingButtons(cmId,presetName)),large:!0}):window.location.href=_url.default.relativeUrl("mod/data/field.php",{id:cmId,mode:"usepreset",fullname:presetName},!1),!0))).catch(_notification.default.exception)},buildModal=params=>_modal_factory.default.create({...params,type:_modal_factory.default.types.DEFAULT}).then((modal=>(modal.show(),modal.showFooter(),modal.registerCloseOnCancel(),modal))).catch(_notification.default.exception),getMappingButtons=(cmId,presetName)=>{const data={};return data.mapfieldsbutton=_url.default.relativeUrl("mod/data/field.php",{id:cmId,fullname:presetName,mode:"usepreset",action:"select"},!1),data.applybutton=_url.default.relativeUrl("mod/data/field.php",{id:cmId,fullname:presetName,mode:"usepreset",action:"notmapping"},!1),data},getMappingInformation=(cmId,presetName)=>{const request={methodname:"mod_data_get_mapping_information",args:{cmid:cmId,importedpreset:presetName}};return _ajax.default.call([request])[0]}}));
//# sourceMappingURL=importmappingdialogue.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -6,6 +6,6 @@ define("mod_data/selectpreset",["exports"],(function(_exports){Object.defineProp
* @copyright 2021 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
const selectors_presetRadioButton='input[name="fullname"]',selectors_selectPresetButton='input[name="selectpreset"]',selectors_selectedPresetRadioButton='input[name="fullname"]:checked';_exports.init=()=>{const radioButton=document.querySelectorAll(selectors_presetRadioButton);disableUsePresetButton(),radioButton.forEach((elem=>{elem.addEventListener("change",(function(event){event.preventDefault(),disableUsePresetButton()}))}))};const disableUsePresetButton=()=>{let selectPresetButton=document.querySelector(selectors_selectPresetButton);document.querySelectorAll(selectors_selectedPresetRadioButton).length>0?(selectPresetButton.removeAttribute("disabled"),selectPresetButton.classList.remove("btn-secondary"),selectPresetButton.classList.add("btn-primary")):(selectPresetButton.setAttribute("disabled",!0),selectPresetButton.classList.remove("btn-primary"),selectPresetButton.classList.add("btn-secondary"))}}));
const selectors_presetRadioButton='input[name="fullname"]',selectors_selectPresetButton='input[name="selectpreset"]',selectors_selectedPresetRadioButton='input[name="fullname"]:checked';_exports.init=()=>{const radioButton=document.querySelectorAll(selectors_presetRadioButton);disableUsePresetButton(),radioButton.forEach((elem=>{elem.addEventListener("change",(function(event){event.preventDefault(),disableUsePresetButton()}))}))};const disableUsePresetButton=()=>{let selectPresetButton=document.querySelector(selectors_selectPresetButton);const selectedRadioButton=document.querySelector(selectors_selectedPresetRadioButton);selectedRadioButton?(selectPresetButton.removeAttribute("disabled"),selectPresetButton.classList.remove("btn-secondary"),selectPresetButton.classList.add("btn-primary"),selectPresetButton.setAttribute("data-presetname",selectedRadioButton.getAttribute("value")),selectPresetButton.setAttribute("data-cmid",selectedRadioButton.getAttribute("data-cmid"))):(selectPresetButton.setAttribute("disabled",!0),selectPresetButton.classList.remove("btn-primary"),selectPresetButton.classList.add("btn-secondary"),selectPresetButton.removeAttribute("data-presetname"),selectPresetButton.removeAttribute("data-cmid"))}}));
//# sourceMappingURL=selectpreset.min.js.map

View File

@ -1 +1 @@
{"version":3,"file":"selectpreset.min.js","sources":["../src/selectpreset.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 * Javascript module to control the form responsible for selecting a preset.\n *\n * @module mod_data/selectpreset\n * @copyright 2021 Mihail Geshoski <mihail@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst selectors = {\n presetRadioButton: 'input[name=\"fullname\"]',\n selectPresetButton: 'input[name=\"selectpreset\"]',\n selectedPresetRadioButton: 'input[name=\"fullname\"]:checked',\n};\n\n/**\n * Initialize module.\n */\nexport const init = () => {\n const radioButton = document.querySelectorAll(selectors.presetRadioButton);\n\n // Initialize the \"Use a preset\" button properly.\n disableUsePresetButton();\n\n radioButton.forEach((elem) => {\n elem.addEventListener('change', function(event) {\n event.preventDefault();\n // Enable the \"Use a preset\" button when any of the radio buttons in the presets list is checked.\n disableUsePresetButton();\n });\n });\n\n};\n\n/**\n * Decide whether to disable or not the \"Use a preset\" button.\n * When there is no preset selected, the button should be displayed disabled; otherwise, it will appear enabled as a primary button.\n *\n * @method\n * @private\n */\nconst disableUsePresetButton = () => {\n let selectPresetButton = document.querySelector(selectors.selectPresetButton);\n const selectedRadioButton = document.querySelectorAll(selectors.selectedPresetRadioButton);\n\n if (selectedRadioButton.length > 0) {\n // There is one preset selected, so the button should be enabled.\n selectPresetButton.removeAttribute('disabled');\n selectPresetButton.classList.remove('btn-secondary');\n selectPresetButton.classList.add('btn-primary');\n } else {\n // There is no any preset selected, so the button should be disabled.\n selectPresetButton.setAttribute('disabled', true);\n selectPresetButton.classList.remove('btn-primary');\n selectPresetButton.classList.add('btn-secondary');\n }\n};\n"],"names":["selectors","radioButton","document","querySelectorAll","disableUsePresetButton","forEach","elem","addEventListener","event","preventDefault","selectPresetButton","querySelector","length","removeAttribute","classList","remove","add","setAttribute"],"mappings":";;;;;;;;MAuBMA,4BACiB,yBADjBA,6BAEkB,6BAFlBA,oCAGyB,+CAMX,WACVC,YAAcC,SAASC,iBAAiBH,6BAG9CI,yBAEAH,YAAYI,SAASC,OACjBA,KAAKC,iBAAiB,UAAU,SAASC,OACrCA,MAAMC,iBAENL,sCAaNA,uBAAyB,SACvBM,mBAAqBR,SAASS,cAAcX,8BACpBE,SAASC,iBAAiBH,qCAE9BY,OAAS,GAE7BF,mBAAmBG,gBAAgB,YACnCH,mBAAmBI,UAAUC,OAAO,iBACpCL,mBAAmBI,UAAUE,IAAI,iBAGjCN,mBAAmBO,aAAa,YAAY,GAC5CP,mBAAmBI,UAAUC,OAAO,eACpCL,mBAAmBI,UAAUE,IAAI"}
{"version":3,"file":"selectpreset.min.js","sources":["../src/selectpreset.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 * Javascript module to control the form responsible for selecting a preset.\n *\n * @module mod_data/selectpreset\n * @copyright 2021 Mihail Geshoski <mihail@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst selectors = {\n presetRadioButton: 'input[name=\"fullname\"]',\n selectPresetButton: 'input[name=\"selectpreset\"]',\n selectedPresetRadioButton: 'input[name=\"fullname\"]:checked',\n};\n\n/**\n * Initialize module.\n */\nexport const init = () => {\n const radioButton = document.querySelectorAll(selectors.presetRadioButton);\n\n // Initialize the \"Use a preset\" button properly.\n disableUsePresetButton();\n\n radioButton.forEach((elem) => {\n elem.addEventListener('change', function(event) {\n event.preventDefault();\n // Enable the \"Use a preset\" button when any of the radio buttons in the presets list is checked.\n disableUsePresetButton();\n });\n });\n\n};\n\n/**\n * Decide whether to disable or not the \"Use a preset\" button.\n * When there is no preset selected, the button should be displayed disabled; otherwise, it will appear enabled as a primary button.\n *\n * @method\n * @private\n */\nconst disableUsePresetButton = () => {\n let selectPresetButton = document.querySelector(selectors.selectPresetButton);\n const selectedRadioButton = document.querySelector(selectors.selectedPresetRadioButton);\n\n if (selectedRadioButton) {\n // There is one preset selected, so the button should be enabled.\n selectPresetButton.removeAttribute('disabled');\n selectPresetButton.classList.remove('btn-secondary');\n selectPresetButton.classList.add('btn-primary');\n selectPresetButton.setAttribute('data-presetname', selectedRadioButton.getAttribute('value'));\n selectPresetButton.setAttribute('data-cmid', selectedRadioButton.getAttribute('data-cmid'));\n } else {\n // There is no any preset selected, so the button should be disabled.\n selectPresetButton.setAttribute('disabled', true);\n selectPresetButton.classList.remove('btn-primary');\n selectPresetButton.classList.add('btn-secondary');\n selectPresetButton.removeAttribute('data-presetname');\n selectPresetButton.removeAttribute('data-cmid');\n }\n};\n"],"names":["selectors","radioButton","document","querySelectorAll","disableUsePresetButton","forEach","elem","addEventListener","event","preventDefault","selectPresetButton","querySelector","selectedRadioButton","removeAttribute","classList","remove","add","setAttribute","getAttribute"],"mappings":";;;;;;;;MAuBMA,4BACiB,yBADjBA,6BAEkB,6BAFlBA,oCAGyB,+CAMX,WACVC,YAAcC,SAASC,iBAAiBH,6BAG9CI,yBAEAH,YAAYI,SAASC,OACjBA,KAAKC,iBAAiB,UAAU,SAASC,OACrCA,MAAMC,iBAENL,sCAaNA,uBAAyB,SACvBM,mBAAqBR,SAASS,cAAcX,oCAC1CY,oBAAsBV,SAASS,cAAcX,qCAE/CY,qBAEAF,mBAAmBG,gBAAgB,YACnCH,mBAAmBI,UAAUC,OAAO,iBACpCL,mBAAmBI,UAAUE,IAAI,eACjCN,mBAAmBO,aAAa,kBAAmBL,oBAAoBM,aAAa,UACpFR,mBAAmBO,aAAa,YAAaL,oBAAoBM,aAAa,gBAG9ER,mBAAmBO,aAAa,YAAY,GAC5CP,mBAAmBI,UAAUC,OAAO,eACpCL,mBAAmBI,UAAUE,IAAI,iBACjCN,mBAAmBG,gBAAgB,mBACnCH,mBAAmBG,gBAAgB"}

View File

@ -0,0 +1,164 @@
// 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/>.
/**
* Javascript module for deleting a database as a preset.
*
* @module mod_data/importmappingdialogue
* @copyright 2022 Amaia Anabitarte <amaia@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import Notification from 'core/notification';
import Ajax from 'core/ajax';
import Url from 'core/url';
import Templates from 'core/templates';
import ModalFactory from 'core/modal_factory';
import {prefetchStrings} from 'core/prefetch';
import {get_string as getString} from 'core/str';
// Load global strings.
prefetchStrings('mod_data', ['mapping:dialogtitle:usepreset']);
const selectors = {
selectPresetButton: 'input[name="selectpreset"]',
};
/**
* Initialize module
*/
export const init = () => {
registerEventListeners();
};
/**
* Register events.
*/
const registerEventListeners = () => {
document.addEventListener('click', (event) => {
const usepreset = event.target.closest(selectors.selectPresetButton);
if (usepreset) {
event.preventDefault();
showMappingDialogue(usepreset);
}
});
};
/**
* Show the confirmation modal for uploading a preset.
*
* @param {HTMLElement} usepreset the preset to import.
*/
const showMappingDialogue = (usepreset) => {
const presetName = usepreset.dataset.presetname;
const cmId = usepreset.dataset.cmid;
getMappingInformation(cmId, presetName).then((result) => {
if (result.data && result.data.needsmapping) {
buildModal({
title: getString('mapping:dialogtitle:usepreset', 'mod_data', result.data.presetname),
body: Templates.render('mod_data/fields_mapping_body', result.data),
footer: Templates.render('mod_data/fields_mapping_footer', getMappingButtons(cmId, presetName)),
large: true,
});
} else {
window.location.href = Url.relativeUrl(
'mod/data/field.php',
{
id: cmId,
mode: 'usepreset',
fullname: presetName,
},
false
);
}
return true;
}).catch(Notification.exception);
};
/**
* Given an object we want to build a modal ready to show
*
* @method buildModal
* @param {Object} params the modal params
* @param {Promise} params.title
* @param {Promise} params.body
* @param {Promise} params.footer
* @return {Object} The modal ready to display immediately and render body in later.
*/
const buildModal = (params) => {
return ModalFactory.create({
...params,
type: ModalFactory.types.DEFAULT,
}).then(modal => {
modal.show();
modal.showFooter();
modal.registerCloseOnCancel();
return modal;
}).catch(Notification.exception);
};
/**
* Add buttons to render on mapping modal.
*
* @param {int} cmId The id of the current database activity.
* @param {string} presetName The preset name to delete.
* @return {array} Same data with buttons.
*/
const getMappingButtons = (cmId, presetName) => {
const data = {};
data.mapfieldsbutton = Url.relativeUrl(
'mod/data/field.php',
{
id: cmId,
fullname: presetName,
mode: 'usepreset',
action: 'select',
},
false
);
data.applybutton = Url.relativeUrl(
'mod/data/field.php',
{
id: cmId,
fullname: presetName,
mode: 'usepreset',
action: 'notmapping'
},
false
);
return data;
};
/**
* Check whether we should show the mapping dialogue or not.
*
* @param {int} cmId The id of the current database activity.
* @param {string} presetName The preset name to delete.
* @return {promise} Resolved with the result and warnings of deleting a preset.
*/
const getMappingInformation = (cmId, presetName) => {
const request = {
methodname: 'mod_data_get_mapping_information',
args: {
cmid: cmId,
importedpreset: presetName,
}
};
return Ajax.call([request])[0];
};

View File

@ -55,17 +55,21 @@ export const init = () => {
*/
const disableUsePresetButton = () => {
let selectPresetButton = document.querySelector(selectors.selectPresetButton);
const selectedRadioButton = document.querySelectorAll(selectors.selectedPresetRadioButton);
const selectedRadioButton = document.querySelector(selectors.selectedPresetRadioButton);
if (selectedRadioButton.length > 0) {
if (selectedRadioButton) {
// There is one preset selected, so the button should be enabled.
selectPresetButton.removeAttribute('disabled');
selectPresetButton.classList.remove('btn-secondary');
selectPresetButton.classList.add('btn-primary');
selectPresetButton.setAttribute('data-presetname', selectedRadioButton.getAttribute('value'));
selectPresetButton.setAttribute('data-cmid', selectedRadioButton.getAttribute('data-cmid'));
} else {
// There is no any preset selected, so the button should be disabled.
selectPresetButton.setAttribute('disabled', true);
selectPresetButton.classList.remove('btn-primary');
selectPresetButton.classList.add('btn-secondary');
selectPresetButton.removeAttribute('data-presetname');
selectPresetButton.removeAttribute('data-cmid');
}
};

View File

@ -0,0 +1,97 @@
<?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_data\external;
use core\notification;
use mod_data\local\importer\preset_importer;
use mod_data\manager;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir . '/externallib.php');
/**
* This is the external method for deleting a saved preset.
*
* @package mod_data
* @since Moodle 4.1
* @copyright 2022 Amaia Anabitarte <amaia@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class get_mapping_information extends \external_api {
/**
* Parameters.
*
* @return \external_function_parameters
*/
public static function execute_parameters(): \external_function_parameters {
return new \external_function_parameters([
'cmid' => new \external_value(PARAM_INT, 'Id of the data activity', VALUE_REQUIRED),
'importedpreset' => new \external_value(PARAM_TEXT, 'Preset to be imported'),
]);
}
/**
* Get importing information for the given database course module.
*
* @param int $cmid Id of the course module where to import the preset.
* @param string $importedpreset Plugin or saved preset to be imported.
* @return array Information needed to decide whether to show the dialogue or not.
*/
public static function execute(int $cmid, string $importedpreset): array {
$params = self::validate_parameters(
self::execute_parameters(),
['cmid' => $cmid, 'importedpreset' => $importedpreset]
);
try {
// Let's get the manager.
list($course, $cm) = get_course_and_cm_from_cmid($params['cmid'], manager::MODULE);
$manager = manager::create_from_coursemodule($cm);
$importer = preset_importer::create_from_plugin_or_directory($manager, $params['importedpreset']);
$result['data'] = $importer->get_mapping_information();
} catch (\moodle_exception $e) {
$result['warnings'][] = [
'item' => $importedpreset,
'warningcode' => 'exception',
'message' => $e->getMessage()
];
notification::error($e->getMessage());
}
return $result;
}
/**
* Return.
*
* @return \external_single_structure
*/
public static function execute_returns(): \external_single_structure {
return new \external_single_structure([
'data' => new \external_single_structure([
'needsmapping' => new \external_value(PARAM_BOOL, 'Whether the importing needs mapping or not'),
'presetname' => new \external_value(PARAM_TEXT, 'Name of the applied preset'),
'fieldstocreate' => new \external_value(PARAM_TEXT, 'List of field names to create'),
'fieldstoremove' => new \external_value(PARAM_TEXT, 'List of field names to remove'),
], 'Information to import if everything went fine', VALUE_OPTIONAL),
'warnings' => new \external_warnings(),
]);
}
}

View File

@ -448,17 +448,64 @@ abstract class preset_importer {
* @throws \moodle_exception when the file provided as parameter (POST or GET) does not exist
*/
public static function create_from_parameters(manager $manager): preset_importer {
global $CFG;
$fullname = optional_param('fullname', '', PARAM_PATH); // Directory the preset is in.
if (!$fullname) {
$presetdir = $CFG->tempdir . '/forms/' . required_param('directory', PARAM_FILE);
if (!file_exists($presetdir) || !is_dir($presetdir)) {
throw new \moodle_exception('cannotimport');
}
$importer = new preset_upload_importer($manager, $presetdir);
} else {
$importer = new preset_existing_importer($manager, $fullname);
$fullname = required_param('directory', PARAM_FILE);
}
return $importer;
return self::create_from_plugin_or_directory($manager, $fullname);
}
/**
* Get the right importer instance from the provided parameters (POST or GET)
*
* @param manager $manager the current database manager
* @param string $pluginordirectory The plugin name or directory to create the importer from.
* @return preset_importer the relevant preset_importer instance
*/
public static function create_from_plugin_or_directory(manager $manager, string $pluginordirectory): preset_importer {
global $CFG;
if (!$pluginordirectory) {
throw new \moodle_exception('emptypresetname', 'mod_data');
}
try {
$presetdir = $CFG->tempdir . '/forms/' . $pluginordirectory;
if (file_exists($presetdir) && is_dir($presetdir)) {
return new preset_upload_importer($manager, $presetdir);
} else {
return new preset_existing_importer($manager, $pluginordirectory);
}
} catch (\moodle_exception $e) {
throw new \moodle_exception('errorpresetnotfound', 'mod_data', '', $pluginordirectory);
}
}
/**
* Get the information needed to decide the modal
*
* @return array An array with all the information to decide the mapping
*/
public function get_mapping_information(): array {
return [
'needsmapping' => $this->needs_mapping(),
'presetname' => preset::get_name_from_plugin($this->get_directory()),
'fieldstocreate' => $this->get_field_names($this->fieldstocreate),
'fieldstoremove' => $this->get_field_names($this->fieldstoremove),
];
}
/**
* Returns a list of the fields
*
* @param array $fields Array of fields to get name from.
* @return string A string listing the names of the fields.
*/
public function get_field_names(array $fields): string {
$fieldnames = array_map(function($field) {
return $field->name;
}, $fields);
return implode(', ', $fieldnames);
}
}

View File

@ -83,7 +83,7 @@ class preset_preview implements templatable, renderable {
* @return array
*/
public function export_for_template(\renderer_base $output): array {
$instance = $this->manager->get_instance();
$coursemodule = $this->manager->get_coursemodule();
$preset = $this->preset;
// Get fields for preview.
@ -107,7 +107,7 @@ class preset_preview implements templatable, renderable {
}
return [
'd' => $instance->id,
'cmid' => $coursemodule->id,
'description' => $preset->description ?? '',
'preview' => $content,
'formactionurl' => $useurl->out(),

View File

@ -102,6 +102,7 @@ class presets implements templatable, renderable {
$fullname = $preset->get_fullname();
$id = $this->manager->get_instance()->id;
$cmid = $this->manager->get_coursemodule()->id;
$previewurl = new moodle_url(
'/mod/data/preset.php',
['d' => $id, 'fullname' => $fullname, 'action' => 'preview']
@ -109,6 +110,7 @@ class presets implements templatable, renderable {
$presets[] = [
'id' => $id,
'cmid' => $cmid,
'name' => $preset->name,
'url' => $previewurl->out(),
'shortname' => $preset->shortname,

View File

@ -576,7 +576,8 @@ class preset {
* @return string The plugin preset name to display.
*/
public static function get_name_from_plugin(string $pluginname): string {
if ($pos = strpos($pluginname, '/')) {
$pos = strpos($pluginname, '/');
if ($pos !== false) {
$pluginname = substr($pluginname, $pos + 1);
}
if (!strpos(trim($pluginname), ' ') && get_string_manager()->string_exists('modulename', 'datapreset_'.$pluginname)) {

View File

@ -122,4 +122,11 @@ $functions = array(
'ajax' => true,
'capabilities' => 'mod/data:manageuserpresets',
),
'mod_data_get_mapping_information' => array(
'classname' => 'mod_data\external\get_mapping_information',
'description' => 'Get importing information',
'type' => 'read',
'ajax' => true,
'capabilities' => 'mod/data:managetemplates',
),
);

View File

@ -255,7 +255,7 @@ switch ($mode) {
case 'usepreset':
$importer = preset_importer::create_from_parameters($manager);
if (!$importer->needs_mapping()) {
if (!$importer->needs_mapping() || $action == 'notmapping') {
$backurl = new moodle_url('/mod/data/field.php', ['id' => $cm->id]);
if ($importer->import(false)) {
notification::success(get_string('importsuccess', 'mod_data'));

View File

@ -146,6 +146,7 @@ $string['eventrecordupdated'] = 'Record updated';
$string['eventtemplateupdated'] = 'Template updated';
$string['eventtemplateviewed'] = 'Templates viewed';
$string['fileencoding'] = 'Encoding';
$string['emptypresetname'] = 'Preset name or file cannot be empty';
$string['entries'] = 'Entries';
$string['entrieslefttoadd'] = 'You must add {$a->entriesleft} more entry/entries in order to complete this activity';
$string['entrieslefttoaddtoview'] = 'You must add {$a->entrieslefttoview} more entry/entries before you can view other participants\' entries.';
@ -155,6 +156,7 @@ $string['errormustbeteacher'] = 'You need to be a teacher to use this page!';
$string['errorpresetexists'] = 'A preset with this name already exists.';
$string['errorpresetexistsbutnotoverwrite'] = 'A preset with this name already exists. Choose a different name.';
$string['errormustsupplyvalue'] = 'You must supply a value here.';
$string['errorpresetnotfound'] = 'Preset with name {$a} not found.';
$string['example'] = 'Database module example';
$string['excel'] = 'Excel';
$string['export'] = 'Export';
@ -271,6 +273,13 @@ $string['manageapproved_help'] = 'If disabled, approved entries are no longer ed
$string['mapexistingfield'] = 'Map to {$a}';
$string['mapnewfield'] = 'Create a new field';
$string['mappingwarning'] = 'All old fields not mapped to a new field will be lost and all data in that field will be removed.';
$string['mapping:fieldstocreate'] = 'Fields to be created: {$a}';
$string['mapping:fieldstodelete'] = 'Existing fields to be deleted: {$a}';
$string['mapping:warningmessagedeleteandcreate'] = 'If fields to be deleted are of the same type as fields to be created, you may be able to map them in Map fields.';
$string['mapping:warningmessagedelete'] = 'If fields to be deleted are of the same type as new fields in the preset you\'re applying, you may be able to map them in Map fields.';
$string['mapping:mapfields'] = 'Map fields';
$string['mapping:applypresets'] = 'Apply preset';
$string['mapping:dialogtitle:usepreset'] = 'Apply preset {$a}?';
$string['maxentries'] = 'Maximum number of entries';
$string['maxentries_help'] = 'The maximum number of entries a student is allowed to submit for this activity.';
$string['maxsize'] = 'Maximum size';

View File

@ -198,6 +198,7 @@
.entriesactions .dropdown-toggle:hover,
.entriesactions .show > .btn-secondary.dropdown-toggle,
#page-mod-data-view .whitebutton .btn-secondary,
#page-mod-data-preset .whitebutton .btn-secondary,
#page-mod-data-field- .whitebutton .btn-secondary,
#page-mod-data-templates .whitebutton .btn-secondary {
background: white;

View File

@ -0,0 +1,48 @@
{{!
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/>.
}}
{{!
@template mod_data/field_mapping_modal
Display a modal to decide on field mapping
Example context (json):
{
"presetname": "Image gallery",
"fieldstocreate": "A, B, C",
"fieldstodelete": "A, B, C",
"cancelbutton": "",
"mapfieldsbutton": "",
"applybutton": ""
}
}}
<div class="p-2">
{{#fieldstocreate}}
<div class="my-2"><span>{{#str}}mapping:fieldstocreate, mod_data, {{.}}{{/str}}</span></div>
{{/fieldstocreate}}
{{#fieldstoremove}}
<div class="my-2">
<span>{{#str}}mapping:fieldstodelete, mod_data, {{.}}{{/str}}</span>
</div>
{{#fieldstocreate}}
<div class="my-2">
{{#str}}mapping:warningmessagedeleteandcreate, mod_data{{/str}}
</div>
{{/fieldstocreate}}
{{^fieldstocreate}}
<div class="my-2">
{{#str}}mapping:warningmessagedelete, mod_data{{/str}}
</div>
{{/fieldstocreate}}
{{/fieldstoremove}}
</div>

View File

@ -0,0 +1,33 @@
{{!
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/>.
}}
{{!
@template mod_data/field_mapping_modal
Display a modal to decide on field mapping
Example context (json):
{
"mapfieldsbutton": "",
"applybutton": ""
}
}}
<button class="btn" data-action="cancel">
{{#str}} cancel {{/str}}
</button>
<a href="{{mapfieldsbutton}}" class="btn btn-secondary" role="button" data-action="mapfields">
{{#str}} mapping:mapfields, mod_data {{/str}}
</a>
<a href="{{applybutton}}" class="btn btn-primary" role="button" data-action="applypreset">
{{#str}} mapping:applypresets, mod_data {{/str}}
</a>

View File

@ -19,7 +19,7 @@
Example context (json):
{
"formactionurl": "#",
"d": "42",
"cmid": "42",
"description": "Preset description",
"preview": "<p>The preset preview HTML</p>",
"userid": "0",
@ -34,11 +34,18 @@
{{< core/sticky_footer }}
{{$ stickycontent }}
<form method="post" action="{{formactionurl}}">
<input type="hidden" name="d" value="{{d}}">
<input type="hidden" name="cmid" value="{{cmid}}">
<input type="hidden" name="mode" value="usepreset">
<input type="hidden" name="action" value="select">
<input type="hidden" name="fullname" value="{{userid}}/{{shortname}}">
<input type="submit" name="selectpreset" value="{{#str}}usepreset, mod_data{{/str}}" class="btn btn-primary">
<input type="submit" name="selectpreset" value="{{#str}}usepreset, mod_data{{/str}}" class="btn btn-primary"
data-cmid="{{cmid}}" data-presetname="{{userid}}/{{shortname}}">
</form>
{{/ stickycontent }}
{{/ core/sticky_footer }}
{{#js}}
require(['mod_data/importmappingdialogue'], function(importPreset) {
importPreset.init();
});
{{/js}}

View File

@ -28,6 +28,7 @@
"presets": [
{
"id": 1,
"cmid": 1,
"name": "Image gallery",
"shortname": "imagegallery",
"fullname": "Image gallery",
@ -38,6 +39,7 @@
},
{
"id": 2,
"cmid": 2,
"name": "Preset saved manually",
"shortname": "Preset saved manually",
"fullname": "Preset saved manually (admin)",
@ -68,7 +70,7 @@
{{#presets}}
<tr>
<td class="p-4 border-right">
<input type="radio" name="fullname" value="{{userid}}/{{shortname}}" />
<input type="radio" name="fullname" value="{{userid}}/{{shortname}}" data-cmid="{{cmid}}" />
</td>
<td class="p-4">
<a href="{{{url}}}">{{fullname}}</a>
@ -104,8 +106,10 @@
selectPreset.init();
});
require(['mod_data/editpreset'], function(editPreset) {
editPreset.init();
});
require(['mod_data/importmappingdialogue'], function(importPreset) {
importPreset.init();
});
{{/js}}

View File

@ -161,5 +161,5 @@ Feature: Users can preview presets
When I follow "Presets"
And I click on "Saved preset by teacher1" "link"
And I click on "Use this preset" "button"
Then I should see "Field mappings"
Then I should see "The preset has been successfully applied"
And I should see "My URL field"

View File

@ -20,6 +20,7 @@ Feature: Users can use predefined presets
And the following "mod_data > fields" exist:
| database | type | name | description |
| data1 | text | Test field name | Test field description |
Scenario: Using a preset on a non empty database could create new fields
Given the following "mod_data > fields" exist:
| database | type | name |
@ -32,10 +33,13 @@ Feature: Users can use predefined presets
And I follow "Presets"
And I click on "fullname" "radio" in the "Image gallery" "table_row"
And I click on "Use this preset" "button"
And I should see "Apply preset Image gallery"
And I click on "Map fields" "button"
And I should see "Field mappings"
And I click on "Continue" "button"
And I should see "The preset has been successfully applied"
And I click on "Continue" "button"
And I follow "Fields"
When I follow "Fields"
Then I should see "title"
And I should see "description" in the "description" "table_row"
And I should see "image" in the "image" "table_row"
@ -53,6 +57,10 @@ Feature: Users can use predefined presets
And I click on "fullname" "radio" in the "Image gallery" "table_row"
And I click on "Use this preset" "button"
# Let's map a field that is not mapped by default
And I should see "Apply preset Image gallery"
And I should see "Fields to be created: image, title, description"
And I should see "Existing fields to be deleted: Test field name, oldtitle"
When I click on "Map fields" "button"
And I should see "Create a new field" in the "oldtitle" "table_row"
And I set the field "id_title" to "Map to oldtitle"
And I click on "Continue" "button"
@ -73,7 +81,9 @@ Feature: Users can use predefined presets
And I follow "Presets"
And I click on "fullname" "radio" in the "Image gallery" "table_row"
And the "Use this preset" "button" should be enabled
Then I click on "Use this preset" "button"
When I click on "Use this preset" "button"
And I should see "Apply preset Image gallery"
And I click on "Map fields" "button"
Then I should see "Field mappings"
And I should see "title"
And I should see "Create a new field" in the "title" "table_row"
@ -91,15 +101,15 @@ Feature: Users can use predefined presets
And I follow "Presets"
And I click on "fullname" "radio" in the "Image gallery" "table_row"
When I click on "Use this preset" "button"
And I should see "Field mappings"
And I should see "Apply preset"
And I click on "Map fields" "button"
And I set the field "id_title" to "Map to Test field name"
And I click on "Continue" "button"
And I should see "The preset has been successfully applied"
And I click on "Continue" "button"
And I follow "Presets"
And I click on "fullname" "radio" in the "Image gallery" "table_row"
And I click on "Use this preset" "button"
Then I should not see "Field mappings"
Then I should not see "Apply preset Image gallery"
And I should see "The preset has been successfully applied"
Scenario: Using a preset from preset preview page on a non empty database could create new fields
@ -114,9 +124,9 @@ Feature: Users can use predefined presets
And I follow "Presets"
And I click on "Image gallery" "link"
And I click on "Use this preset" "button"
And I click on "Continue" "button"
And I should see "Apply preset Image gallery"
When I click on "Apply preset" "button"
And I should see "The preset has been successfully applied"
And I click on "Continue" "button"
And I follow "Fields"
Then I should see "title"
And I should see "description" in the "description" "table_row"
@ -135,6 +145,10 @@ Feature: Users can use predefined presets
And I click on "Image gallery" "link"
And I click on "Use this preset" "button"
# Let's map a field that is not mapped by default
And I should see "Apply preset Image gallery"
And I should see "Fields to be created: image, title, description"
And I should see "Existing fields to be deleted: Test field name, oldtitle"
When I click on "Map fields" "button"
And I should see "Create a new field" in the "oldtitle" "table_row"
And I set the field "id_title" to "Map to oldtitle"
And I click on "Continue" "button"
@ -155,7 +169,9 @@ Feature: Users can use predefined presets
And I follow "Presets"
And I click on "Image gallery" "link"
And the "Use this preset" "button" should be enabled
Then I click on "Use this preset" "button"
When I click on "Use this preset" "button"
And I should see "Apply preset Image gallery"
And I click on "Map fields" "button"
Then I should see "Field mappings"
And I should see "title"
And I should see "Create a new field" in the "title" "table_row"
@ -174,6 +190,8 @@ Feature: Users can use predefined presets
And I follow "Presets"
And I click on "Image gallery" "link"
When I click on "Use this preset" "button"
And I should see "Apply preset Image gallery"
And I click on "Map fields" "button"
And I should see "Field mappings"
And I set the field "id_title" to "Map to Test field name"
And I click on "Continue" "button"
@ -184,3 +202,46 @@ Feature: Users can use predefined presets
And I click on "Use this preset" "button"
Then I should not see "Field mappings"
And I should see "The preset has been successfully applied"
Scenario: Apply preset dialogue should show helpful information to the user
Given the following "activities" exist:
| activity | name | intro | course | idnumber |
| data | Sea landscapes | introduction... | C1 | data2 |
And the following "mod_data > fields" exist:
| database | type | name |
| data2 | text | title |
And I am on the "Sea landscapes" "data activity" page logged in as teacher1
And I follow "Presets"
And I click on "Image gallery" "link"
When I click on "Use this preset" "button"
And I should see "Apply preset Image gallery"
# Fields to be created only.
Then I should see "Fields to be created: image, description"
And I should not see "If fields to be deleted are of the same type as fields to be created"
And I should not see "If fields to be deleted are of the same type as new fields in the preset"
And I click on "Cancel" "button" in the "Apply preset Image gallery?" "dialogue"
And I follow "Presets"
And the following "mod_data > fields" exist:
| database | type | name |
| data2 | number | number |
And I click on "Image gallery" "link"
And I click on "Use this preset" "button"
And I should see "Apply preset Image gallery"
# Fields to be created and fields to be deleted.
And I should see "Fields to be created: image, description"
And I should see "Existing fields to be deleted: number"
And I should see "If fields to be deleted are of the same type as fields to be created"
And I should not see "If fields to be deleted are of the same type as new fields in the preset"
And I click on "Cancel" "button" in the "Apply preset Image gallery?" "dialogue"
And I follow "Presets"
And the following "mod_data > fields" exist:
| database | type | name |
| data2 | textarea | description |
| data2 | picture | image |
And I click on "Image gallery" "link"
And I click on "Use this preset" "button"
And I should see "Apply preset Image gallery"
# Fields to be deleted only.
And I should see "Existing fields to be deleted: number"
And I should not see "If fields to be deleted are of the same type as fields to be created"
And I should see "If fields to be deleted are of the same type as new fields in the preset"

View File

@ -0,0 +1,235 @@
<?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_data\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
use external_api;
use mod_data\manager;
/**
* External function tests class for get_mapping_information.
*
* @package mod_data
* @category external
* @copyright 2022 Amaia Anabitarte <amaia@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \mod_data\external\get_mapping_information
*/
class get_mapping_information_test extends \advanced_testcase {
/**
* Data provider for test_get_mapping_information().
*
* @return array[]
*/
public function get_mapping_information_provider(): array {
// Image gallery preset is: ['title' => 'text', 'description' => 'textarea', 'image' => 'picture'];
$titlefield = new \stdClass();
$titlefield->name = 'title';
$titlefield->type = 'text';
$descfield = new \stdClass();
$descfield->name = 'description';
$descfield->type = 'textarea';
$imagefield = new \stdClass();
$imagefield->name = 'image';
$imagefield->type = 'picture';
$difffield = new \stdClass();
$difffield->name = 'title';
$difffield->type = 'textarea';
$newfield = new \stdClass();
$newfield->name = 'number';
$newfield->type = 'number';
return [
'Empty database / Empty importer' => [
'currentfields' => [],
'newfields' => [],
'pluginname' => '',
'fieldstocreate' => '',
'fieldstoremove' => '',
],
'Empty database / Importer with fields' => [
'currentfields' => [],
'newfields' => [$imagefield, $titlefield, $descfield],
'pluginname' => 'imagegallery',
'fieldstocreate' => 'image, title, description',
'fieldstoremove' => '',
],
'Database with fields / Empty importer' => [
'currentfields' => [$imagefield, $titlefield, $descfield],
'newfields' => [],
'pluginname' => '',
'fieldstocreate' => '',
'fieldstoremove' => 'image, title, description',
],
'Same fields' => [
'currentfields' => [$imagefield, $titlefield, $descfield],
'newfields' => [$imagefield, $titlefield, $descfield],
'pluginname' => 'imagegallery',
'fieldstocreate' => '',
'fieldstoremove' => '',
],
'Fields to create' => [
'currentfields' => [$titlefield, $descfield],
'newfields' => [$imagefield, $titlefield, $descfield],
'pluginname' => 'imagegallery',
'fieldstocreate' => 'image',
'fieldstoremove' => '',
],
'Fields to remove' => [
'currentfields' => [$imagefield, $titlefield, $descfield, $difffield],
'newfields' => [$imagefield, $titlefield, $descfield],
'pluginname' => 'imagegallery',
'fieldstocreate' => '',
'fieldstoremove' => 'title',
],
'Fields to update' => [
'currentfields' => [$imagefield, $difffield, $descfield],
'newfields' => [$imagefield, $titlefield, $descfield],
'pluginname' => 'imagegallery',
'fieldstocreate' => 'title',
'fieldstoremove' => 'title',
],
'Fields to create, remove and update' => [
'currentfields' => [$titlefield, $descfield, $imagefield, $difffield],
'newfields' => [$titlefield, $descfield, $newfield],
'pluginname' => '',
'fieldstocreate' => 'number',
'fieldstoremove' => 'image, title',
],
];
}
/**
* Test for get_mapping_information method.
*
* @dataProvider get_mapping_information_provider
* @covers ::execute
*
* @param array $currentfields Fields of the current activity.
* @param array $newfields Fields to be imported.
* @param string $pluginname The plugin preset to be imported.
* @param string $fieldstocreate Expected fields on $fieldstocreate.
* @param string $fieldstoremove Expected fields on $fieldstoremove.
*/
public function test_get_mapping_information(
array $currentfields,
array $newfields,
string $pluginname,
string $fieldstocreate,
string $fieldstoremove
) {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
// Create a course and a database activity.
$course = $this->getDataGenerator()->create_course();
$activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
// Add current fields to the activity.
foreach ($currentfields as $field) {
$plugingenerator->create_field($field, $activity);
}
$manager = manager::create_from_instance($activity);
$module = $manager->get_coursemodule();
$presetactivity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
// Add current fields to the activity.
foreach ($newfields as $field) {
$plugingenerator->create_field($field, $presetactivity);
}
$record = (object) [
'name' => 'Testing preset name',
'description' => 'Testing preset description',
];
$saved = $plugingenerator->create_preset($presetactivity, $record);
$result = get_mapping_information::execute($module->id, $USER->id . '/' . $saved->name);
$result = external_api::clean_returnvalue(get_mapping_information::execute_returns(), $result);
$this->assertEquals($result['data']['fieldstocreate'], $fieldstocreate);
$this->assertEquals($result['data']['fieldstoremove'], $fieldstoremove);
// Create presets and importers.
if ($pluginname) {
$result = get_mapping_information::execute($module->id, '/' . $pluginname);;
$result = external_api::clean_returnvalue(get_mapping_information::execute_returns(), $result);
$this->assertEquals($result['data']['fieldstoremove'], $fieldstoremove);
$this->assertEquals($result['data']['fieldstocreate'], $fieldstocreate);
}
}
/**
* Test for get_mapping_information method for wrong presets.
*
* @covers ::execute
*
*/
public function test_get_mapping_information_for_wrong_preset() {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
// Create a course and a database activity.
$course = $this->getDataGenerator()->create_course();
$activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
$manager = manager::create_from_instance($activity);
$module = $manager->get_coursemodule();
// We get warnings with empty preset name.
$result = get_mapping_information::execute($module->id, '');
$result = external_api::clean_returnvalue(get_mapping_information::execute_returns(), $result);
$this->assertFalse(array_key_exists('data', $result));
$this->assertTrue(array_key_exists('warnings', $result));
// We get warnings with non-existing preset name.
$result = get_mapping_information::execute($module->id, $USER->id . '/Non-existing');
$result = external_api::clean_returnvalue(get_mapping_information::execute_returns(), $result);
$this->assertFalse(array_key_exists('data', $result));
$this->assertTrue(array_key_exists('warnings', $result));
$record = (object) [
'name' => 'Testing preset name',
'description' => 'Testing preset description',
];
$saved = $plugingenerator->create_preset($activity, $record);
// We get no warning with the right preset.
$result = get_mapping_information::execute($module->id, $USER->id . '/' . $saved->name);
$result = external_api::clean_returnvalue(get_mapping_information::execute_returns(), $result);
$this->assertTrue(array_key_exists('data', $result));
$this->assertFalse(array_key_exists('warnings', $result));
}
}

View File

@ -17,6 +17,7 @@
namespace mod_data;
use mod_data\local\importer\preset_existing_importer;
use mod_data\local\importer\preset_importer;
/**
* Preset importer tests class for mod_data.
@ -280,4 +281,179 @@ class preset_importer_test extends \advanced_testcase {
$this->assertEquals(count($pluginimporter->fieldstoupdate), $fieldstoupdate);
}
}
/**
* Test for get_mapping_information method.
*
* @dataProvider set_affected_provider
* @covers ::get_mapping_information
*
* @param array $currentfields Fields of the current activity.
* @param array $newfields Fields to be imported.
* @param string $pluginname The plugin preset to be imported.
* @param int $fieldstocreate Expected number of fields on $fieldstocreate.
* @param int $fieldstoremove Expected number of fields on $fieldstoremove.
* @param int $fieldstoupdate Expected number of fields on $fieldstoupdate.
*/
public function test_get_mapping_information(
array $currentfields,
array $newfields,
string $pluginname,
int $fieldstocreate,
int $fieldstoremove,
int $fieldstoupdate
) {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
// Create a course and a database activity.
$course = $this->getDataGenerator()->create_course();
$activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
// Add current fields to the activity.
foreach ($currentfields as $field) {
$plugingenerator->create_field($field, $activity);
}
$manager = manager::create_from_instance($activity);
$presetactivity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
// Add current fields to the activity.
foreach ($newfields as $field) {
$plugingenerator->create_field($field, $presetactivity);
}
$record = (object) [
'name' => 'Testing preset name',
'description' => 'Testing preset description',
];
$saved = $plugingenerator->create_preset($presetactivity, $record);
$savedimporter = new preset_existing_importer($manager, $USER->id . '/Testing preset name');
$information = $savedimporter->get_mapping_information();
$this->assertEquals($savedimporter->needs_mapping(), $information['needsmapping']);
$this->assertEquals(count($savedimporter->fieldstoremove), $fieldstoremove);
$this->assertEquals(count($savedimporter->fieldstocreate), $fieldstocreate);
$this->assertEquals(count($savedimporter->fieldstoupdate), $fieldstoupdate);
// Create presets and importers.
if ($pluginname) {
$plugin = preset::create_from_plugin(null, $pluginname);
$pluginimporter = new preset_existing_importer($manager, '/' . $pluginname);
$information = $pluginimporter->get_mapping_information();
$this->assertEquals($pluginimporter->needs_mapping(), $information['needsmapping']);
$this->assertEquals(count($pluginimporter->fieldstoremove), $fieldstoremove);
$this->assertEquals(count($pluginimporter->fieldstocreate), $fieldstocreate);
$this->assertEquals(count($pluginimporter->fieldstoupdate), $fieldstoupdate);
}
}
/**
* Data provider for get_field_names().
*
* @return array[]
*/
public function get_field_names_provider(): array {
return [
'Empty list' => [
'fields' => [],
'expected' => '',
],
'List with one field' => [
'fields' => ['fieldname' => 'text'],
'expected' => 'fieldname',
],
'List of fields with same type' => [
'fields' => ['textfield' => 'text', 'other' => 'text'],
'expected' => 'textfield, other',
],
'List of fields with different type' => [
'fields' => ['textfield' => 'text', 'number' => 'number'],
'expected' => 'textfield, number',
],
];
}
/**
* Test for get_field_names method.
*
* @dataProvider get_field_names_provider
* @covers ::get_field_names
*
* @param array $fields List of fields to get the names from.
* @param string $expected The list of field names expected.
*/
public function test_get_field_names(array $fields, string $expected) {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
// Create a course and a database activity.
$course = $this->getDataGenerator()->create_course();
$presetactivity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
foreach ($fields as $fieldname => $fieldtype) {
$newfield = new \stdClass();
$newfield->name = $fieldname;
$newfield->type = $fieldtype;
$createdfield = $plugingenerator->create_field($newfield, $presetactivity);
}
$manager = manager::create_from_instance($presetactivity);
$record = (object) [
'name' => 'Testing preset name',
'description' => 'Testing preset description',
];
$saved = $plugingenerator->create_preset($presetactivity, $record);
$savedimporter = new preset_existing_importer($manager, $USER->id . '/Testing preset name');
$this->assertEquals($expected, $savedimporter->get_field_names($manager->get_field_records()));
}
/**
* Test for create_from_plugin_or_directory creation static method.
*
* @covers ::create_from_plugin_or_directory
*
*/
public function test_create_from_plugin_or_directory() {
global $USER;
$this->resetAfterTest();
$this->setAdminUser();
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
// Create a course and a database activity.
$course = $this->getDataGenerator()->create_course();
$activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
$manager = manager::create_from_instance($activity);
$presetactivity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
$record = (object) [
'name' => 'Testing preset name',
'description' => 'Testing preset description',
];
$saved = $plugingenerator->create_preset($presetactivity, $record);
// A plugin preset returns an instance of preset_existing_importer.
$preset = preset_importer::create_from_plugin_or_directory($manager, '/imagegallery');
$this->assertInstanceOf('\mod_data\local\importer\preset_existing_importer', $preset);
// A saved preset returns an instance of preset_existing_importer.
$preset = preset_importer::create_from_plugin_or_directory($manager, $USER->id . '/Testing preset name');
$this->assertInstanceOf('\mod_data\local\importer\preset_existing_importer', $preset);
// An empty preset name throws an exception.
$this->expectException('moodle_exception');
try {
preset_importer::create_from_plugin_or_directory($manager, '');
} finally {
// A non-existing preset name throws an exception.
$this->expectException('moodle_exception');
preset_importer::create_from_plugin_or_directory($manager, $USER->id . '/Non-existing');
}
}
}

View File

@ -24,7 +24,7 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2022100600; // The current module version (Date: YYYYMMDDXX).
$plugin->version = 2022110600; // The current module version (Date: YYYYMMDDXX).
$plugin->requires = 2022041200; // Requires this Moodle version.
$plugin->component = 'mod_data'; // Full name of the plugin (used for diagnostics)
$plugin->cron = 0;