mirror of
https://github.com/moodle/moodle.git
synced 2025-01-19 06:18:28 +01:00
Merge branch 'MDL-75187-master' of https://github.com/sarjona/moodle
This commit is contained in:
commit
d235080a03
10
mod/data/amd/build/deletepreset.min.js
vendored
Normal file
10
mod/data/amd/build/deletepreset.min.js
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
define("mod_data/deletepreset",["exports","core/notification","core/prefetch","core/str","core/ajax","core/url"],(function(_exports,_notification,_prefetch,_str,_ajax,_url){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
|
||||
/**
|
||||
* Javascript module for deleting a database as a preset.
|
||||
*
|
||||
* @module mod_data/deletepreset
|
||||
* @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);const selectors_deletePresetButton='[data-action="deletepreset"]';_exports.init=()=>{(0,_prefetch.prefetchStrings)("mod_data",["deleteconfirm","deletewarning"]),(0,_prefetch.prefetchStrings)("core",["delete"]),registerEventListeners()};const registerEventListeners=()=>{document.addEventListener("click",(event=>{const deleteOption=event.target.closest(selectors_deletePresetButton);deleteOption&&(event.preventDefault(),deletePresetConfirm(deleteOption))}))},deletePresetConfirm=deleteOption=>{const presetName=deleteOption.getAttribute("data-presetname"),dataId=deleteOption.getAttribute("data-dataid");_notification.default.saveCancelPromise((0,_str.get_string)("deleteconfirm","mod_data",presetName),(0,_str.get_string)("deletewarning","mod_data"),(0,_str.get_string)("delete","core")).then((()=>async function(dataId,presetName){var request={methodname:"mod_data_delete_saved_preset",args:{dataid:dataId,presetnames:{presetname:presetName}}};try{await _ajax.default.call([request])[0],window.location.href=_url.default.relativeUrl("mod/data/preset.php",{d:dataId},!1)}catch(error){_notification.default.exception(error)}}(dataId,presetName))).catch((()=>{}))}}));
|
||||
|
||||
//# sourceMappingURL=deletepreset.min.js.map
|
1
mod/data/amd/build/deletepreset.min.js.map
Normal file
1
mod/data/amd/build/deletepreset.min.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"deletepreset.min.js","sources":["../src/deletepreset.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 for deleting a database as a preset.\n *\n * @module mod_data/deletepreset\n * @copyright 2022 Amaia Anabitarte <amaia@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Notification from 'core/notification';\nimport {prefetchStrings} from 'core/prefetch';\nimport {get_string as getString} from 'core/str';\nimport Ajax from 'core/ajax';\nimport Url from 'core/url';\n\nconst selectors = {\n deletePresetButton: '[data-action=\"deletepreset\"]',\n};\n\n/**\n * Initialize module\n */\nexport const init = () => {\n prefetchStrings('mod_data', [\n 'deleteconfirm',\n 'deletewarning',\n ]);\n prefetchStrings('core', [\n 'delete',\n ]);\n\n registerEventListeners();\n};\n\n/**\n * Register events for delete preset option in action menu.\n */\nconst registerEventListeners = () => {\n document.addEventListener('click', (event) => {\n const deleteOption = event.target.closest(selectors.deletePresetButton);\n if (deleteOption) {\n event.preventDefault();\n deletePresetConfirm(deleteOption);\n }\n });\n};\n\n/**\n * Show the confirmation modal to delete the preset.\n *\n * @param {HTMLElement} deleteOption the element to delete.\n */\nconst deletePresetConfirm = (deleteOption) => {\n const presetName = deleteOption.getAttribute('data-presetname');\n const dataId = deleteOption.getAttribute('data-dataid');\n\n Notification.saveCancelPromise(\n getString('deleteconfirm', 'mod_data', presetName),\n getString('deletewarning', 'mod_data'),\n getString('delete', 'core'),\n ).then(() => {\n return deletePreset(dataId, presetName);\n }).catch(() => {\n return;\n });\n};\n\n/**\n * Delete site user preset.\n *\n * @param {int} dataId The id of the current database activity.\n * @param {string} presetName The preset name to delete.\n * @return {promise} Resolved with the result and warnings of deleting a preset.\n */\nasync function deletePreset(dataId, presetName) {\n var request = {\n methodname: 'mod_data_delete_saved_preset',\n args: {\n dataid: dataId,\n presetnames: {presetname: presetName},\n }\n };\n try {\n await Ajax.call([request])[0];\n window.location.href = Url.relativeUrl(\n 'mod/data/preset.php',\n {\n d: dataId,\n },\n false\n );\n } catch (error) {\n Notification.exception(error);\n }\n}\n"],"names":["selectors","registerEventListeners","document","addEventListener","event","deleteOption","target","closest","preventDefault","deletePresetConfirm","presetName","getAttribute","dataId","saveCancelPromise","then","request","methodname","args","dataid","presetnames","presetname","Ajax","call","window","location","href","Url","relativeUrl","d","error","exception","deletePreset","catch"],"mappings":";;;;;;;kNA6BMA,6BACkB,6CAMJ,mCACA,WAAY,CACxB,gBACA,gDAEY,OAAQ,CACpB,WAGJC,gCAMEA,uBAAyB,KAC3BC,SAASC,iBAAiB,SAAUC,cAC1BC,aAAeD,MAAME,OAAOC,QAAQP,8BACtCK,eACAD,MAAMI,iBACNC,oBAAoBJ,mBAU1BI,oBAAuBJ,qBACnBK,WAAaL,aAAaM,aAAa,mBACvCC,OAASP,aAAaM,aAAa,qCAE5BE,mBACT,mBAAU,gBAAiB,WAAYH,aACvC,mBAAU,gBAAiB,aAC3B,mBAAU,SAAU,SACtBI,MAAK,mBAciBF,OAAQF,gBAC5BK,QAAU,CACVC,WAAY,+BACZC,KAAM,CACFC,OAAQN,OACRO,YAAa,CAACC,WAAYV,wBAIxBW,cAAKC,KAAK,CAACP,UAAU,GAC3BQ,OAAOC,SAASC,KAAOC,aAAIC,YACvB,sBACA,CACIC,EAAGhB,SAEP,GAEN,MAAOiB,6BACQC,UAAUD,QA/BhBE,CAAanB,OAAQF,cAC7BsB,OAAM"}
|
109
mod/data/amd/src/deletepreset.js
Normal file
109
mod/data/amd/src/deletepreset.js
Normal file
@ -0,0 +1,109 @@
|
||||
// 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/deletepreset
|
||||
* @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 {prefetchStrings} from 'core/prefetch';
|
||||
import {get_string as getString} from 'core/str';
|
||||
import Ajax from 'core/ajax';
|
||||
import Url from 'core/url';
|
||||
|
||||
const selectors = {
|
||||
deletePresetButton: '[data-action="deletepreset"]',
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize module
|
||||
*/
|
||||
export const init = () => {
|
||||
prefetchStrings('mod_data', [
|
||||
'deleteconfirm',
|
||||
'deletewarning',
|
||||
]);
|
||||
prefetchStrings('core', [
|
||||
'delete',
|
||||
]);
|
||||
|
||||
registerEventListeners();
|
||||
};
|
||||
|
||||
/**
|
||||
* Register events for delete preset option in action menu.
|
||||
*/
|
||||
const registerEventListeners = () => {
|
||||
document.addEventListener('click', (event) => {
|
||||
const deleteOption = event.target.closest(selectors.deletePresetButton);
|
||||
if (deleteOption) {
|
||||
event.preventDefault();
|
||||
deletePresetConfirm(deleteOption);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Show the confirmation modal to delete the preset.
|
||||
*
|
||||
* @param {HTMLElement} deleteOption the element to delete.
|
||||
*/
|
||||
const deletePresetConfirm = (deleteOption) => {
|
||||
const presetName = deleteOption.getAttribute('data-presetname');
|
||||
const dataId = deleteOption.getAttribute('data-dataid');
|
||||
|
||||
Notification.saveCancelPromise(
|
||||
getString('deleteconfirm', 'mod_data', presetName),
|
||||
getString('deletewarning', 'mod_data'),
|
||||
getString('delete', 'core'),
|
||||
).then(() => {
|
||||
return deletePreset(dataId, presetName);
|
||||
}).catch(() => {
|
||||
return;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete site user preset.
|
||||
*
|
||||
* @param {int} dataId 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.
|
||||
*/
|
||||
async function deletePreset(dataId, presetName) {
|
||||
var request = {
|
||||
methodname: 'mod_data_delete_saved_preset',
|
||||
args: {
|
||||
dataid: dataId,
|
||||
presetnames: {presetname: presetName},
|
||||
}
|
||||
};
|
||||
try {
|
||||
await Ajax.call([request])[0];
|
||||
window.location.href = Url.relativeUrl(
|
||||
'mod/data/preset.php',
|
||||
{
|
||||
d: dataId,
|
||||
},
|
||||
false
|
||||
);
|
||||
} catch (error) {
|
||||
Notification.exception(error);
|
||||
}
|
||||
}
|
122
mod/data/classes/external/delete_saved_preset.php
vendored
Normal file
122
mod/data/classes/external/delete_saved_preset.php
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
<?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\manager;
|
||||
use mod_data\preset;
|
||||
|
||||
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 delete_saved_preset extends \external_api {
|
||||
/**
|
||||
* Parameters.
|
||||
*
|
||||
* @return \external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters(): \external_function_parameters {
|
||||
return new \external_function_parameters([
|
||||
'dataid' => new \external_value(PARAM_INT, 'Id of the data activity', VALUE_REQUIRED),
|
||||
'presetnames' => new \external_multiple_structure(
|
||||
new \external_value(PARAM_TEXT, 'The preset name to delete', VALUE_REQUIRED)
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete saved preset from the file system.
|
||||
*
|
||||
* @param int $dataid Id of the data activity to check context and permissions.
|
||||
* @param array $presetnames List of saved preset names to delete.
|
||||
* @return array True if the content has been deleted; false and the warning, otherwise.
|
||||
*/
|
||||
public static function execute(int $dataid, array $presetnames): array {
|
||||
global $DB;
|
||||
|
||||
$result = false;
|
||||
$warnings = [];
|
||||
|
||||
$params = self::validate_parameters(self::execute_parameters(), ['dataid' => $dataid, 'presetnames' => $presetnames]);
|
||||
|
||||
$instance = $DB->get_record('data', ['id' => $params['dataid']], '*', MUST_EXIST);
|
||||
$manager = manager::create_from_instance($instance);
|
||||
|
||||
foreach ($params['presetnames'] as $presetname) {
|
||||
try {
|
||||
$preset = preset::create_from_instance($manager, $presetname);
|
||||
if ($preset->can_manage()) {
|
||||
if ($preset->delete()) {
|
||||
notification::success(get_string('presetdeleted', 'mod_data'));
|
||||
$result = true;
|
||||
} else {
|
||||
// An error ocurred while deleting the preset.
|
||||
$warnings[] = [
|
||||
'item' => $presetname,
|
||||
'warningcode' => 'failedpresetdelete',
|
||||
'message' => get_string('failedpresetdelete', 'mod_data')
|
||||
];
|
||||
notification::error(get_string('failedpresetdelete', 'mod_data'));
|
||||
}
|
||||
} else {
|
||||
// The user has no permission to delete the preset.
|
||||
$warnings[] = [
|
||||
'item' => $presetname,
|
||||
'warningcode' => 'cannotdeletepreset',
|
||||
'message' => get_string('cannotdeletepreset', 'mod_data')
|
||||
];
|
||||
notification::error(get_string('cannotdeletepreset', 'mod_data'));
|
||||
}
|
||||
} catch (\moodle_exception $e) {
|
||||
// The saved preset has not been deleted.
|
||||
$warnings[] = [
|
||||
'item' => $presetname,
|
||||
'warningcode' => 'exception',
|
||||
'message' => $e->getMessage()
|
||||
];
|
||||
notification::error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'result' => $result,
|
||||
'warnings' => $warnings
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return.
|
||||
*
|
||||
* @return \external_single_structure
|
||||
*/
|
||||
public static function execute_returns(): \external_single_structure {
|
||||
return new \external_single_structure([
|
||||
'result' => new \external_value(PARAM_BOOL, 'The processing result'),
|
||||
'warnings' => new \external_warnings()
|
||||
]);
|
||||
}
|
||||
}
|
@ -95,7 +95,7 @@ class save_as_preset extends dynamic_form {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isset($selectedpreset->name) && !data_user_can_delete_preset($context, $selectedpreset)) {
|
||||
if (!$selectedpreset instanceof preset || !$selectedpreset->can_manage()) {
|
||||
$errors['name'] = get_string('cannotoverwritepreset', 'data');
|
||||
}
|
||||
} else if ($formdata['action'] == 'saveaspreset' || $formdata['oldpresetname'] != $formdata['name']) {
|
||||
@ -105,7 +105,7 @@ class save_as_preset extends dynamic_form {
|
||||
$usercandelete = false;
|
||||
foreach ($sitepresets as $preset) {
|
||||
if ($formdata['name'] == $preset->name) {
|
||||
if (data_user_can_delete_preset($context, $preset)) {
|
||||
if ($preset->can_manage()) {
|
||||
$errors['name'] = get_string('errorpresetexists', 'data');
|
||||
$usercandelete = true;
|
||||
} else {
|
||||
@ -176,8 +176,8 @@ class save_as_preset extends dynamic_form {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isset($selectedpreset->name) && data_user_can_delete_preset($context, $selectedpreset)) {
|
||||
data_delete_site_preset($formdata->name);
|
||||
if ($selectedpreset instanceof preset && $selectedpreset->can_manage()) {
|
||||
$selectedpreset->delete();
|
||||
}
|
||||
}
|
||||
$presetname = $formdata->name;
|
||||
|
@ -136,7 +136,7 @@ class presets implements templatable, renderable {
|
||||
$actionmenu->attributes['class'] .= ' presets-actions';
|
||||
|
||||
// Only users with mod/data:manageuserpresets capability have options to edit the preset.
|
||||
if (data_user_can_delete_preset($PAGE->context, $preset)) {
|
||||
if ($preset->can_manage()) {
|
||||
$params = [
|
||||
'd' => $this->id,
|
||||
'action' => 'edit',
|
||||
@ -158,14 +158,19 @@ class presets implements templatable, renderable {
|
||||
// Delete.
|
||||
$params = [
|
||||
'd' => $this->id,
|
||||
'fullname' => "{$userid}/{$preset->shortname}",
|
||||
'action' => 'confirmdelete',
|
||||
'action' => 'delete',
|
||||
];
|
||||
$deleteactionurl = new moodle_url('/mod/data/preset.php', $params);
|
||||
$attributes = [
|
||||
'data-action' => 'deletepreset',
|
||||
'data-dataid' => $this->id,
|
||||
"data-presetname" => $preset->name,
|
||||
];
|
||||
$actionmenu->add(new action_menu_link_secondary(
|
||||
$deleteactionurl,
|
||||
null,
|
||||
get_string('delete'),
|
||||
$attributes,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -535,4 +535,67 @@ class preset {
|
||||
|
||||
return $preset->asXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the user has permission to manage the preset.
|
||||
*
|
||||
* @return bool Returns true if the user can manage this preset, false otherwise.
|
||||
*/
|
||||
public function can_manage(): bool {
|
||||
global $USER;
|
||||
|
||||
if ($this->isplugin) {
|
||||
// Plugin presets can't be removed or edited.
|
||||
return false;
|
||||
}
|
||||
|
||||
$context = $this->manager->get_context();
|
||||
if (has_capability('mod/data:manageuserpresets', $context)) {
|
||||
return true;
|
||||
} else {
|
||||
if ($this->get_userid() == $USER->id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all files related to a saved preset.
|
||||
*
|
||||
* @return bool True if the preset is a saved preset and the file exists in the file system; false otherwise.
|
||||
*/
|
||||
public function delete(): bool {
|
||||
if ($this->isplugin) {
|
||||
// Plugin presets can't be removed.
|
||||
return false;
|
||||
}
|
||||
|
||||
$exists = false;
|
||||
$filepath = $this->get_path();
|
||||
|
||||
$dir = self::get_file($filepath, '.');
|
||||
if (!empty($dir)) {
|
||||
$exists = true;
|
||||
|
||||
$fs = get_file_storage();
|
||||
$files = $fs->get_directory_files(
|
||||
$dir->get_contextid(),
|
||||
$dir->get_component(),
|
||||
$dir->get_filearea(),
|
||||
$dir->get_itemid(),
|
||||
$filepath
|
||||
);
|
||||
if (!empty($files)) {
|
||||
foreach ($files as $file) {
|
||||
$file->delete();
|
||||
}
|
||||
}
|
||||
$dir->delete();
|
||||
// Reseting storedfile property because the file has been removed.
|
||||
$this->storedfile = null;
|
||||
}
|
||||
|
||||
return $exists;
|
||||
}
|
||||
}
|
||||
|
@ -115,4 +115,11 @@ $functions = array(
|
||||
'capabilities' => 'mod/data:writeentry',
|
||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
|
||||
),
|
||||
'mod_data_delete_saved_preset' => array(
|
||||
'classname' => 'mod_data\external\delete_saved_preset',
|
||||
'description' => 'Delete site user preset.',
|
||||
'type' => 'write',
|
||||
'ajax' => true,
|
||||
'capabilities' => 'mod/data:manageuserpresets',
|
||||
),
|
||||
);
|
||||
|
@ -115,11 +115,12 @@ $string['delcheck'] = 'Bulk delete checkbox';
|
||||
$string['delete'] = 'Delete';
|
||||
$string['deleteallentries'] = 'Delete all entries';
|
||||
$string['deletecomment'] = 'Are you sure you want to delete this comment?';
|
||||
$string['deleteconfirm'] = 'Delete preset {$a}?';
|
||||
$string['deleted'] = 'deleted';
|
||||
$string['deleteentry'] = 'Delete entry';
|
||||
$string['deletefield'] = 'Delete field';
|
||||
$string['deletenotenrolled'] = 'Delete entries by users not enrolled';
|
||||
$string['deletewarning'] = 'Are you sure you want to delete this preset?';
|
||||
$string['deletewarning'] = 'Deleting a preset removes it from the list of available presets in all courses.';
|
||||
$string['descending'] = 'Descending';
|
||||
$string['directorynotapreset'] = '{$a->directory} Not a preset: missing files: {$a->missing_files}';
|
||||
$string['disapprove'] = 'Undo approval';
|
||||
@ -163,7 +164,7 @@ $string['exportformat'] = 'Export format';
|
||||
$string['exportoptions'] = 'Export options';
|
||||
$string['exportownentries'] = 'Export your own entries only? ({$a->mine}/{$a->all})';
|
||||
$string['exportpreset'] = 'Export preset';
|
||||
$string['failedpresetdelete'] = 'Error deleting a preset!';
|
||||
$string['failedpresetdelete'] = 'An error was encountered while trying to delete the preset.';
|
||||
$string['fieldadded'] = 'Field added';
|
||||
$string['fieldallowautolink'] = 'Allow autolink';
|
||||
$string['fielddeleted'] = 'Field deleted';
|
||||
@ -321,6 +322,7 @@ $string['pleaseaddsome'] = 'Please create some below or <a href="{$a}">choose a
|
||||
$string['pluginadministration'] = 'Database activity administration';
|
||||
$string['pluginname'] = 'Database';
|
||||
$string['portfolionotfile'] = 'Export to a portfolio rather than a file (csv and leap2a only)';
|
||||
$string['presetdeleted'] = 'Preset deleted.';
|
||||
$string['presetinfo'] = 'Saving as a preset will publish this template. Other users may be able to use it in their databases.';
|
||||
$string['presetnotselected'] = 'No preset has been selected.';
|
||||
$string['presets'] = 'Presets';
|
||||
|
@ -2085,8 +2085,13 @@ function data_get_available_site_presets($context, array $presets=array()) {
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
* @deprecated since Moodle 4.1 MDL-75187 - please, use the preset::delete() function instead.
|
||||
* @todo MDL-75189 This will be deleted in Moodle 4.5.
|
||||
* @see preset::delete()
|
||||
*/
|
||||
function data_delete_site_preset($name) {
|
||||
debugging('data_delete_site_preset() is deprecated. Please use preset::delete() instead.', DEBUG_DEVELOPER);
|
||||
|
||||
$fs = get_file_storage();
|
||||
|
||||
$files = $fs->get_directory_files(DATA_PRESET_CONTEXT, DATA_PRESET_COMPONENT, DATA_PRESET_FILEAREA, 0, '/'.$name.'/');
|
||||
@ -3852,10 +3857,22 @@ function data_get_advanced_search_sql($sort, $data, $recordids, $selectdata, $so
|
||||
* @param stdClass $context Context object.
|
||||
* @param stdClass $preset The preset object that we are checking for deletion.
|
||||
* @return bool Returns true if the user can delete, otherwise false.
|
||||
* @deprecated since Moodle 4.1 MDL-75187 - please, use the preset::can_manage() function instead.
|
||||
* @todo MDL-75189 This will be deleted in Moodle 4.5.
|
||||
* @see preset::can_manage()
|
||||
*/
|
||||
function data_user_can_delete_preset($context, $preset) {
|
||||
global $USER;
|
||||
|
||||
debugging('data_user_can_delete_preset() is deprecated. Please use manager::can_manage() instead.', DEBUG_DEVELOPER);
|
||||
|
||||
if ($context->contextlevel == CONTEXT_MODULE && isset($preset->name)) {
|
||||
$cm = get_coursemodule_from_id('', $context->instanceid, 0, false, MUST_EXIST);
|
||||
$manager = manager::create_from_coursemodule($cm);
|
||||
$todelete = preset::create_from_instance($manager, $preset->name);
|
||||
return $todelete->can_manage();
|
||||
}
|
||||
|
||||
if (has_capability('mod/data:manageuserpresets', $context)) {
|
||||
return true;
|
||||
} else {
|
||||
|
@ -53,7 +53,7 @@ if ($id) {
|
||||
}
|
||||
|
||||
$action = optional_param('action', 'view', PARAM_ALPHA); // The page action.
|
||||
$allowedactions = ['view', 'delete', 'confirmdelete', 'import', 'importzip', 'finishimport',
|
||||
$allowedactions = ['view', 'import', 'importzip', 'finishimport',
|
||||
'export'];
|
||||
if (!in_array($action, $allowedactions)) {
|
||||
throw new moodle_exception('invalidaccess');
|
||||
@ -71,6 +71,7 @@ $PAGE->set_title(get_string('course') . ': ' . $course->fullname);
|
||||
$PAGE->set_heading($course->fullname);
|
||||
$PAGE->force_settings_menu(true);
|
||||
$PAGE->activityheader->disable();
|
||||
$PAGE->requires->js_call_amd('mod_data/deletepreset', 'init');
|
||||
|
||||
// fill in missing properties needed for updating of instance
|
||||
$data->course = $cm->course;
|
||||
@ -124,7 +125,7 @@ if ($formdata = $formimportzip->get_data()) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (in_array($action, ['confirmdelete', 'delete', 'finishimport'])) {
|
||||
if ($action === 'finishimport') {
|
||||
$fullname = optional_param('fullname', '' , PARAM_PATH); // The directory the preset is in.
|
||||
// Find out preset owner userid and shortname.
|
||||
$parts = explode('/', $fullname, 2);
|
||||
@ -132,60 +133,29 @@ if (in_array($action, ['confirmdelete', 'delete', 'finishimport'])) {
|
||||
$shortname = empty($parts[1]) ? '' : $parts[1];
|
||||
echo html_writer::start_div('overflow-hidden');
|
||||
|
||||
if ($action === 'confirmdelete') {
|
||||
$path = data_preset_path($course, $userid, $shortname);
|
||||
$strwarning = get_string('deletewarning', 'data').'<br />'.$shortname;
|
||||
$optionsyes = [
|
||||
'fullname' => $fullname,
|
||||
'action' => 'delete',
|
||||
'd' => $data->id,
|
||||
];
|
||||
$optionsno = ['d' => $data->id];
|
||||
echo $OUTPUT->confirm($strwarning, new moodle_url('/mod/data/preset.php', $optionsyes),
|
||||
new moodle_url('/mod/data/preset.php', $optionsno));
|
||||
echo $OUTPUT->footer();
|
||||
exit(0);
|
||||
} else if ($action === 'delete') {
|
||||
if (!confirm_sesskey()) {
|
||||
throw new moodle_exception('invalidsesskey');
|
||||
}
|
||||
$selectedpreset = new stdClass();
|
||||
foreach ($presets as $preset) {
|
||||
if ($preset->shortname == $shortname) {
|
||||
$selectedpreset = $preset;
|
||||
}
|
||||
}
|
||||
if (!isset($selectedpreset->shortname) || !data_user_can_delete_preset($context, $selectedpreset)) {
|
||||
throw new \moodle_exception('invalidrequest');
|
||||
}
|
||||
|
||||
data_delete_site_preset($shortname);
|
||||
$strdeleted = get_string('deleted', 'data');
|
||||
echo $OUTPUT->notification("$shortname $strdeleted", 'notifysuccess');
|
||||
} else if ($action === 'finishimport') {
|
||||
if (!confirm_sesskey()) {
|
||||
throw new moodle_exception('invalidsesskey');
|
||||
}
|
||||
$overwritesettings = optional_param('overwritesettings', false, PARAM_BOOL);
|
||||
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 data_preset_upload_importer($course, $cm, $data, $presetdir);
|
||||
} else {
|
||||
$importer = new data_preset_existing_importer($course, $cm, $data, $fullname);
|
||||
}
|
||||
$importer->import($overwritesettings);
|
||||
$strimportsuccess = get_string('importsuccess', 'data');
|
||||
$straddentries = get_string('addentries', 'data');
|
||||
$strtodatabase = get_string('todatabase', 'data');
|
||||
if (!$DB->get_records('data_records', array('dataid'=>$data->id))) {
|
||||
echo $OUTPUT->notification("$strimportsuccess <a href='edit.php?d=$data->id'>$straddentries</a> $strtodatabase", 'notifysuccess');
|
||||
} else {
|
||||
echo $OUTPUT->notification("$strimportsuccess", 'notifysuccess');
|
||||
}
|
||||
if (!confirm_sesskey()) {
|
||||
throw new moodle_exception('invalidsesskey');
|
||||
}
|
||||
$overwritesettings = optional_param('overwritesettings', false, PARAM_BOOL);
|
||||
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 data_preset_upload_importer($course, $cm, $data, $presetdir);
|
||||
} else {
|
||||
$importer = new data_preset_existing_importer($course, $cm, $data, $fullname);
|
||||
}
|
||||
$importer->import($overwritesettings);
|
||||
$strimportsuccess = get_string('importsuccess', 'data');
|
||||
$straddentries = get_string('addentries', 'data');
|
||||
$strtodatabase = get_string('todatabase', 'data');
|
||||
if (!$DB->get_records('data_records', ['dataid' => $data->id])) {
|
||||
echo $OUTPUT->notification("$strimportsuccess <a href='edit.php?d=$data->id'>$straddentries</a> $strtodatabase", 'notifysuccess');
|
||||
} else {
|
||||
echo $OUTPUT->notification("$strimportsuccess", 'notifysuccess');
|
||||
}
|
||||
|
||||
echo $OUTPUT->continue_button(new moodle_url('/mod/data/preset.php', ['d' => $data->id]));
|
||||
echo html_writer::end_div();
|
||||
echo $OUTPUT->footer();
|
||||
|
@ -169,7 +169,6 @@ Feature: Users can view and manage data presets
|
||||
And I click on "Save" "button" in the "Edit preset" "dialogue"
|
||||
Then I should not see "Preset saved."
|
||||
And I should see "Saved preset by teacher1"
|
||||
And I should see "This preset has also a description" in the "Saved preset by teacher1" "table_row"
|
||||
|
||||
@javascript
|
||||
Scenario: Teachers can edit presets and overwrite them if they are the authors
|
||||
@ -237,3 +236,27 @@ Feature: Users can view and manage data presets
|
||||
And I should see "This preset has also a description" in the "Saved preset 1" "table_row"
|
||||
And I should not see "Saved preset by teacher1"
|
||||
And I should not see "The preset1 has description"
|
||||
|
||||
@javascript
|
||||
Scenario: Teachers can delete their own presets
|
||||
Given the following "mod_data > fields" exist:
|
||||
| database | type | name | description |
|
||||
| data1 | text | Test field name | Test field description |
|
||||
And the following "mod_data > presets" exist:
|
||||
| database | name | description | user |
|
||||
| data1 | Saved preset by teacher1 | My funny description goes here. | teacher1 |
|
||||
And I am on the "Mountain landscapes" "data activity" page logged in as teacher1
|
||||
When I follow "Presets"
|
||||
And I should see "Image gallery"
|
||||
And I should see "Saved preset 1"
|
||||
And I should see "Saved preset by teacher1"
|
||||
# Plugin presets can't be removed.
|
||||
And I should not see "Actions" in the "Image gallery" "table_row"
|
||||
# The teacher should not be able to delete presets saved by others.
|
||||
And I should not see "Actions" in the "Saved preset 1" "table_row"
|
||||
# The teacher should be able to delete their own preset.
|
||||
And I open the action menu in "Saved preset by teacher" "table_row"
|
||||
And I follow "Delete"
|
||||
And I click on "Delete" "button" in the "Delete preset Saved preset by teacher1?" "dialogue"
|
||||
And I should see "Preset deleted"
|
||||
And I should not see "Saved preset by teacher1"
|
||||
|
135
mod/data/tests/external/delete_saved_preset_test.php
vendored
Normal file
135
mod/data/tests/external/delete_saved_preset_test.php
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
<?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 externallib_advanced_testcase;
|
||||
use external_api;
|
||||
use mod_data\manager;
|
||||
|
||||
/**
|
||||
* External function test for delete_saved_preset.
|
||||
*
|
||||
* @package mod_data
|
||||
* @category external
|
||||
* @since Moodle 4.1
|
||||
* @copyright 2022 Amaia Anabitarte <amaia@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \mod_data\external\delete_saved_preset
|
||||
*/
|
||||
class delete_saved_preset_test extends externallib_advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test the behaviour of delete_saved_preset().
|
||||
*
|
||||
* @covers ::execute
|
||||
*/
|
||||
public function test_delete_saved_preset() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create course, database activity and users.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$data = $this->getDataGenerator()->create_module('data', ['course' => $course->id]);
|
||||
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
|
||||
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
|
||||
$manager = manager::create_from_instance($data);
|
||||
$initialpresets = $manager->get_available_presets();
|
||||
|
||||
$preset1name = 'Admin preset';
|
||||
$preset2name = 'Teacher preset';
|
||||
|
||||
// Trying to delete a preset when there is no saved preset created.
|
||||
$result = delete_saved_preset::execute($data->id, [$preset1name, $preset2name]);
|
||||
$result = external_api::clean_returnvalue(delete_saved_preset::execute_returns(), $result);
|
||||
$this->assertFalse($result['result']);
|
||||
$this->assertCount(2, $result['warnings']);
|
||||
// Check no preset has been deleted.
|
||||
$currentpresets = $manager->get_available_presets();
|
||||
$this->assertEquals(count($initialpresets), count($currentpresets));
|
||||
|
||||
// Create a saved preset.
|
||||
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
|
||||
$record = (object)[
|
||||
'name' => $preset1name,
|
||||
'description' => 'Testing preset description',
|
||||
];
|
||||
$adminpreset = $plugingenerator->create_preset($data, $record);
|
||||
// Update initial preset list.
|
||||
$initialpresets = $manager->get_available_presets();
|
||||
|
||||
// There is a warning for non-existing preset.
|
||||
$result = delete_saved_preset::execute($data->id, ['Another preset']);
|
||||
$result = external_api::clean_returnvalue(delete_saved_preset::execute_returns(), $result);
|
||||
$this->assertFalse($result['result']);
|
||||
$this->assertCount(1, $result['warnings']);
|
||||
// Check no preset has been deleted.
|
||||
$currentpresets = $manager->get_available_presets();
|
||||
$this->assertEquals(count($initialpresets), count($currentpresets));
|
||||
|
||||
// Create a saved preset by teacher.
|
||||
$this->setUser($teacher);
|
||||
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
|
||||
$record = (object)[
|
||||
'name' => $preset2name,
|
||||
'description' => 'Testing preset description',
|
||||
];
|
||||
$teacherpreset = $plugingenerator->create_preset($data, $record);
|
||||
// Update initial preset list.
|
||||
$this->setAdminUser();
|
||||
$initialpresets = $manager->get_available_presets();
|
||||
|
||||
// Student can't delete presets.
|
||||
$this->setUser($student);
|
||||
$result = delete_saved_preset::execute($data->id, [$preset1name, $preset2name]);
|
||||
$result = external_api::clean_returnvalue(delete_saved_preset::execute_returns(), $result);
|
||||
$this->assertFalse($result['result']);
|
||||
$this->assertCount(2, $result['warnings']);
|
||||
// Check no preset has been deleted.
|
||||
$this->setAdminUser();
|
||||
$currentpresets = $manager->get_available_presets();
|
||||
$this->assertEquals(count($initialpresets), count($currentpresets));
|
||||
|
||||
// Teacher can delete their preset.
|
||||
$this->setUser($teacher);
|
||||
$result = delete_saved_preset::execute($data->id, [$preset2name]);
|
||||
$result = external_api::clean_returnvalue(delete_saved_preset::execute_returns(), $result);
|
||||
$this->assertTrue($result['result']);
|
||||
$this->assertCount(0, $result['warnings']);
|
||||
// Check the preset has been deleted.
|
||||
$this->setAdminUser();
|
||||
$currentpresets = $manager->get_available_presets();
|
||||
$this->assertEquals(count($initialpresets) - 1, count($currentpresets));
|
||||
foreach ($currentpresets as $currentpreset) {
|
||||
$this->assertNotEquals($currentpreset->name, $preset2name);
|
||||
}
|
||||
|
||||
// Teacher can't delete other users' preset.
|
||||
$this->setUser($teacher);
|
||||
$result = delete_saved_preset::execute($data->id, [$preset1name]);
|
||||
$result = external_api::clean_returnvalue(delete_saved_preset::execute_returns(), $result);
|
||||
$this->assertFalse($result['result']);
|
||||
$this->assertCount(1, $result['warnings']);
|
||||
// Check no preset has been deleted.
|
||||
$this->setAdminUser();
|
||||
$currentpresets = $manager->get_available_presets();
|
||||
$this->assertEquals(count($initialpresets) - 1, count($currentpresets));
|
||||
}
|
||||
}
|
@ -610,4 +610,120 @@ class preset_test extends \advanced_testcase {
|
||||
$file = preset::get_file($preset->get_path(), 'unexistingpreset.xml');
|
||||
$this->assertNull($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for can_manage().
|
||||
*
|
||||
* @covers ::can_manage
|
||||
*/
|
||||
public function test_can_manage() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create course, database activity and users.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$data = $this->getDataGenerator()->create_module('data', ['course' => $course->id]);
|
||||
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
|
||||
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
|
||||
$manager = manager::create_from_instance($data);
|
||||
|
||||
$preset1name = 'Admin preset';
|
||||
$preset2name = 'Teacher preset';
|
||||
|
||||
// Create a saved preset by admin.
|
||||
$this->setAdminUser();
|
||||
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
|
||||
$record = (object) [
|
||||
'name' => $preset1name,
|
||||
'description' => 'Testing preset description',
|
||||
];
|
||||
$adminpreset = $plugingenerator->create_preset($data, $record);
|
||||
|
||||
// Create a saved preset by teacher.
|
||||
$this->setUser($teacher);
|
||||
$record = (object) [
|
||||
'name' => $preset2name,
|
||||
'description' => 'Testing preset description',
|
||||
];
|
||||
$teacherpreset = $plugingenerator->create_preset($data, $record);
|
||||
|
||||
// Plugins can't be deleted.
|
||||
$pluginpresets = manager::get_available_plugin_presets();
|
||||
$pluginpreset = reset($pluginpresets);
|
||||
$this->assertFalse($pluginpreset->can_manage());
|
||||
|
||||
// Admin can delete all saved presets.
|
||||
$this->setAdminUser();
|
||||
$this->assertTrue($adminpreset->can_manage());
|
||||
$this->assertTrue($teacherpreset->can_manage());
|
||||
|
||||
// Teacher can delete their own preset only.
|
||||
$this->setUser($teacher);
|
||||
$this->assertFalse($adminpreset->can_manage());
|
||||
$this->assertTrue($teacherpreset->can_manage());
|
||||
|
||||
// Student can't delete any of the presets.
|
||||
$this->setUser($student);
|
||||
$this->assertFalse($adminpreset->can_manage());
|
||||
$this->assertFalse($teacherpreset->can_manage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for delete().
|
||||
*
|
||||
* @covers ::delete
|
||||
*/
|
||||
public function test_delete() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create course, database activity and users.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$data = $this->getDataGenerator()->create_module('data', ['course' => $course->id]);
|
||||
$manager = manager::create_from_instance($data);
|
||||
$presetname = 'Admin preset';
|
||||
|
||||
// Create a saved preset by admin.
|
||||
$this->setAdminUser();
|
||||
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
|
||||
$record = (object) [
|
||||
'name' => $presetname,
|
||||
'description' => 'Testing preset description',
|
||||
];
|
||||
$adminpreset = $plugingenerator->create_preset($data, $record);
|
||||
$initialpresets = $manager->get_available_presets();
|
||||
|
||||
// Plugins can't be deleted.
|
||||
$pluginpresets = manager::get_available_plugin_presets();
|
||||
$pluginpreset = reset($pluginpresets);
|
||||
$result = $pluginpreset->delete();
|
||||
$currentpluginpresets = manager::get_available_plugin_presets();
|
||||
$this->assertEquals(count($pluginpresets), count($currentpluginpresets));
|
||||
|
||||
$result = $adminpreset->delete();
|
||||
$this->assertTrue($result);
|
||||
|
||||
// After deleting the preset, there is no file linked.
|
||||
$adminpreset = preset::create_from_instance($manager, $presetname);
|
||||
$this->assertEmpty($adminpreset->storedfile);
|
||||
|
||||
// Check the preset has been deleted.
|
||||
$currentpresets = $manager->get_available_presets();
|
||||
$this->assertEquals(count($initialpresets) - 1, count($currentpresets));
|
||||
|
||||
// The behavior of trying to delete a preset twice.
|
||||
$result = $adminpreset->delete();
|
||||
$this->assertFalse($result);
|
||||
|
||||
// Check the preset has not been deleted.
|
||||
$currentpresets = $manager->get_available_presets();
|
||||
$this->assertEquals(count($initialpresets) - 1, count($currentpresets));
|
||||
|
||||
$emptypreset = preset::create_from_instance($manager, $presetname);
|
||||
// The behavior of deleting an empty preset.
|
||||
$result = $emptypreset->delete();
|
||||
$this->assertFalse($result);
|
||||
|
||||
// Check the preset has not been deleted.
|
||||
$currentpresets = $manager->get_available_presets();
|
||||
$this->assertEquals(count($initialpresets) - 1, count($currentpresets));
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2022081600; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2022082601; // 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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user