mirror of
https://github.com/moodle/moodle.git
synced 2025-08-04 00:16:46 +02:00
Merge branch 'MDL-61407-master' of git://github.com/andrewnicols/moodle
This commit is contained in:
commit
209f6e1eda
123 changed files with 5000 additions and 33 deletions
|
@ -386,6 +386,29 @@ $string['penaltyforeachincorrecttry_help'] = 'When questions are run using the \
|
||||||
|
|
||||||
The penalty is a proportion of the total question grade, so if the question is worth three marks, and the penalty is 0.3333333, then the student will score 3 if they get the question right first time, 2 if they get it right second try, and 1 of they get it right on the third try.';
|
The penalty is a proportion of the total question grade, so if the question is worth three marks, and the penalty is 0.3333333, then the student will score 3 if they get the question right first time, 2 if they get it right second try, and 1 of they get it right on the third try.';
|
||||||
$string['previewquestion'] = 'Preview question: {$a}';
|
$string['previewquestion'] = 'Preview question: {$a}';
|
||||||
|
$string['privacy:metadata:database:question'] = 'The details about an specific question.';
|
||||||
|
$string['privacy:metadata:database:question:createdby'] = 'The person who created the question.';
|
||||||
|
$string['privacy:metadata:database:question:generalfeedback'] = 'The general feedback for this question.';
|
||||||
|
$string['privacy:metadata:database:question:modifiedby'] = 'The person who last updated the question.';
|
||||||
|
$string['privacy:metadata:database:question:name'] = 'The name of the question.';
|
||||||
|
$string['privacy:metadata:database:question:questiontext'] = 'The question text.';
|
||||||
|
$string['privacy:metadata:database:question:timecreated'] = 'The date and time when this question was created.';
|
||||||
|
$string['privacy:metadata:database:question:timemodified'] = 'The date and time when this question was updated.';
|
||||||
|
$string['privacy:metadata:database:question_attempt_step_data'] = 'Question attempt steps may have additional data specific to that step. The data is stored in the step_data table.';
|
||||||
|
$string['privacy:metadata:database:question_attempt_step_data:name'] = 'The name of the data item.';
|
||||||
|
$string['privacy:metadata:database:question_attempt_step_data:value'] = 'The value of the data item.';
|
||||||
|
$string['privacy:metadata:database:question_attempt_steps'] = 'Each question attempt has a number of steps to indicate the different phases from beginning to completion to marking. This table stores the information for each of these steps.';
|
||||||
|
$string['privacy:metadata:database:question_attempt_steps:fraction'] = 'The grade that was awarded to this question attempt scaled to a value out of 1.';
|
||||||
|
$string['privacy:metadata:database:question_attempt_steps:state'] = 'The state of this question attempt step at the end of the step transition.';
|
||||||
|
$string['privacy:metadata:database:question_attempt_steps:timecreated'] = 'The date and time that this step transition begun.';
|
||||||
|
$string['privacy:metadata:database:question_attempt_steps:userid'] = 'The user who performed the step transition.';
|
||||||
|
$string['privacy:metadata:database:question_attempts'] = 'The information about an attempt at a specific question.';
|
||||||
|
$string['privacy:metadata:database:question_attempts:flagged'] = 'An indication that the user has flagged this question within the attempt.';
|
||||||
|
$string['privacy:metadata:database:question_attempts:responsesummary'] = 'A summary of the question response.';
|
||||||
|
$string['privacy:metadata:database:question_attempts:timemodified'] = 'The time that the question attempt was updated.';
|
||||||
|
$string['privacy:metadata:link:qbehaviour'] = 'The Question subsystem makes use of the Question Behaviour plugintype.';
|
||||||
|
$string['privacy:metadata:link:qformat'] = 'The Question subsystem makes use of the Question Format plugintype for the purpose of importing and exporting questions in different formats.';
|
||||||
|
$string['privacy:metadata:link:qtype'] = 'The Question subsystem interacts with the Question Type plugintype which contains the different types of questions.';
|
||||||
$string['questionbehaviouradminsetting'] = 'Question behaviour settings';
|
$string['questionbehaviouradminsetting'] = 'Question behaviour settings';
|
||||||
$string['questionbehavioursdisabled'] = 'Question behaviours to disable';
|
$string['questionbehavioursdisabled'] = 'Question behaviours to disable';
|
||||||
$string['questionbehavioursdisabledexplained'] = 'Enter a comma separated list of behaviours you do not want to appear in dropdown menu';
|
$string['questionbehavioursdisabledexplained'] = 'Enter a comma separated list of behaviours you do not want to appear in dropdown menu';
|
||||||
|
@ -422,6 +445,7 @@ $string['specificfeedback_help'] = 'Feedback that depends on what response the s
|
||||||
$string['started'] = 'Started';
|
$string['started'] = 'Started';
|
||||||
$string['state'] = 'State';
|
$string['state'] = 'State';
|
||||||
$string['step'] = 'Step';
|
$string['step'] = 'Step';
|
||||||
|
$string['steps'] = 'Steps';
|
||||||
$string['submissionoutofsequence'] = 'Access out of sequence. Please do not click the back button when working on quiz questions.';
|
$string['submissionoutofsequence'] = 'Access out of sequence. Please do not click the back button when working on quiz questions.';
|
||||||
$string['submissionoutofsequencefriendlymessage'] = "You have entered data outside the normal sequence. This can occur if you use your browser's Back or Forward buttons; please don't use these during the test. It can also happen if you click on something while a page is loading. Click <strong>Continue</strong> to resume.";
|
$string['submissionoutofsequencefriendlymessage'] = "You have entered data outside the normal sequence. This can occur if you use your browser's Back or Forward buttons; please don't use these during the test. It can also happen if you click on something while a page is loading. Click <strong>Continue</strong> to resume.";
|
||||||
$string['submit'] = 'Submit';
|
$string['submit'] = 'Submit';
|
||||||
|
@ -450,4 +474,3 @@ $string['whichtries'] = 'Which tries';
|
||||||
$string['withselected'] = 'With selected';
|
$string['withselected'] = 'With selected';
|
||||||
$string['xoutofmax'] = '{$a->mark} out of {$a->max}';
|
$string['xoutofmax'] = '{$a->mark} out of {$a->max}';
|
||||||
$string['yougotnright'] = 'You have correctly selected {$a->num}.';
|
$string['yougotnright'] = 'You have correctly selected {$a->num}.';
|
||||||
|
|
||||||
|
|
|
@ -2073,7 +2073,7 @@ function question_pluginfile($course, $context, $component, $filearea, $args, $f
|
||||||
}
|
}
|
||||||
|
|
||||||
// export data to moodle file pool
|
// export data to moodle file pool
|
||||||
if (!$content = $qformat->exportprocess(true)) {
|
if (!$content = $qformat->exportprocess()) {
|
||||||
send_file_not_found();
|
send_file_not_found();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for quizaccess_delaybetweenattempts.
|
||||||
|
*
|
||||||
|
* @package quizaccess_delaybetweenattempts
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace quizaccess_delaybetweenattempts\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for quizaccess_delaybetweenattempts implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,5 +28,6 @@ defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
|
||||||
$string['pluginname'] = 'Delay between attempts quiz access rule';
|
$string['pluginname'] = 'Delay between attempts quiz access rule';
|
||||||
|
$string['privacy:metadata'] = 'The Delay between attempts quiz access rule plugin does not store any personal data.';
|
||||||
$string['youcannotwait'] = 'This quiz closes before you will be allowed to start another attempt.';
|
$string['youcannotwait'] = 'This quiz closes before you will be allowed to start another attempt.';
|
||||||
$string['youmustwait'] = 'You must wait before you may re-attempt this quiz. You will be allowed to start another attempt after {$a}.';
|
$string['youmustwait'] = 'You must wait before you may re-attempt this quiz. You will be allowed to start another attempt after {$a}.';
|
||||||
|
|
46
mod/quiz/accessrule/ipaddress/classes/privacy/provider.php
Normal file
46
mod/quiz/accessrule/ipaddress/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for quizaccess_ipaddress.
|
||||||
|
*
|
||||||
|
* @package quizaccess_ipaddress
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace quizaccess_ipaddress\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for quizaccess_ipaddress implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,4 +28,5 @@ defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
|
||||||
$string['pluginname'] = 'IP address quiz access rule';
|
$string['pluginname'] = 'IP address quiz access rule';
|
||||||
|
$string['privacy:metadata'] = 'The IP address quiz access rule plugin does not store any personal data.';
|
||||||
$string['subnetwrong'] = 'This quiz is only accessible from certain locations, and this computer is not on the allowed list.';
|
$string['subnetwrong'] = 'This quiz is only accessible from certain locations, and this computer is not on the allowed list.';
|
||||||
|
|
46
mod/quiz/accessrule/numattempts/classes/privacy/provider.php
Normal file
46
mod/quiz/accessrule/numattempts/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for quizaccess_numattempts.
|
||||||
|
*
|
||||||
|
* @package quizaccess_numattempts
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace quizaccess_numattempts\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for quizaccess_numattempts implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,3 +29,4 @@ defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
$string['attemptsallowedn'] = 'Attempts allowed: {$a}';
|
$string['attemptsallowedn'] = 'Attempts allowed: {$a}';
|
||||||
$string['pluginname'] = 'Number of attempts quiz access rule';
|
$string['pluginname'] = 'Number of attempts quiz access rule';
|
||||||
|
$string['privacy:metadata'] = 'The Number of attempts quiz access rule plugin does not store any personal data.';
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for quizaccess_offlineattempts.
|
||||||
|
*
|
||||||
|
* @package quizaccess_offlineattempts
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace quizaccess_offlineattempts\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for quizaccess_offlineattempts implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,4 +34,4 @@ $string['offlineattemptserror'] = 'It is not possible for a quiz to be attempted
|
||||||
$string['offlinedatamessage'] = 'You have worked on this attempt using a mobile device. Data was last saved to this site {$a} ago.';
|
$string['offlinedatamessage'] = 'You have worked on this attempt using a mobile device. Data was last saved to this site {$a} ago.';
|
||||||
$string['pleaseconfirm'] = 'Please check and confirm that you do not have any unsaved work.';
|
$string['pleaseconfirm'] = 'Please check and confirm that you do not have any unsaved work.';
|
||||||
$string['pluginname'] = 'Offline attempts access rule';
|
$string['pluginname'] = 'Offline attempts access rule';
|
||||||
|
$string['privacy:metadata'] = 'The Offline attempts quiz access rule plugin does not store any personal data.';
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for quizaccess_openclosedate.
|
||||||
|
*
|
||||||
|
* @package quizaccess_openclosedate
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace quizaccess_openclosedate\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for quizaccess_openclosedate implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,4 +29,5 @@ defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
$string['notavailable'] = 'This quiz is not currently available';
|
$string['notavailable'] = 'This quiz is not currently available';
|
||||||
$string['pluginname'] = 'Open and close date access rule';
|
$string['pluginname'] = 'Open and close date access rule';
|
||||||
|
$string['privacy:metadata'] = 'The Open and close date quiz access rule plugin does not store any personal data.';
|
||||||
$string['quiznotavailable'] = 'The quiz will not be available until {$a}';
|
$string['quiznotavailable'] = 'The quiz will not be available until {$a}';
|
||||||
|
|
46
mod/quiz/accessrule/password/classes/privacy/provider.php
Normal file
46
mod/quiz/accessrule/password/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for quizaccess_password.
|
||||||
|
*
|
||||||
|
* @package quizaccess_password
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace quizaccess_password\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for quizaccess_password implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,5 +28,6 @@ defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
$string['passworderror'] = 'The password entered was incorrect';
|
$string['passworderror'] = 'The password entered was incorrect';
|
||||||
$string['pluginname'] = 'Password quiz access rule';
|
$string['pluginname'] = 'Password quiz access rule';
|
||||||
|
$string['privacy:metadata'] = 'The Password quiz access rule plugin does not store any personal data.';
|
||||||
$string['quizpassword'] = 'Quiz password';
|
$string['quizpassword'] = 'Quiz password';
|
||||||
$string['requirepasswordmessage'] = 'To attempt this quiz you need to know the quiz password';
|
$string['requirepasswordmessage'] = 'To attempt this quiz you need to know the quiz password';
|
||||||
|
|
46
mod/quiz/accessrule/safebrowser/classes/privacy/provider.php
Normal file
46
mod/quiz/accessrule/safebrowser/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for quizaccess_safebrowser.
|
||||||
|
*
|
||||||
|
* @package quizaccess_safebrowser
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace quizaccess_safebrowser\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for quizaccess_safebrowser implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
|
||||||
$string['pluginname'] = 'Safe Exam Browser quiz access rule';
|
$string['pluginname'] = 'Safe Exam Browser quiz access rule';
|
||||||
|
$string['privacy:metadata'] = 'The Safe Exam Browser quiz access rule plugin does not store any personal data.';
|
||||||
$string['requiresafeexambrowser'] = 'Require the use of Safe Exam Browser';
|
$string['requiresafeexambrowser'] = 'Require the use of Safe Exam Browser';
|
||||||
$string['safebrowsererror'] = 'This quiz has been set up so that it may only be attempted using the Safe Exam Browser. You cannot attempt it from this web browser.';
|
$string['safebrowsererror'] = 'This quiz has been set up so that it may only be attempted using the Safe Exam Browser. You cannot attempt it from this web browser.';
|
||||||
$string['safebrowsernotice'] = 'This quiz has been configured so that students may only attempt it using the Safe Exam Browser.';
|
$string['safebrowsernotice'] = 'This quiz has been configured so that students may only attempt it using the Safe Exam Browser.';
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for quizaccess_securewindow.
|
||||||
|
*
|
||||||
|
* @package quizaccess_securewindow
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace quizaccess_securewindow\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for quizaccess_securewindow implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,3 +29,4 @@ defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
$string['pluginname'] = 'JavaScript security quiz access rule';
|
$string['pluginname'] = 'JavaScript security quiz access rule';
|
||||||
$string['popupwithjavascriptsupport'] = 'Full screen pop-up with some JavaScript security';
|
$string['popupwithjavascriptsupport'] = 'Full screen pop-up with some JavaScript security';
|
||||||
|
$string['privacy:metadata'] = 'The JavaScript security quiz access rule plugin does not store any personal data.';
|
||||||
|
|
46
mod/quiz/accessrule/timelimit/classes/privacy/provider.php
Normal file
46
mod/quiz/accessrule/timelimit/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for quizaccess_timelimit.
|
||||||
|
*
|
||||||
|
* @package quizaccess_timelimit
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace quizaccess_timelimit\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for quizaccess_timelimit implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,4 +30,5 @@ defined('MOODLE_INTERNAL') || die();
|
||||||
$string['confirmstartheader'] = 'Timed quiz';
|
$string['confirmstartheader'] = 'Timed quiz';
|
||||||
$string['confirmstart'] = 'The quiz has a time limit of {$a}. Time will count down from the moment you start your attempt and you must submit before it expires. Are you sure that you wish to start now?';
|
$string['confirmstart'] = 'The quiz has a time limit of {$a}. Time will count down from the moment you start your attempt and you must submit before it expires. Are you sure that you wish to start now?';
|
||||||
$string['pluginname'] = 'Time limit quiz access rule';
|
$string['pluginname'] = 'Time limit quiz access rule';
|
||||||
|
$string['privacy:metadata'] = 'The Time limit quiz access rule plugin does not store any personal data.';
|
||||||
$string['quiztimelimit'] = 'Time limit: {$a}';
|
$string['quiztimelimit'] = 'Time limit: {$a}';
|
||||||
|
|
65
mod/quiz/classes/privacy/helper.php
Normal file
65
mod/quiz/classes/privacy/helper.php
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem helper for mod_quiz.
|
||||||
|
*
|
||||||
|
* @package mod_quiz
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace mod_quiz\privacy;
|
||||||
|
|
||||||
|
use \core_privacy\local\request\writer;
|
||||||
|
use \core_privacy\local\request\transform;
|
||||||
|
use \core_privacy\local\request\contextlist;
|
||||||
|
use \core_privacy\local\request\approved_contextlist;
|
||||||
|
use \core_privacy\local\request\deletion_criteria;
|
||||||
|
use \core_privacy\local\metadata\collection;
|
||||||
|
use \core_privacy\manager;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
require_once($CFG->dirroot . '/mod/quiz/lib.php');
|
||||||
|
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for mod_quiz.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class helper {
|
||||||
|
/**
|
||||||
|
* Determine the subcontext for the specified quiz attempt.
|
||||||
|
*
|
||||||
|
* @param \stdClass $attempt The attempt data retrieved from the database.
|
||||||
|
* @param \stdClass $user The user record.
|
||||||
|
* @return \array The calculated subcontext.
|
||||||
|
*/
|
||||||
|
public static function get_quiz_attempt_subcontext(\stdClass $attempt, \stdClass $user) {
|
||||||
|
$subcontext = [
|
||||||
|
get_string('attempts', 'mod_quiz'),
|
||||||
|
];
|
||||||
|
if ($attempt->userid != $user->id) {
|
||||||
|
$subcontext[] = fullname($user);
|
||||||
|
}
|
||||||
|
$subcontext[] = $attempt->attempt;
|
||||||
|
|
||||||
|
return $subcontext;
|
||||||
|
}
|
||||||
|
}
|
66
mod/quiz/classes/privacy/legacy_quizaccess_polyfill.php
Normal file
66
mod/quiz/classes/privacy/legacy_quizaccess_polyfill.php
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file contains the polyfil to allow a plugin to operate with Moodle 3.3 up.
|
||||||
|
*
|
||||||
|
* @package mod_quiz
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
namespace mod_quiz\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The trait used to provide a backwards compatibility for third-party plugins.
|
||||||
|
*
|
||||||
|
* @package mod_quiz
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
trait legacy_quizaccess_polyfill {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export all user data for the specified user, for the specified quiz.
|
||||||
|
*
|
||||||
|
* @param \quiz $quiz The quiz being exported
|
||||||
|
* @param \stdClass $user The user to export data for
|
||||||
|
* @return \stdClass The data to be exported for this access rule.
|
||||||
|
*/
|
||||||
|
public static function export_quizaccess_user_data(\quiz $quiz, \stdClass $user) : \stdClass {
|
||||||
|
return static::_export_quizaccess_user_data($quiz, $user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all data for all users in the specified quiz.
|
||||||
|
*
|
||||||
|
* @param \quiz $quiz The quiz being deleted
|
||||||
|
*/
|
||||||
|
public static function delete_quizaccess_data_for_all_users_in_context(\quiz $quiz) {
|
||||||
|
static::_delete_quizaccess_data_for_all_users_in_context($quiz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all user data for the specified user, in the specified quiz.
|
||||||
|
*
|
||||||
|
* @param \quiz $quiz The quiz being deleted
|
||||||
|
* @param \stdClass $user The user to export data for
|
||||||
|
*/
|
||||||
|
public static function delete_quizaccess_data_for_user(\quiz $quiz, \stdClass $user) {
|
||||||
|
static::_delete_quizaccess_data_for_user($quiz, $user);
|
||||||
|
}
|
||||||
|
}
|
442
mod/quiz/classes/privacy/provider.php
Normal file
442
mod/quiz/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,442 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for mod_quiz.
|
||||||
|
*
|
||||||
|
* @package mod_quiz
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace mod_quiz\privacy;
|
||||||
|
|
||||||
|
use \core_privacy\local\request\writer;
|
||||||
|
use \core_privacy\local\request\transform;
|
||||||
|
use \core_privacy\local\request\contextlist;
|
||||||
|
use \core_privacy\local\request\approved_contextlist;
|
||||||
|
use \core_privacy\local\request\deletion_criteria;
|
||||||
|
use \core_privacy\local\metadata\collection;
|
||||||
|
use \core_privacy\manager;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
require_once($CFG->dirroot . '/mod/quiz/lib.php');
|
||||||
|
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for mod_quiz.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements
|
||||||
|
// This plugin has data.
|
||||||
|
\core_privacy\local\metadata\provider,
|
||||||
|
|
||||||
|
// This plugin currently implements the original plugin_provider interface.
|
||||||
|
\core_privacy\local\request\plugin\provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of contexts that contain user information for the specified user.
|
||||||
|
*
|
||||||
|
* @param collection $items The collection to add metadata to.
|
||||||
|
* @return collection The array of metadata
|
||||||
|
*/
|
||||||
|
public static function get_metadata(collection $items) : collection {
|
||||||
|
// The table 'quiz' stores a record for each quiz.
|
||||||
|
// It does not contain user personal data, but data is returned from it for contextual requirements.
|
||||||
|
|
||||||
|
// The table 'quiz_attempts' stores a record of each quiz attempt.
|
||||||
|
// It contains a userid which links to the user making the attempt and contains information about that attempt.
|
||||||
|
$items->add_database_table('quiz_attempts', [
|
||||||
|
'attempt' => 'privacy:metadata:quiz_attempts:attempt',
|
||||||
|
'currentpage' => 'privacy:metadata:quiz_attempts:currentpage',
|
||||||
|
'preview' => 'privacy:metadata:quiz_attempts:preview',
|
||||||
|
'state' => 'privacy:metadata:quiz_attempts:state',
|
||||||
|
'timestart' => 'privacy:metadata:quiz_attempts:timestart',
|
||||||
|
'timefinish' => 'privacy:metadata:quiz_attempts:timefinish',
|
||||||
|
'timemodified' => 'privacy:metadata:quiz_attempts:timemodified',
|
||||||
|
'timemodifiedoffline' => 'privacy:metadata:quiz_attempts:timemodifiedoffline',
|
||||||
|
'timecheckstate' => 'privacy:metadata:quiz_attempts:timecheckstate',
|
||||||
|
'sumgrades' => 'privacy:metadata:quiz_attempts:sumgrades',
|
||||||
|
], 'privacy:metadata:quiz_attempts');
|
||||||
|
|
||||||
|
// The table 'quiz_feedback' contains the feedback responses which will be shown to users depending upon the
|
||||||
|
// grade they achieve in the quiz.
|
||||||
|
// It does not identify the user who wrote the feedback item so cannot be returned directly and is not
|
||||||
|
// described, but relevant feedback items will be included with the quiz export for a user who has a grade.
|
||||||
|
|
||||||
|
// The table 'quiz_grades' contains the current grade for each quiz/user combination.
|
||||||
|
$items->add_database_table('quiz_grades', [
|
||||||
|
'quiz' => 'privacy:metadata:quiz_grades:quiz',
|
||||||
|
'userid' => 'privacy:metadata:quiz_grades:userid',
|
||||||
|
'grade' => 'privacy:metadata:quiz_grades:grade',
|
||||||
|
'timemodified' => 'privacy:metadata:quiz_grades:timemodified',
|
||||||
|
], 'privacy:metadata:quiz_grades');
|
||||||
|
|
||||||
|
// The table 'quiz_overrides' contains any user or group overrides for users.
|
||||||
|
// It should be included where data exists for a user.
|
||||||
|
$items->add_database_table('quiz_overrides', [
|
||||||
|
'quiz' => 'privacy:metadata:quiz_overrides:quiz',
|
||||||
|
'userid' => 'privacy:metadata:quiz_overrides:userid',
|
||||||
|
'timeopen' => 'privacy:metadata:quiz_overrides:timeopen',
|
||||||
|
'timeclose' => 'privacy:metadata:quiz_overrides:timeclose',
|
||||||
|
'timelimit' => 'privacy:metadata:quiz_overrides:timelimit',
|
||||||
|
], 'privacy:metadata:quiz_overrides');
|
||||||
|
|
||||||
|
// These define the structure of the quiz.
|
||||||
|
|
||||||
|
// The table 'quiz_sections' contains data about the structure of a quiz.
|
||||||
|
// It does not contain any user identifying data and does not need a mapping.
|
||||||
|
|
||||||
|
// The table 'quiz_slots' contains data about the structure of a quiz.
|
||||||
|
// It does not contain any user identifying data and does not need a mapping.
|
||||||
|
|
||||||
|
// The table 'quiz_reports' does not contain any user identifying data and does not need a mapping.
|
||||||
|
|
||||||
|
// The table 'quiz_statistics' contains abstract statistics about question usage and cannot be mapped to any
|
||||||
|
// specific user.
|
||||||
|
// It does not contain any user identifying data and does not need a mapping.
|
||||||
|
|
||||||
|
// The quiz links to the 'core_question' subsystem for all question functionality.
|
||||||
|
$items->add_subsystem_link('core_question', [], 'privacy:metadata:core_question');
|
||||||
|
|
||||||
|
// The quiz has two subplugins..
|
||||||
|
$items->add_plugintype_link('quiz', [], 'privacy:metadata:quiz');
|
||||||
|
$items->add_plugintype_link('quizaccess', [], 'privacy:metadata:quizaccess');
|
||||||
|
|
||||||
|
// Although the quiz supports the core_completion API and defines custom completion items, these will be
|
||||||
|
// noted by the manager as all activity modules are capable of supporting this functionality.
|
||||||
|
|
||||||
|
return $items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of contexts where the specified user has attempted a quiz, or been involved with manual marking
|
||||||
|
* and/or grading of a quiz.
|
||||||
|
*
|
||||||
|
* @param int $userid The user to search.
|
||||||
|
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
|
||||||
|
*/
|
||||||
|
public static function get_contexts_for_userid(int $userid) : contextlist {
|
||||||
|
// Get the SQL used to link indirect question usages for the user.
|
||||||
|
// This includes where a user is the manual marker on a question attempt.
|
||||||
|
$qubaid = \core_question\privacy\provider::get_related_question_usages_for_user('rel', 'mod_quiz', 'qa.uniqueid', $userid);
|
||||||
|
|
||||||
|
// Select the context of any quiz attempt where a user has an attempt, plus the related usages.
|
||||||
|
$sql = "SELECT c.id
|
||||||
|
FROM {context} c
|
||||||
|
JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
|
||||||
|
JOIN {modules} m ON m.id = cm.module AND m.name = :modname
|
||||||
|
JOIN {quiz} q ON q.id = cm.instance
|
||||||
|
JOIN {quiz_attempts} qa ON qa.quiz = q.id
|
||||||
|
LEFT JOIN {quiz_overrides} qo ON qo.quiz = q.id AND qo.userid = :qouserid
|
||||||
|
" . $qubaid->from . "
|
||||||
|
WHERE (
|
||||||
|
qa.userid = :qauserid OR
|
||||||
|
" . $qubaid->where() . "
|
||||||
|
) AND qa.preview = 0
|
||||||
|
";
|
||||||
|
|
||||||
|
$params = array_merge(
|
||||||
|
[
|
||||||
|
'contextlevel' => CONTEXT_MODULE,
|
||||||
|
'modname' => 'quiz',
|
||||||
|
'qauserid' => $userid,
|
||||||
|
'qouserid' => $userid,
|
||||||
|
],
|
||||||
|
$qubaid->from_where_params()
|
||||||
|
);
|
||||||
|
|
||||||
|
$resultset = new contextlist();
|
||||||
|
$resultset->add_from_sql($sql, $params);
|
||||||
|
|
||||||
|
return $resultset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all data for all users in the specified context.
|
||||||
|
*
|
||||||
|
* @param approved_contextlist $contextlist The approved contexts to export information for.
|
||||||
|
*/
|
||||||
|
public static function export_user_data(approved_contextlist $contextlist) {
|
||||||
|
global $DB;
|
||||||
|
|
||||||
|
if (!count($contextlist)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = $contextlist->get_user();
|
||||||
|
$userid = $user->id;
|
||||||
|
list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
|
||||||
|
|
||||||
|
$sql = "SELECT
|
||||||
|
q.*,
|
||||||
|
qg.id AS hasgrade,
|
||||||
|
qg.grade AS bestgrade,
|
||||||
|
qg.timemodified AS grademodified,
|
||||||
|
qo.id AS hasoverride,
|
||||||
|
qo.timeopen AS override_timeopen,
|
||||||
|
qo.timeclose AS override_timeclose,
|
||||||
|
qo.timelimit AS override_timelimit,
|
||||||
|
c.id AS contextid,
|
||||||
|
cm.id AS cmid
|
||||||
|
FROM {context} c
|
||||||
|
INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
|
||||||
|
INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname
|
||||||
|
INNER JOIN {quiz} q ON q.id = cm.instance
|
||||||
|
LEFT JOIN {quiz_overrides} qo ON qo.quiz = q.id AND qo.userid = :qouserid
|
||||||
|
LEFT JOIN {quiz_grades} qg ON qg.quiz = q.id AND qg.userid = :qguserid
|
||||||
|
WHERE c.id {$contextsql}";
|
||||||
|
|
||||||
|
$params = [
|
||||||
|
'contextlevel' => CONTEXT_MODULE,
|
||||||
|
'modname' => 'quiz',
|
||||||
|
'qguserid' => $userid,
|
||||||
|
'qouserid' => $userid,
|
||||||
|
];
|
||||||
|
$params += $contextparams;
|
||||||
|
|
||||||
|
// Fetch the individual quizzes.
|
||||||
|
$quizzes = $DB->get_recordset_sql($sql, $params);
|
||||||
|
foreach ($quizzes as $quiz) {
|
||||||
|
list($course, $cm) = get_course_and_cm_from_cmid($quiz->cmid, 'quiz');
|
||||||
|
$quizobj = new \quiz($quiz, $cm, $course);
|
||||||
|
$context = $quizobj->get_context();
|
||||||
|
|
||||||
|
$quizdata = \core_privacy\local\request\helper::get_context_data($context, $contextlist->get_user());
|
||||||
|
\core_privacy\local\request\helper::export_context_files($context, $contextlist->get_user());
|
||||||
|
|
||||||
|
if (!empty($quizdata->timeopen)) {
|
||||||
|
$quizdata->timeopen = transform::datetime($quiz->timeopen);
|
||||||
|
}
|
||||||
|
if (!empty($quizdata->timeclose)) {
|
||||||
|
$quizdata->timeclose = transform::datetime($quiz->timeclose);
|
||||||
|
}
|
||||||
|
if (!empty($quizdata->timelimit)) {
|
||||||
|
$quizdata->timelimit = $quiz->timelimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($quiz->hasoverride)) {
|
||||||
|
$quizdata->override = (object) [];
|
||||||
|
|
||||||
|
if (!empty($quizdata->override_override_timeopen)) {
|
||||||
|
$quizdata->override->timeopen = transform::datetime($quiz->override_timeopen);
|
||||||
|
}
|
||||||
|
if (!empty($quizdata->override_timeclose)) {
|
||||||
|
$quizdata->override->timeclose = transform::datetime($quiz->override_timeclose);
|
||||||
|
}
|
||||||
|
if (!empty($quizdata->override_timelimit)) {
|
||||||
|
$quizdata->override->timelimit = $quiz->override_timelimit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$quizdata->accessdata = (object) [];
|
||||||
|
|
||||||
|
$components = \core_component::get_plugin_list('quizaccess');
|
||||||
|
$exportparams = [
|
||||||
|
$quizobj,
|
||||||
|
$user,
|
||||||
|
];
|
||||||
|
foreach (array_keys($components) as $component) {
|
||||||
|
$classname = manager::get_provider_classname_for_component("quizaccess_$component");
|
||||||
|
if (class_exists($classname) && is_subclass_of($classname, quizaccess_provider::class)) {
|
||||||
|
$result = component_class_callback($classname, 'export_quizaccess_user_data', $exportparams);
|
||||||
|
if (count((array) $result)) {
|
||||||
|
$quizdata->accessdata->$component = $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty((array) $quizdata->accessdata)) {
|
||||||
|
unset($quizdata->accessdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer::with_context($context)
|
||||||
|
->export_data([], $quizdata);
|
||||||
|
}
|
||||||
|
$quizzes->close();
|
||||||
|
|
||||||
|
// Store all quiz attempt data.
|
||||||
|
static::export_quiz_attempts($contextlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all data for all users in the specified context.
|
||||||
|
*
|
||||||
|
* @param context $context The specific context to delete data for.
|
||||||
|
*/
|
||||||
|
public static function delete_data_for_all_users_in_context(\context $context) {
|
||||||
|
$cm = get_coursemodule_from_id('quiz', $context->instanceid);
|
||||||
|
if (!$cm) {
|
||||||
|
// Only quiz module will be handled.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$quiz = \quiz::create($cm->instance);
|
||||||
|
|
||||||
|
// Handle the 'quizaccess' subplugin.
|
||||||
|
manager::plugintype_class_callback(
|
||||||
|
'quizaccess',
|
||||||
|
quizaccess_provider::class,
|
||||||
|
'delete_subplugin_data_for_all_users_in_context',
|
||||||
|
[$quiz]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Delete all overrides - do not log.
|
||||||
|
quiz_delete_all_overrides($quiz, false);
|
||||||
|
|
||||||
|
// This will delete all question attempts, quiz attempts, and quiz grades for this quiz.
|
||||||
|
quiz_delete_all_attempts($quiz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all user data for the specified user, in the specified contexts.
|
||||||
|
*
|
||||||
|
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
|
||||||
|
*/
|
||||||
|
public static function delete_data_for_user(approved_contextlist $contextlist) {
|
||||||
|
global $DB;
|
||||||
|
|
||||||
|
foreach ($contextlist as $context) {
|
||||||
|
$cm = get_coursemodule_from_id('quiz', $context->instanceid);
|
||||||
|
$quiz = \quiz::create($cm->instance);
|
||||||
|
$user = $contextlist->get_user();
|
||||||
|
|
||||||
|
// Handle the 'quizaccess' quizaccess.
|
||||||
|
manager::plugintype_class_callback(
|
||||||
|
'quizaccess',
|
||||||
|
quizaccess_provider::class,
|
||||||
|
'delete_quizaccess_data_for_user',
|
||||||
|
[$quiz, $user]
|
||||||
|
);
|
||||||
|
|
||||||
|
$overrides = $DB->get_records('quiz_overrides' , [
|
||||||
|
'quiz' => $quiz->get_quizid(),
|
||||||
|
'userid' => $user->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
foreach ($overrides as $override) {
|
||||||
|
quiz_delete_override($quiz, $override->id, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will delete all question attempts, quiz attempts, and quiz grades for this quiz.
|
||||||
|
quiz_delete_user_attempts($quiz, $user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store all quiz attempts for the contextlist.
|
||||||
|
*
|
||||||
|
* @param approved_contextlist $contextlist
|
||||||
|
*/
|
||||||
|
protected static function export_quiz_attempts(approved_contextlist $contextlist) {
|
||||||
|
global $DB;
|
||||||
|
|
||||||
|
$userid = $contextlist->get_user()->id;
|
||||||
|
list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
|
||||||
|
$qubaid = \core_question\privacy\provider::get_related_question_usages_for_user('rel', 'mod_quiz', 'qa.uniqueid', $userid);
|
||||||
|
|
||||||
|
$sql = "SELECT
|
||||||
|
c.id AS contextid,
|
||||||
|
cm.id AS cmid,
|
||||||
|
qa.*
|
||||||
|
FROM {context} c
|
||||||
|
JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
|
||||||
|
JOIN {modules} m ON m.id = cm.module AND m.name = 'quiz'
|
||||||
|
JOIN {quiz} q ON q.id = cm.instance
|
||||||
|
JOIN {quiz_attempts} qa ON qa.quiz = q.id
|
||||||
|
" . $qubaid->from. "
|
||||||
|
WHERE (
|
||||||
|
qa.userid = :qauserid OR
|
||||||
|
" . $qubaid->where() . "
|
||||||
|
) AND qa.preview = 0
|
||||||
|
";
|
||||||
|
|
||||||
|
$params = array_merge(
|
||||||
|
[
|
||||||
|
'contextlevel' => CONTEXT_MODULE,
|
||||||
|
'qauserid' => $userid,
|
||||||
|
],
|
||||||
|
$qubaid->from_where_params()
|
||||||
|
);
|
||||||
|
|
||||||
|
$attempts = $DB->get_recordset_sql($sql, $params);
|
||||||
|
foreach ($attempts as $attempt) {
|
||||||
|
$quiz = $DB->get_record('quiz', ['id' => $attempt->quiz]);
|
||||||
|
$context = \context_module::instance($attempt->cmid);
|
||||||
|
$attemptsubcontext = helper::get_quiz_attempt_subcontext($attempt, $contextlist->get_user());
|
||||||
|
$options = quiz_get_review_options($quiz, $attempt, $context);
|
||||||
|
|
||||||
|
if ($attempt->userid == $userid) {
|
||||||
|
// This attempt was made by the user.
|
||||||
|
// They 'own' all data on it.
|
||||||
|
// Store the question usage data.
|
||||||
|
\core_question\privacy\provider::export_question_usage($userid,
|
||||||
|
$context,
|
||||||
|
$attemptsubcontext,
|
||||||
|
$attempt->uniqueid,
|
||||||
|
$options,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Store the quiz attempt data.
|
||||||
|
$data = (object) [
|
||||||
|
'state' => \quiz_attempt::state_name($attempt->state),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!empty($attempt->timestart)) {
|
||||||
|
$data->timestart = transform::datetime($attempt->timestart);
|
||||||
|
}
|
||||||
|
if (!empty($attempt->timefinish)) {
|
||||||
|
$data->timefinish = transform::datetime($attempt->timefinish);
|
||||||
|
}
|
||||||
|
if (!empty($attempt->timemodified)) {
|
||||||
|
$data->timemodified = transform::datetime($attempt->timemodified);
|
||||||
|
}
|
||||||
|
if (!empty($attempt->timemodifiedoffline)) {
|
||||||
|
$data->timemodifiedoffline = transform::datetime($attempt->timemodifiedoffline);
|
||||||
|
}
|
||||||
|
if (!empty($attempt->timecheckstate)) {
|
||||||
|
$data->timecheckstate = transform::datetime($attempt->timecheckstate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($options->marks == \question_display_options::MARK_AND_MAX) {
|
||||||
|
$grade = quiz_rescale_grade($attempt->sumgrades, $quiz, false);
|
||||||
|
$data->grade = (object) [
|
||||||
|
'grade' => quiz_format_grade($quiz, $grade),
|
||||||
|
'feedback' => quiz_feedback_for_grade($grade, $quiz, $context),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
writer::with_context($context)
|
||||||
|
->export_data($attemptsubcontext, $data);
|
||||||
|
} else {
|
||||||
|
// This attempt was made by another user.
|
||||||
|
// The current user may have marked part of the quiz attempt.
|
||||||
|
\core_question\privacy\provider::export_question_usage(
|
||||||
|
$userid,
|
||||||
|
$context,
|
||||||
|
$attemptsubcontext,
|
||||||
|
$attempt->uniqueid,
|
||||||
|
$options,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$attempts->close();
|
||||||
|
}
|
||||||
|
}
|
63
mod/quiz/classes/privacy/quizaccess_provider.php
Normal file
63
mod/quiz/classes/privacy/quizaccess_provider.php
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The quizaccess_provider interface provides the expected interface for all 'quizaccess' quizaccesss.
|
||||||
|
*
|
||||||
|
* @package mod_quiz
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
namespace mod_quiz\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
use \core_privacy\local\request\contextlist;
|
||||||
|
use \core_privacy\local\request\approved_contextlist;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The quizaccess_provider interface provides the expected interface for all 'quizaccess' quizaccesss.
|
||||||
|
*
|
||||||
|
* @package mod_quiz
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
interface quizaccess_provider extends \core_privacy\local\request\plugin\subplugin_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export all user data for the specified user, for the specified quiz.
|
||||||
|
*
|
||||||
|
* @param \quiz $quiz The quiz being exported
|
||||||
|
* @param \stdClass $user The user to export data for
|
||||||
|
* @return \stdClass The data to be exported for this access rule.
|
||||||
|
*/
|
||||||
|
public static function export_quizaccess_user_data(\quiz $quiz, \stdClass $user) : \stdClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all data for all users in the specified quiz.
|
||||||
|
*
|
||||||
|
* @param \quiz $quiz The quiz being deleted
|
||||||
|
*/
|
||||||
|
public static function delete_quizaccess_data_for_all_users_in_context(\quiz $quiz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all user data for the specified user, in the specified quiz.
|
||||||
|
*
|
||||||
|
* @param \quiz $quiz The quiz being deleted
|
||||||
|
* @param \stdClass $user The user to export data for
|
||||||
|
*/
|
||||||
|
public static function delete_quizaccess_data_for_user(\quiz $quiz, \stdClass $user);
|
||||||
|
}
|
|
@ -626,6 +626,31 @@ $string['previewquestion'] = 'Preview question';
|
||||||
$string['previewquiz'] = 'Preview {$a}';
|
$string['previewquiz'] = 'Preview {$a}';
|
||||||
$string['previewquiznow'] = 'Preview quiz now';
|
$string['previewquiznow'] = 'Preview quiz now';
|
||||||
$string['previous'] = 'Previous state';
|
$string['previous'] = 'Previous state';
|
||||||
|
$string['privacy:metadata:core_question'] = 'The quiz activity stores question usage information in the core_question subsystem.';
|
||||||
|
$string['privacy:metadata:quiz'] = 'The quiz activity makes use of quiz reports.';
|
||||||
|
$string['privacy:metadata:quiz_attempts'] = 'Details about each attempt on a quiz.';
|
||||||
|
$string['privacy:metadata:quiz_attempts:attempt'] = 'The attempt number.';
|
||||||
|
$string['privacy:metadata:quiz_attempts:currentpage'] = 'The current page that the user is on.';
|
||||||
|
$string['privacy:metadata:quiz_attempts:preview'] = 'Whether this is a preview of the quiz.';
|
||||||
|
$string['privacy:metadata:quiz_attempts:state'] = 'The current state of the attempt.';
|
||||||
|
$string['privacy:metadata:quiz_attempts:sumgrades'] = 'The sum of grades in the attempt.';
|
||||||
|
$string['privacy:metadata:quiz_attempts:timecheckstate'] = 'The time that the state was checked.';
|
||||||
|
$string['privacy:metadata:quiz_attempts:timefinish'] = 'The time that the attempt was completed.';
|
||||||
|
$string['privacy:metadata:quiz_attempts:timemodified'] = 'The time that the attempt was updated.';
|
||||||
|
$string['privacy:metadata:quiz_attempts:timemodifiedoffline'] = 'The time that the attempt was updated via an offline update.';
|
||||||
|
$string['privacy:metadata:quiz_attempts:timestart'] = 'The time that the attempt was started.';
|
||||||
|
$string['privacy:metadata:quiz_grades'] = 'Details about the overall grade for this quiz.';
|
||||||
|
$string['privacy:metadata:quiz_grades:grade'] = 'The overall grade for this quiz.';
|
||||||
|
$string['privacy:metadata:quiz_grades:quiz'] = 'The quiz that was graded.';
|
||||||
|
$string['privacy:metadata:quiz_grades:timemodified'] = 'The time that the grade was modified.';
|
||||||
|
$string['privacy:metadata:quiz_grades:userid'] = 'The user who was graded.';
|
||||||
|
$string['privacy:metadata:quiz_overrides'] = 'Details about overrides for this quiz.';
|
||||||
|
$string['privacy:metadata:quiz_overrides:quiz'] = 'The quiz with override information.';
|
||||||
|
$string['privacy:metadata:quiz_overrides:timeclose'] = 'The new close time for the quiz.';
|
||||||
|
$string['privacy:metadata:quiz_overrides:timelimit'] = 'The new time limit for the quiz.';
|
||||||
|
$string['privacy:metadata:quiz_overrides:timeopen'] = 'The new open time for the quiz.';
|
||||||
|
$string['privacy:metadata:quiz_overrides:userid'] = 'The user being overridden.';
|
||||||
|
$string['privacy:metadata:quizaccess'] = 'The quiz activity makes use of quiz access rules.';
|
||||||
$string['publish'] = 'Publish';
|
$string['publish'] = 'Publish';
|
||||||
$string['publishedit'] = 'You must have permission in the publishing course to add or edit questions in this category';
|
$string['publishedit'] = 'You must have permission in the publishing course to add or edit questions in this category';
|
||||||
$string['qname'] = 'name';
|
$string['qname'] = 'name';
|
||||||
|
|
|
@ -214,9 +214,10 @@ function quiz_delete_instance($id) {
|
||||||
*
|
*
|
||||||
* @param object $quiz The quiz object.
|
* @param object $quiz The quiz object.
|
||||||
* @param int $overrideid The id of the override being deleted
|
* @param int $overrideid The id of the override being deleted
|
||||||
|
* @param bool $log Whether to trigger logs.
|
||||||
* @return bool true on success
|
* @return bool true on success
|
||||||
*/
|
*/
|
||||||
function quiz_delete_override($quiz, $overrideid) {
|
function quiz_delete_override($quiz, $overrideid, $log = true) {
|
||||||
global $DB;
|
global $DB;
|
||||||
|
|
||||||
if (!isset($quiz->cmid)) {
|
if (!isset($quiz->cmid)) {
|
||||||
|
@ -244,26 +245,28 @@ function quiz_delete_override($quiz, $overrideid) {
|
||||||
|
|
||||||
$DB->delete_records('quiz_overrides', array('id' => $overrideid));
|
$DB->delete_records('quiz_overrides', array('id' => $overrideid));
|
||||||
|
|
||||||
// Set the common parameters for one of the events we will be triggering.
|
if ($log) {
|
||||||
$params = array(
|
// Set the common parameters for one of the events we will be triggering.
|
||||||
'objectid' => $override->id,
|
$params = array(
|
||||||
'context' => context_module::instance($quiz->cmid),
|
'objectid' => $override->id,
|
||||||
'other' => array(
|
'context' => context_module::instance($quiz->cmid),
|
||||||
'quizid' => $override->quiz
|
'other' => array(
|
||||||
)
|
'quizid' => $override->quiz
|
||||||
);
|
)
|
||||||
// Determine which override deleted event to fire.
|
);
|
||||||
if (!empty($override->userid)) {
|
// Determine which override deleted event to fire.
|
||||||
$params['relateduserid'] = $override->userid;
|
if (!empty($override->userid)) {
|
||||||
$event = \mod_quiz\event\user_override_deleted::create($params);
|
$params['relateduserid'] = $override->userid;
|
||||||
} else {
|
$event = \mod_quiz\event\user_override_deleted::create($params);
|
||||||
$params['other']['groupid'] = $override->groupid;
|
} else {
|
||||||
$event = \mod_quiz\event\group_override_deleted::create($params);
|
$params['other']['groupid'] = $override->groupid;
|
||||||
}
|
$event = \mod_quiz\event\group_override_deleted::create($params);
|
||||||
|
}
|
||||||
|
|
||||||
// Trigger the override deleted event.
|
// Trigger the override deleted event.
|
||||||
$event->add_record_snapshot('quiz_overrides', $override);
|
$event->add_record_snapshot('quiz_overrides', $override);
|
||||||
$event->trigger();
|
$event->trigger();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -272,13 +275,14 @@ function quiz_delete_override($quiz, $overrideid) {
|
||||||
* Deletes all quiz overrides from the database and clears any corresponding calendar events
|
* Deletes all quiz overrides from the database and clears any corresponding calendar events
|
||||||
*
|
*
|
||||||
* @param object $quiz The quiz object.
|
* @param object $quiz The quiz object.
|
||||||
|
* @param bool $log Whether to trigger logs.
|
||||||
*/
|
*/
|
||||||
function quiz_delete_all_overrides($quiz) {
|
function quiz_delete_all_overrides($quiz, $log = true) {
|
||||||
global $DB;
|
global $DB;
|
||||||
|
|
||||||
$overrides = $DB->get_records('quiz_overrides', array('quiz' => $quiz->id), 'id');
|
$overrides = $DB->get_records('quiz_overrides', array('quiz' => $quiz->id), 'id');
|
||||||
foreach ($overrides as $override) {
|
foreach ($overrides as $override) {
|
||||||
quiz_delete_override($quiz, $override->id);
|
quiz_delete_override($quiz, $override->id, $log);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,6 +409,24 @@ function quiz_delete_all_attempts($quiz) {
|
||||||
$DB->delete_records('quiz_grades', array('quiz' => $quiz->id));
|
$DB->delete_records('quiz_grades', array('quiz' => $quiz->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all the attempts belonging to a user in a particular quiz.
|
||||||
|
*
|
||||||
|
* @param object $quiz The quiz object.
|
||||||
|
* @param object $user The user object.
|
||||||
|
*/
|
||||||
|
function quiz_delete_user_attempts($quiz, $user) {
|
||||||
|
global $CFG, $DB;
|
||||||
|
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||||
|
question_engine::delete_questions_usage_by_activities(new qubaids_for_quiz_user($quiz->get_quizid(), $user->id));
|
||||||
|
$params = [
|
||||||
|
'quiz' => $quiz->get_quizid(),
|
||||||
|
'userid' => $user->id,
|
||||||
|
];
|
||||||
|
$DB->delete_records('quiz_attempts', $params);
|
||||||
|
$DB->delete_records('quiz_grades', $params);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the best current grade for a particular user in a quiz.
|
* Get the best current grade for a particular user in a quiz.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1972,7 +1972,6 @@ class mod_quiz_display_options extends question_display_options {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link qubaid_condition} for finding all the question usages belonging to
|
* A {@link qubaid_condition} for finding all the question usages belonging to
|
||||||
* a particular quiz.
|
* a particular quiz.
|
||||||
|
@ -1998,6 +1997,41 @@ class qubaids_for_quiz extends qubaid_join {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link qubaid_condition} for finding all the question usages belonging to a particular user and quiz combination.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrwe@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class qubaids_for_quiz_user extends qubaid_join {
|
||||||
|
/**
|
||||||
|
* Constructor for this qubaid.
|
||||||
|
*
|
||||||
|
* @param int $quizid The quiz to search.
|
||||||
|
* @param int $userid The user to filter on
|
||||||
|
* @param bool $includepreviews Whether to include preview attempts
|
||||||
|
* @param bool $onlyfinished Whether to only include finished attempts or not
|
||||||
|
*/
|
||||||
|
public function __construct($quizid, $userid, $includepreviews = true, $onlyfinished = false) {
|
||||||
|
$where = 'quiza.quiz = :quizaquiz AND quiza.userid = :quizauserid';
|
||||||
|
$params = [
|
||||||
|
'quizaquiz' => $quizid,
|
||||||
|
'quizauserid' => $userid,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!$includepreviews) {
|
||||||
|
$where .= ' AND preview = 0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($onlyfinished) {
|
||||||
|
$where .= ' AND state = :statefinished';
|
||||||
|
$params['statefinished'] = quiz_attempt::FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct('{quiz_attempts} quiza', 'quiza.uniqueid', $where, $params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a textual representation of a question for display.
|
* Creates a textual representation of a question for display.
|
||||||
*
|
*
|
||||||
|
|
46
mod/quiz/report/grading/classes/privacy/provider.php
Normal file
46
mod/quiz/report/grading/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for quiz_grading.
|
||||||
|
*
|
||||||
|
* @package quiz_grading
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace quiz_grading\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for quiz_grading implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -68,6 +68,7 @@ $string['nothingfound'] = 'Nothing to display';
|
||||||
$string['options'] = 'Options';
|
$string['options'] = 'Options';
|
||||||
$string['orderattempts'] = 'Order attempts';
|
$string['orderattempts'] = 'Order attempts';
|
||||||
$string['pluginname'] = 'Manual grading';
|
$string['pluginname'] = 'Manual grading';
|
||||||
|
$string['privacy:metadata'] = 'The Quiz Manual grading plugin does not store any personal data. It provides an interface for users to store data without storing any data itself.';
|
||||||
$string['qno'] = 'Q #';
|
$string['qno'] = 'Q #';
|
||||||
$string['questionname'] = 'Question name';
|
$string['questionname'] = 'Question name';
|
||||||
$string['questionsperpage'] = 'Questions per page';
|
$string['questionsperpage'] = 'Questions per page';
|
||||||
|
|
78
mod/quiz/report/overview/classes/privacy/provider.php
Normal file
78
mod/quiz/report/overview/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for quiz_overview..
|
||||||
|
*
|
||||||
|
* @package quiz_overview
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace quiz_overview\privacy;
|
||||||
|
|
||||||
|
use \core_privacy\local\request\writer;
|
||||||
|
use \core_privacy\local\request\transform;
|
||||||
|
use \core_privacy\local\metadata\collection;
|
||||||
|
use \core_privacy\manager;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for quiz_overview..
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements
|
||||||
|
\core_privacy\local\metadata\provider,
|
||||||
|
\core_privacy\local\request\user_preference_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns meta data about this system.
|
||||||
|
*
|
||||||
|
* @param collection $collection The initialised collection to add items to.
|
||||||
|
* @return collection A listing of user data stored through this system.
|
||||||
|
*/
|
||||||
|
public static function get_metadata(collection $collection) : collection {
|
||||||
|
$collection->add_user_preference('quiz_overview_slotmarks', 'privacy:metadata:preference:quiz_overview_slotmarks');
|
||||||
|
|
||||||
|
return $collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export all user preferences for the plugin.
|
||||||
|
*
|
||||||
|
* @param int $userid The userid of the user whose data is to be exported.
|
||||||
|
*/
|
||||||
|
public static function export_user_preferences(int $userid) {
|
||||||
|
$preference = get_user_preferences('quiz_overview_slotmarks', null);
|
||||||
|
if (null !== $preference) {
|
||||||
|
if (empty($preference)) {
|
||||||
|
$description = get_string('privacy:preference:slotmarks:no', 'quiz_overview');
|
||||||
|
} else {
|
||||||
|
$description = get_string('privacy:preference:slotmarks:yes', 'quiz_overview');
|
||||||
|
}
|
||||||
|
|
||||||
|
writer::export_user_preference(
|
||||||
|
'quiz_overview',
|
||||||
|
'slotmarks',
|
||||||
|
transform::yesno($preference),
|
||||||
|
$description
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -53,6 +53,9 @@ $string['pluginname'] = 'Grades';
|
||||||
$string['preferencespage'] = 'Preferences just for this page';
|
$string['preferencespage'] = 'Preferences just for this page';
|
||||||
$string['preferencessave'] = 'Show report';
|
$string['preferencessave'] = 'Show report';
|
||||||
$string['preferencesuser'] = 'Your preferences for this report';
|
$string['preferencesuser'] = 'Your preferences for this report';
|
||||||
|
$string['privacy:metadata:preference:quiz_overview_slotmarks'] = 'Whether to show marks for each question slot.';
|
||||||
|
$string['privacy:preference:slotmarks:yes'] = 'Marks are shown alongside the question slot.';
|
||||||
|
$string['privacy:preference:slotmarks:no'] = 'Marks are not shown alongside the question slot.';
|
||||||
$string['regrade'] = 'Regrade';
|
$string['regrade'] = 'Regrade';
|
||||||
$string['regradeall'] = 'Regrade all';
|
$string['regradeall'] = 'Regrade all';
|
||||||
$string['regradealldry'] = 'Dry run a full regrade';
|
$string['regradealldry'] = 'Dry run a full regrade';
|
||||||
|
|
99
mod/quiz/report/overview/tests/privacy_provider_test.php
Normal file
99
mod/quiz/report/overview/tests/privacy_provider_test.php
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy provider tests.
|
||||||
|
*
|
||||||
|
* @package quiz_overview
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
use core_privacy\local\metadata\collection;
|
||||||
|
use quiz_overview\privacy\provider;
|
||||||
|
use core_privacy\local\request\writer;
|
||||||
|
use core_privacy\local\request\transform;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy provider tests class.
|
||||||
|
*
|
||||||
|
* @package quiz_overview
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class quiz_overview_privacy_provider_testcase extends \core_privacy\tests\provider_testcase {
|
||||||
|
/**
|
||||||
|
* When no preference exists, there should be no export.
|
||||||
|
*/
|
||||||
|
public function test_preference_unset() {
|
||||||
|
global $USER;
|
||||||
|
|
||||||
|
$this->resetAfterTest();
|
||||||
|
$this->setAdminUser();
|
||||||
|
|
||||||
|
provider::export_user_preferences($USER->id);
|
||||||
|
|
||||||
|
$this->assertFalse(writer::with_context(\context_system::instance())->has_any_data());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preference does exist.
|
||||||
|
*/
|
||||||
|
public function test_preference_yes() {
|
||||||
|
global $USER;
|
||||||
|
|
||||||
|
$this->resetAfterTest();
|
||||||
|
$this->setAdminUser();
|
||||||
|
|
||||||
|
set_user_preference('quiz_overview_slotmarks', 1);
|
||||||
|
|
||||||
|
provider::export_user_preferences($USER->id);
|
||||||
|
|
||||||
|
$writer = writer::with_context(\context_system::instance());
|
||||||
|
$this->assertTrue($writer->has_any_data());
|
||||||
|
|
||||||
|
$preferences = $writer->get_user_preferences('quiz_overview');
|
||||||
|
$this->assertNotEmpty($preferences->slotmarks);
|
||||||
|
$this->assertEquals(transform::yesno(1), $preferences->slotmarks->value);
|
||||||
|
$description = get_string('privacy:preference:slotmarks:yes', 'quiz_overview');
|
||||||
|
$this->assertEquals($description, $preferences->slotmarks->description);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preference does exist and is no.
|
||||||
|
*/
|
||||||
|
public function test_preference_no() {
|
||||||
|
global $USER;
|
||||||
|
|
||||||
|
$this->resetAfterTest();
|
||||||
|
$this->setAdminUser();
|
||||||
|
|
||||||
|
set_user_preference('quiz_overview_slotmarks', 0);
|
||||||
|
|
||||||
|
provider::export_user_preferences($USER->id);
|
||||||
|
|
||||||
|
$writer = writer::with_context(\context_system::instance());
|
||||||
|
$this->assertTrue($writer->has_any_data());
|
||||||
|
|
||||||
|
$preferences = $writer->get_user_preferences('quiz_overview');
|
||||||
|
$this->assertNotEmpty($preferences->slotmarks);
|
||||||
|
$this->assertEquals(transform::yesno(0), $preferences->slotmarks->value);
|
||||||
|
$description = get_string('privacy:preference:slotmarks:no', 'quiz_overview');
|
||||||
|
$this->assertEquals($description, $preferences->slotmarks->description);
|
||||||
|
}
|
||||||
|
}
|
99
mod/quiz/report/responses/classes/privacy/provider.php
Normal file
99
mod/quiz/report/responses/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for quiz_responses.
|
||||||
|
*
|
||||||
|
* @package quiz_responses
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace quiz_responses\privacy;
|
||||||
|
|
||||||
|
use core_privacy\local\metadata\collection;
|
||||||
|
use core_privacy\local\request\writer;
|
||||||
|
use core_privacy\local\request\transform;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
global $CFG;
|
||||||
|
require_once($CFG->dirroot . '/question/engine/questionattempt.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for quiz_responses with user preferences.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements
|
||||||
|
\core_privacy\local\metadata\provider,
|
||||||
|
\core_privacy\local\request\user_preference_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns meta data about this system.
|
||||||
|
*
|
||||||
|
* @param collection $collection The initialised collection to add items to.
|
||||||
|
* @return collection A listing of user data stored through this system.
|
||||||
|
*/
|
||||||
|
public static function get_metadata(collection $collection) : collection {
|
||||||
|
$collection->add_user_preference('quiz_report_responses_qtext', 'privacy:preference:qtext');
|
||||||
|
$collection->add_user_preference('quiz_report_responses_resp', 'privacy:preference:resp');
|
||||||
|
$collection->add_user_preference('quiz_report_responses_right', 'privacy:preference:right');
|
||||||
|
$collection->add_user_preference('quiz_report_responses_which_tries', 'privacy:preference:which_tries');
|
||||||
|
|
||||||
|
return $collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export all user preferences for the plugin.
|
||||||
|
*
|
||||||
|
* @param int $userid The userid of the user whose data is to be exported.
|
||||||
|
*/
|
||||||
|
public static function export_user_preferences(int $userid) {
|
||||||
|
$preferences = [
|
||||||
|
'qtext',
|
||||||
|
'resp',
|
||||||
|
'right',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($preferences as $key) {
|
||||||
|
$preference = get_user_preferences("quiz_report_responses_{$key}", null, $userid);
|
||||||
|
if (null !== $preference) {
|
||||||
|
$desc = get_string("privacy:preference:{$key}", 'quiz_responses');
|
||||||
|
writer::export_user_preference('quiz_responses', $key, transform::yesno($preference), $desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$preference = get_user_preferences("quiz_report_responses_which_tries", null, $userid);
|
||||||
|
if (null !== $preference) {
|
||||||
|
switch($preference) {
|
||||||
|
case \question_attempt::FIRST_TRY:
|
||||||
|
$value = get_string("privacy:preference:which_tries:first", 'quiz_responses');
|
||||||
|
break;
|
||||||
|
case \question_attempt::LAST_TRY:
|
||||||
|
$value = get_string("privacy:preference:which_tries:last", 'quiz_responses');
|
||||||
|
break;
|
||||||
|
case \question_attempt::ALL_TRIES:
|
||||||
|
$value = get_string("privacy:preference:which_tries:all", 'quiz_responses');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$desc = get_string("privacy:preference:which_tries", 'quiz_responses');
|
||||||
|
|
||||||
|
writer::export_user_preference('quiz_responses', 'which_tries', $value, $desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,13 @@ $string['include'] = 'Include the';
|
||||||
$string['mustselectcols'] = 'You must include something.';
|
$string['mustselectcols'] = 'You must include something.';
|
||||||
$string['pagesize'] = 'Page size';
|
$string['pagesize'] = 'Page size';
|
||||||
$string['pluginname'] = 'Responses';
|
$string['pluginname'] = 'Responses';
|
||||||
|
$string['privacy:preference:qtext'] = 'Whether to show the question text columns.';
|
||||||
|
$string['privacy:preference:resp'] = 'Whether to show the students\' response columns.';
|
||||||
|
$string['privacy:preference:right'] = 'Whether to show the correct response columns.';
|
||||||
|
$string['privacy:preference:which_tries'] = 'Which tries to show responses from.';
|
||||||
|
$string['privacy:preference:which_tries:first'] = 'The first try at a question during an attempt by a user.';
|
||||||
|
$string['privacy:preference:which_tries:last'] = 'The last try at a question during an attempt by a user.';
|
||||||
|
$string['privacy:preference:which_tries:all'] = 'All tries at a question during an attempt by a user.';
|
||||||
$string['questiontext'] = 'question text';
|
$string['questiontext'] = 'question text';
|
||||||
$string['reportresponses'] = 'Responses';
|
$string['reportresponses'] = 'Responses';
|
||||||
$string['response'] = 'response';
|
$string['response'] = 'response';
|
||||||
|
|
139
mod/quiz/report/responses/tests/privacy_provider_test.php
Normal file
139
mod/quiz/report/responses/tests/privacy_provider_test.php
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy provider tests.
|
||||||
|
*
|
||||||
|
* @package quiz_responses
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
use core_privacy\local\metadata\collection;
|
||||||
|
use quiz_responses\privacy\provider;
|
||||||
|
use core_privacy\local\request\writer;
|
||||||
|
use core_privacy\local\request\transform;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
global $CFG;
|
||||||
|
require_once($CFG->dirroot . '/question/engine/questionattempt.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy provider tests class.
|
||||||
|
*
|
||||||
|
* @package quiz_responses
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class quiz_responses_privacy_provider_testcase extends \core_privacy\tests\provider_testcase {
|
||||||
|
/**
|
||||||
|
* When no preference exists, there should be no export.
|
||||||
|
*/
|
||||||
|
public function test_preference_unset() {
|
||||||
|
global $USER;
|
||||||
|
|
||||||
|
$this->resetAfterTest();
|
||||||
|
$this->setAdminUser();
|
||||||
|
|
||||||
|
provider::export_user_preferences($USER->id);
|
||||||
|
|
||||||
|
$this->assertFalse(writer::with_context(\context_system::instance())->has_any_data());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preference does exist.
|
||||||
|
*/
|
||||||
|
public function test_preference_bool_true() {
|
||||||
|
global $USER;
|
||||||
|
|
||||||
|
$this->resetAfterTest();
|
||||||
|
$this->setAdminUser();
|
||||||
|
|
||||||
|
set_user_preference('quiz_report_responses_qtext', true);
|
||||||
|
set_user_preference('quiz_report_responses_resp', true);
|
||||||
|
set_user_preference('quiz_report_responses_right', true);
|
||||||
|
|
||||||
|
provider::export_user_preferences($USER->id);
|
||||||
|
|
||||||
|
$writer = writer::with_context(\context_system::instance());
|
||||||
|
$this->assertTrue($writer->has_any_data());
|
||||||
|
|
||||||
|
$preferences = $writer->get_user_preferences('quiz_responses');
|
||||||
|
|
||||||
|
$this->assertNotEmpty($preferences->qtext);
|
||||||
|
$this->assertEquals(transform::yesno(1), $preferences->qtext->value);
|
||||||
|
|
||||||
|
$this->assertNotEmpty($preferences->resp);
|
||||||
|
$this->assertEquals(transform::yesno(1), $preferences->resp->value);
|
||||||
|
|
||||||
|
$this->assertNotEmpty($preferences->right);
|
||||||
|
$this->assertEquals(transform::yesno(1), $preferences->right->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preference does exist.
|
||||||
|
*/
|
||||||
|
public function test_preference_bool_false() {
|
||||||
|
global $USER;
|
||||||
|
|
||||||
|
$this->resetAfterTest();
|
||||||
|
$this->setAdminUser();
|
||||||
|
|
||||||
|
set_user_preference('quiz_report_responses_qtext', false);
|
||||||
|
set_user_preference('quiz_report_responses_resp', false);
|
||||||
|
set_user_preference('quiz_report_responses_right', false);
|
||||||
|
|
||||||
|
provider::export_user_preferences($USER->id);
|
||||||
|
|
||||||
|
$writer = writer::with_context(\context_system::instance());
|
||||||
|
$this->assertTrue($writer->has_any_data());
|
||||||
|
|
||||||
|
$preferences = $writer->get_user_preferences('quiz_responses');
|
||||||
|
|
||||||
|
$this->assertNotEmpty($preferences->qtext);
|
||||||
|
$this->assertEquals(transform::yesno(0), $preferences->qtext->value);
|
||||||
|
|
||||||
|
$this->assertNotEmpty($preferences->resp);
|
||||||
|
$this->assertEquals(transform::yesno(0), $preferences->resp->value);
|
||||||
|
|
||||||
|
$this->assertNotEmpty($preferences->right);
|
||||||
|
$this->assertEquals(transform::yesno(0), $preferences->right->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preference does exist.
|
||||||
|
*/
|
||||||
|
public function test_preference_bool_which_first() {
|
||||||
|
global $USER;
|
||||||
|
|
||||||
|
$this->resetAfterTest();
|
||||||
|
$this->setAdminUser();
|
||||||
|
|
||||||
|
set_user_preference('quiz_report_responses_which_tries', question_attempt::FIRST_TRY);
|
||||||
|
|
||||||
|
provider::export_user_preferences($USER->id);
|
||||||
|
|
||||||
|
$writer = writer::with_context(\context_system::instance());
|
||||||
|
$this->assertTrue($writer->has_any_data());
|
||||||
|
|
||||||
|
$preferences = $writer->get_user_preferences('quiz_responses');
|
||||||
|
|
||||||
|
$expected = get_string("privacy:preference:which_tries:first", 'quiz_responses');
|
||||||
|
$this->assertNotEmpty($preferences->which_tries);
|
||||||
|
$this->assertEquals($expected, $preferences->which_tries->value);
|
||||||
|
}
|
||||||
|
}
|
46
mod/quiz/report/statistics/classes/privacy/provider.php
Normal file
46
mod/quiz/report/statistics/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for quiz_statistics.
|
||||||
|
*
|
||||||
|
* @package quiz_statistics
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace quiz_statistics\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for quiz_statistics implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -86,6 +86,7 @@ $string['nostudentsingroup'] = 'There are no students in this group yet';
|
||||||
$string['optiongrade'] = 'Partial credit';
|
$string['optiongrade'] = 'Partial credit';
|
||||||
$string['partofquestion'] = 'Part of question';
|
$string['partofquestion'] = 'Part of question';
|
||||||
$string['pluginname'] = 'Statistics';
|
$string['pluginname'] = 'Statistics';
|
||||||
|
$string['privacy:metadata'] = 'Although the Quiz Statistics plugin has database tables, the data is aggregate data and does not describe a unique indidividual.';
|
||||||
$string['position'] = 'Position';
|
$string['position'] = 'Position';
|
||||||
$string['positions'] = 'Position(s)';
|
$string['positions'] = 'Position(s)';
|
||||||
$string['questioninformation'] = 'Question information';
|
$string['questioninformation'] = 'Question information';
|
||||||
|
@ -115,4 +116,3 @@ $string['statistics:view'] = 'View statistics report';
|
||||||
$string['statsfor'] = 'Quiz statistics (for {$a})';
|
$string['statsfor'] = 'Quiz statistics (for {$a})';
|
||||||
$string['variant'] = 'Variant';
|
$string['variant'] = 'Variant';
|
||||||
$string['whichtries'] = 'Analyze responses for';
|
$string['whichtries'] = 'Analyze responses for';
|
||||||
|
|
||||||
|
|
164
mod/quiz/tests/privacy_legacy_quizaccess_polyfill_test.php
Normal file
164
mod/quiz/tests/privacy_legacy_quizaccess_polyfill_test.php
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for the privacy legacy polyfill for quiz access rules.
|
||||||
|
*
|
||||||
|
* @package mod_quiz
|
||||||
|
* @category test
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
global $CFG;
|
||||||
|
require_once($CFG->dirroot . '/mod/quiz/attemptlib.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for the privacy legacy polyfill for quiz access rules.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class core_privacy_legacy_quizaccess_polyfill_test extends advanced_testcase {
|
||||||
|
/**
|
||||||
|
* Test that the core_quizaccess\privacy\legacy_polyfill works and that the static _export_quizaccess_user_data can
|
||||||
|
* be called.
|
||||||
|
*/
|
||||||
|
public function test_export_quizaccess_user_data() {
|
||||||
|
$quiz = $this->createMock(quiz::class);
|
||||||
|
$user = (object) [];
|
||||||
|
$returnvalue = (object) [];
|
||||||
|
|
||||||
|
$mock = $this->createMock(test_privacy_legacy_quizaccess_polyfill_mock_wrapper::class);
|
||||||
|
$mock->expects($this->once())
|
||||||
|
->method('get_return_value')
|
||||||
|
->with('_export_quizaccess_user_data', [$quiz, $user])
|
||||||
|
->willReturn($returnvalue);
|
||||||
|
|
||||||
|
test_privacy_legacy_quizaccess_polyfill_provider::$mock = $mock;
|
||||||
|
$result = test_privacy_legacy_quizaccess_polyfill_provider::export_quizaccess_user_data($quiz, $user);
|
||||||
|
$this->assertSame($returnvalue, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the _delete_quizaccess_for_context shim.
|
||||||
|
*/
|
||||||
|
public function test_delete_quizaccess_for_context() {
|
||||||
|
$context = context_system::instance();
|
||||||
|
|
||||||
|
$quiz = $this->createMock(quiz::class);
|
||||||
|
|
||||||
|
$mock = $this->createMock(test_privacy_legacy_quizaccess_polyfill_mock_wrapper::class);
|
||||||
|
$mock->expects($this->once())
|
||||||
|
->method('get_return_value')
|
||||||
|
->with('_delete_quizaccess_data_for_all_users_in_context', [$quiz]);
|
||||||
|
|
||||||
|
test_privacy_legacy_quizaccess_polyfill_provider::$mock = $mock;
|
||||||
|
test_privacy_legacy_quizaccess_polyfill_provider::delete_quizaccess_data_for_all_users_in_context($quiz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the _delete_quizaccess_for_context shim.
|
||||||
|
*/
|
||||||
|
public function test_delete_quizaccess_for_user() {
|
||||||
|
$context = context_system::instance();
|
||||||
|
|
||||||
|
$quiz = $this->createMock(quiz::class);
|
||||||
|
$user = (object) [];
|
||||||
|
|
||||||
|
$mock = $this->createMock(test_privacy_legacy_quizaccess_polyfill_mock_wrapper::class);
|
||||||
|
$mock->expects($this->once())
|
||||||
|
->method('get_return_value')
|
||||||
|
->with('_delete_quizaccess_data_for_user', [$quiz, $user]);
|
||||||
|
|
||||||
|
test_privacy_legacy_quizaccess_polyfill_provider::$mock = $mock;
|
||||||
|
test_privacy_legacy_quizaccess_polyfill_provider::delete_quizaccess_data_for_user($quiz, $user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legacy polyfill test class for the quizaccess_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class test_privacy_legacy_quizaccess_polyfill_provider implements
|
||||||
|
\core_privacy\local\metadata\provider,
|
||||||
|
\mod_quiz\privacy\quizaccess_provider {
|
||||||
|
|
||||||
|
use \mod_quiz\privacy\legacy_quizaccess_polyfill;
|
||||||
|
use \core_privacy\local\legacy_polyfill;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var test_privacy_legacy_quizaccess_polyfill_provider $mock.
|
||||||
|
*/
|
||||||
|
public static $mock = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export all user data for the quizaccess plugin.
|
||||||
|
*
|
||||||
|
* @param \quiz $quiz
|
||||||
|
* @param \stdClass $user
|
||||||
|
*/
|
||||||
|
protected static function _export_quizaccess_user_data($quiz, $user) {
|
||||||
|
return static::$mock->get_return_value(__FUNCTION__, func_get_args());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes all user data for the given context.
|
||||||
|
*
|
||||||
|
* @param \quiz $quiz
|
||||||
|
*/
|
||||||
|
protected static function _delete_quizaccess_data_for_all_users_in_context($quiz) {
|
||||||
|
static::$mock->get_return_value(__FUNCTION__, func_get_args());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete personal data for the given user and context.
|
||||||
|
*
|
||||||
|
* @param \quiz $quiz The quiz being deleted
|
||||||
|
* @param \stdClass $user The user to export data for
|
||||||
|
*/
|
||||||
|
protected static function _delete_quizaccess_data_for_user($quiz, $user) {
|
||||||
|
static::$mock->get_return_value(__FUNCTION__, func_get_args());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns metadata about this plugin.
|
||||||
|
*
|
||||||
|
* @param \core_privacy\local\metadata\collection $collection The initialised collection to add items to.
|
||||||
|
* @return \core_privacy\local\metadata\collection A listing of user data stored through this system.
|
||||||
|
*/
|
||||||
|
protected static function _get_metadata(\core_privacy\local\metadata\collection $collection) {
|
||||||
|
return $collection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called inside the polyfill methods in the test polyfill provider, allowing us to ensure these are called with correct params.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class test_privacy_legacy_quizaccess_polyfill_mock_wrapper {
|
||||||
|
/**
|
||||||
|
* Get the return value for the specified item.
|
||||||
|
*/
|
||||||
|
public function get_return_value() {
|
||||||
|
}
|
||||||
|
}
|
279
mod/quiz/tests/privacy_provider_test.php
Normal file
279
mod/quiz/tests/privacy_provider_test.php
Normal file
|
@ -0,0 +1,279 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy provider tests.
|
||||||
|
*
|
||||||
|
* @package mod_quiz
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
use core_privacy\local\metadata\collection;
|
||||||
|
use core_privacy\local\request\deletion_criteria;
|
||||||
|
use core_privacy\local\request\writer;
|
||||||
|
use mod_quiz\privacy\provider;
|
||||||
|
use mod_quiz\privacy\helper;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
global $CFG;
|
||||||
|
require_once($CFG->dirroot . '/question/tests/privacy_helper.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy provider tests class.
|
||||||
|
*
|
||||||
|
* @package mod_quiz
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class mod_quiz_privacy_provider_testcase extends \core_privacy\tests\provider_testcase {
|
||||||
|
|
||||||
|
use core_question_privacy_helper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that a user who has no data gets no contexts
|
||||||
|
*/
|
||||||
|
public function test_get_contexts_for_userid_no_data() {
|
||||||
|
global $USER;
|
||||||
|
$this->resetAfterTest();
|
||||||
|
$this->setAdminUser();
|
||||||
|
|
||||||
|
$contextlist = provider::get_contexts_for_userid($USER->id);
|
||||||
|
$this->assertEmpty($contextlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The export function should handle an empty contextlist properly.
|
||||||
|
*/
|
||||||
|
public function test_export_user_data_no_data() {
|
||||||
|
global $USER;
|
||||||
|
$this->resetAfterTest();
|
||||||
|
$this->setAdminUser();
|
||||||
|
|
||||||
|
$approvedcontextlist = new \core_privacy\tests\request\approved_contextlist(
|
||||||
|
\core_user::get_user($USER->id),
|
||||||
|
'mod_quiz',
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
provider::export_user_data($approvedcontextlist);
|
||||||
|
$this->assertDebuggingNotCalled();
|
||||||
|
|
||||||
|
// No data should have been exported.
|
||||||
|
$writer = \core_privacy\local\request\writer::with_context(\context_system::instance());
|
||||||
|
$this->assertFalse($writer->has_any_data_in_any_context());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The delete function should handle an empty contextlist properly.
|
||||||
|
*/
|
||||||
|
public function test_delete_data_for_user_no_data() {
|
||||||
|
global $USER;
|
||||||
|
$this->resetAfterTest();
|
||||||
|
$this->setAdminUser();
|
||||||
|
|
||||||
|
$approvedcontextlist = new \core_privacy\tests\request\approved_contextlist(
|
||||||
|
\core_user::get_user($USER->id),
|
||||||
|
'mod_quiz',
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
provider::delete_data_for_user($approvedcontextlist);
|
||||||
|
$this->assertDebuggingNotCalled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export + Delete quiz data for a user who has made a single attempt.
|
||||||
|
*/
|
||||||
|
public function test_user_with_data() {
|
||||||
|
global $DB;
|
||||||
|
$this->resetAfterTest(true);
|
||||||
|
|
||||||
|
// Make a quiz.
|
||||||
|
$course = $this->getDataGenerator()->create_course();
|
||||||
|
$user = $this->getDataGenerator()->create_user();
|
||||||
|
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
|
||||||
|
|
||||||
|
$quiz = $quizgenerator->create_instance([
|
||||||
|
'course' => $course->id,
|
||||||
|
'questionsperpage' => 0,
|
||||||
|
'grade' => 100.0,
|
||||||
|
'sumgrades' => 2,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Create a couple of questions.
|
||||||
|
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||||
|
$cat = $questiongenerator->create_question_category();
|
||||||
|
|
||||||
|
$saq = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
|
||||||
|
quiz_add_quiz_question($saq->id, $quiz);
|
||||||
|
$numq = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
|
||||||
|
quiz_add_quiz_question($numq->id, $quiz);
|
||||||
|
|
||||||
|
// Run as the user and make an attempt on the quiz.
|
||||||
|
$this->setUser($user);
|
||||||
|
$starttime = time();
|
||||||
|
$quizobj = quiz::create($quiz->id, $user->id);
|
||||||
|
$context = $quizobj->get_context();
|
||||||
|
|
||||||
|
$quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
|
||||||
|
$quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
|
||||||
|
|
||||||
|
// Start the attempt.
|
||||||
|
$attempt = quiz_create_attempt($quizobj, 1, false, $starttime, false, $user->id);
|
||||||
|
quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $starttime);
|
||||||
|
quiz_attempt_save_started($quizobj, $quba, $attempt);
|
||||||
|
|
||||||
|
// Answer the questions.
|
||||||
|
$attemptobj = quiz_attempt::create($attempt->id);
|
||||||
|
|
||||||
|
$tosubmit = [
|
||||||
|
1 => ['answer' => 'frog'],
|
||||||
|
2 => ['answer' => '3.14'],
|
||||||
|
];
|
||||||
|
|
||||||
|
$attemptobj->process_submitted_actions($starttime, false, $tosubmit);
|
||||||
|
|
||||||
|
// Finish the attempt.
|
||||||
|
$attemptobj = quiz_attempt::create($attempt->id);
|
||||||
|
$this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
|
||||||
|
$attemptobj->process_finish($starttime, false);
|
||||||
|
|
||||||
|
// Fetch the contexts -only one context should be returned.
|
||||||
|
$this->setUser();
|
||||||
|
$contextlist = provider::get_contexts_for_userid($user->id);
|
||||||
|
$this->assertCount(1, $contextlist);
|
||||||
|
$this->assertEquals($context, $contextlist->current());
|
||||||
|
|
||||||
|
// Perform the export and check the data.
|
||||||
|
$this->setUser($user);
|
||||||
|
$approvedcontextlist = new \core_privacy\tests\request\approved_contextlist(
|
||||||
|
\core_user::get_user($user->id),
|
||||||
|
'mod_quiz',
|
||||||
|
$contextlist->get_contextids()
|
||||||
|
);
|
||||||
|
provider::export_user_data($approvedcontextlist);
|
||||||
|
|
||||||
|
// Ensure that the quiz data was exported correctly.
|
||||||
|
$writer = writer::with_context($context);
|
||||||
|
$this->assertTrue($writer->has_any_data());
|
||||||
|
|
||||||
|
$quizdata = $writer->get_data([]);
|
||||||
|
$this->assertEquals($quizobj->get_quiz_name(), $quizdata->name);
|
||||||
|
|
||||||
|
// Every module has an intro.
|
||||||
|
$this->assertTrue(isset($quizdata->intro));
|
||||||
|
|
||||||
|
// Fetch the attempt data.
|
||||||
|
$attemptsubcontext = [
|
||||||
|
get_string('attempts', 'mod_quiz'),
|
||||||
|
$attempt->attempt,
|
||||||
|
];
|
||||||
|
$attemptdata = writer::with_context($context)->get_data($attemptsubcontext);
|
||||||
|
|
||||||
|
$attempt = $attemptobj->get_attempt();
|
||||||
|
$this->assertTrue(isset($attemptdata->state));
|
||||||
|
$this->assertEquals(\quiz_attempt::state_name($attemptobj->get_state()), $attemptdata->state);
|
||||||
|
$this->assertTrue(isset($attemptdata->timestart));
|
||||||
|
$this->assertTrue(isset($attemptdata->timefinish));
|
||||||
|
$this->assertTrue(isset($attemptdata->timemodified));
|
||||||
|
$this->assertFalse(isset($attemptdata->timemodifiedoffline));
|
||||||
|
$this->assertFalse(isset($attemptdata->timecheckstate));
|
||||||
|
|
||||||
|
$this->assertTrue(isset($attemptdata->grade));
|
||||||
|
$this->assertEquals(100.00, $attemptdata->grade->grade);
|
||||||
|
|
||||||
|
// Check that the exported question attempts are correct.
|
||||||
|
$attemptsubcontext = helper::get_quiz_attempt_subcontext($attemptobj->get_attempt(), $user);
|
||||||
|
$this->assert_question_attempt_exported(
|
||||||
|
$context,
|
||||||
|
$attemptsubcontext,
|
||||||
|
\question_engine::load_questions_usage_by_activity($attemptobj->get_uniqueid()),
|
||||||
|
quiz_get_review_options($quiz, $attemptobj->get_attempt(), $context),
|
||||||
|
$user
|
||||||
|
);
|
||||||
|
|
||||||
|
// Delete the data and check it is removed.
|
||||||
|
$this->setUser();
|
||||||
|
provider::delete_data_for_user($approvedcontextlist);
|
||||||
|
$this->expectException(\dml_missing_record_exception::class);
|
||||||
|
\quiz_attempt::create($attemptobj->get_quizid());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export + Delete quiz data for a user who has made a single attempt.
|
||||||
|
*/
|
||||||
|
public function test_user_with_preview() {
|
||||||
|
global $DB;
|
||||||
|
$this->resetAfterTest(true);
|
||||||
|
|
||||||
|
// Make a quiz.
|
||||||
|
$course = $this->getDataGenerator()->create_course();
|
||||||
|
$user = $this->getDataGenerator()->create_user();
|
||||||
|
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
|
||||||
|
|
||||||
|
$quiz = $quizgenerator->create_instance([
|
||||||
|
'course' => $course->id,
|
||||||
|
'questionsperpage' => 0,
|
||||||
|
'grade' => 100.0,
|
||||||
|
'sumgrades' => 2,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Create a couple of questions.
|
||||||
|
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||||
|
$cat = $questiongenerator->create_question_category();
|
||||||
|
|
||||||
|
$saq = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
|
||||||
|
quiz_add_quiz_question($saq->id, $quiz);
|
||||||
|
$numq = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
|
||||||
|
quiz_add_quiz_question($numq->id, $quiz);
|
||||||
|
|
||||||
|
// Run as the user and make an attempt on the quiz.
|
||||||
|
$this->setUser($user);
|
||||||
|
$starttime = time();
|
||||||
|
$quizobj = quiz::create($quiz->id, $user->id);
|
||||||
|
$context = $quizobj->get_context();
|
||||||
|
|
||||||
|
$quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
|
||||||
|
$quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
|
||||||
|
|
||||||
|
// Start the attempt.
|
||||||
|
$attempt = quiz_create_attempt($quizobj, 1, false, $starttime, true, $user->id);
|
||||||
|
quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $starttime);
|
||||||
|
quiz_attempt_save_started($quizobj, $quba, $attempt);
|
||||||
|
|
||||||
|
// Answer the questions.
|
||||||
|
$attemptobj = quiz_attempt::create($attempt->id);
|
||||||
|
|
||||||
|
$tosubmit = [
|
||||||
|
1 => ['answer' => 'frog'],
|
||||||
|
2 => ['answer' => '3.14'],
|
||||||
|
];
|
||||||
|
|
||||||
|
$attemptobj->process_submitted_actions($starttime, false, $tosubmit);
|
||||||
|
|
||||||
|
// Finish the attempt.
|
||||||
|
$attemptobj = quiz_attempt::create($attempt->id);
|
||||||
|
$this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
|
||||||
|
$attemptobj->process_finish($starttime, false);
|
||||||
|
|
||||||
|
// Fetch the contexts - no context should be returned.
|
||||||
|
$this->setUser();
|
||||||
|
$contextlist = provider::get_contexts_for_userid($user->id);
|
||||||
|
$this->assertCount(0, $contextlist);
|
||||||
|
}
|
||||||
|
}
|
|
@ -73,6 +73,8 @@ class content_writer implements \core_privacy\local\request\content_writer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether any data has been exported at all within the current context.
|
* Whether any data has been exported at all within the current context.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function has_any_data() {
|
public function has_any_data() {
|
||||||
$hasdata = !empty($this->data->{$this->context->id});
|
$hasdata = !empty($this->data->{$this->context->id});
|
||||||
|
@ -96,6 +98,32 @@ class content_writer implements \core_privacy\local\request\content_writer {
|
||||||
return $hasanydata;
|
return $hasanydata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether any data has been exported for any context.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function has_any_data_in_any_context() {
|
||||||
|
$checkfordata = function($location) {
|
||||||
|
foreach ($location as $context => $data) {
|
||||||
|
if (!empty($data)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
$hasanydata = $checkfordata($this->data);
|
||||||
|
$hasanydata = $hasanydata || $checkfordata($this->relateddata);
|
||||||
|
$hasanydata = $hasanydata || $checkfordata($this->metadata);
|
||||||
|
$hasanydata = $hasanydata || $checkfordata($this->files);
|
||||||
|
$hasanydata = $hasanydata || $checkfordata($this->customfiles);
|
||||||
|
$hasanydata = $hasanydata || $checkfordata($this->userprefs);
|
||||||
|
|
||||||
|
return $hasanydata;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for the content writer.
|
* Constructor for the content writer.
|
||||||
*
|
*
|
||||||
|
|
|
@ -40,6 +40,14 @@ use \core_privacy\local\request\writer;
|
||||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
*/
|
*/
|
||||||
class writer_test extends advanced_testcase {
|
class writer_test extends advanced_testcase {
|
||||||
|
/**
|
||||||
|
* Ensure that the writer is cleared away as appropriate after each
|
||||||
|
* test.
|
||||||
|
*/
|
||||||
|
public function tearDown() {
|
||||||
|
writer::reset();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that calling with_context multiple times will return the same write instance.
|
* Test that calling with_context multiple times will return the same write instance.
|
||||||
*/
|
*/
|
||||||
|
|
46
question/behaviour/adaptive/classes/privacy/provider.php
Normal file
46
question/behaviour/adaptive/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qbehaviour_adaptive.
|
||||||
|
*
|
||||||
|
* @package qbehaviour_adaptive
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qbehaviour_adaptive\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qbehaviour_adaptive implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,7 @@ $string['gradingdetailswithpenalty'] = 'Marks for this submission: {$a->raw}/{$a
|
||||||
$string['gradingdetailswithtotalpenalty'] = 'Marks for this submission: {$a->raw}/{$a->max}. This submission attracted a penalty of {$a->penalty}. Total penalties so far: {$a->totalpenalty}.';
|
$string['gradingdetailswithtotalpenalty'] = 'Marks for this submission: {$a->raw}/{$a->max}. This submission attracted a penalty of {$a->penalty}. Total penalties so far: {$a->totalpenalty}.';
|
||||||
$string['notcomplete'] = 'Not complete';
|
$string['notcomplete'] = 'Not complete';
|
||||||
$string['pluginname'] = 'Adaptive mode';
|
$string['pluginname'] = 'Adaptive mode';
|
||||||
|
$string['privacy:metadata'] = 'The Adaptive mode question behaviour plugin does not store any personal data.';
|
||||||
|
|
||||||
// Old strings these are currently only used in the unit tests, to verify that the new
|
// Old strings these are currently only used in the unit tests, to verify that the new
|
||||||
// strings give the same results as the old strings.
|
// strings give the same results as the old strings.
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qbehaviour_adaptivenopenalty.
|
||||||
|
*
|
||||||
|
* @package qbehaviour_adaptivenopenalty
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qbehaviour_adaptivenopenalty\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qbehaviour_adaptivenopenalty implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,3 +24,4 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$string['pluginname'] = 'Adaptive mode (no penalties)';
|
$string['pluginname'] = 'Adaptive mode (no penalties)';
|
||||||
|
$string['privacy:metadata'] = 'The Adaptive mode (no penalties) question behaviour plugin does not store any personal data.';
|
||||||
|
|
46
question/behaviour/deferredcbm/classes/privacy/provider.php
Normal file
46
question/behaviour/deferredcbm/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qbehaviour_deferredcbm.
|
||||||
|
*
|
||||||
|
* @package qbehaviour_deferredcbm
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qbehaviour_deferredcbm\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qbehaviour_deferredcbm implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -66,6 +66,7 @@ $string['howcertainareyou'] = 'Certainty{$a->help}: {$a->choices}';
|
||||||
$string['noquestions'] = 'No responses';
|
$string['noquestions'] = 'No responses';
|
||||||
$string['overconfident'] = 'over-confident';
|
$string['overconfident'] = 'over-confident';
|
||||||
$string['pluginname'] = 'Deferred feedback with CBM';
|
$string['pluginname'] = 'Deferred feedback with CBM';
|
||||||
|
$string['privacy:metadata'] = 'The Deferred feedback with CBM question behaviour plugin does not store any personal data.';
|
||||||
$string['slightlyoverconfident'] = 'a bit over-confident';
|
$string['slightlyoverconfident'] = 'a bit over-confident';
|
||||||
$string['slightlyunderconfident'] = 'a bit under-confident';
|
$string['slightlyunderconfident'] = 'a bit under-confident';
|
||||||
$string['underconfident'] = 'under-confident';
|
$string['underconfident'] = 'under-confident';
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qbehaviour_deferredfeedback.
|
||||||
|
*
|
||||||
|
* @package qbehaviour_deferredfeedback
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qbehaviour_deferredfeedback\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qbehaviour_deferredfeedback implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,3 +24,4 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$string['pluginname'] = 'Deferred feedback';
|
$string['pluginname'] = 'Deferred feedback';
|
||||||
|
$string['privacy:metadata'] = 'The Deferred feedback behaviour plugin does not store any personal data.';
|
||||||
|
|
46
question/behaviour/immediatecbm/classes/privacy/provider.php
Normal file
46
question/behaviour/immediatecbm/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qbehaviour_immediatecbm.
|
||||||
|
*
|
||||||
|
* @package qbehaviour_immediatecbm
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qbehaviour_immediatecbm\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qbehaviour_immediatecbm implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,3 +25,4 @@
|
||||||
|
|
||||||
$string['pleaseselectacertainty'] = 'Please select a certainty.';
|
$string['pleaseselectacertainty'] = 'Please select a certainty.';
|
||||||
$string['pluginname'] = 'Immediate feedback with CBM';
|
$string['pluginname'] = 'Immediate feedback with CBM';
|
||||||
|
$string['privacy:metadata'] = 'The Immediate feedback with CBM question behaviour plugin does not store any personal data.';
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qbehaviour_immediatefeedback.
|
||||||
|
*
|
||||||
|
* @package qbehaviour_immediatefeedback
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qbehaviour_immediatefeedback\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qbehaviour_immediatefeedback implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,3 +25,4 @@
|
||||||
|
|
||||||
$string['notcomplete'] = 'Not complete';
|
$string['notcomplete'] = 'Not complete';
|
||||||
$string['pluginname'] = 'Immediate feedback';
|
$string['pluginname'] = 'Immediate feedback';
|
||||||
|
$string['privacy:metadata'] = 'The Immediate feedback question behaviour plugin does not store any personal data.';
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qbehaviour_informationitem.
|
||||||
|
*
|
||||||
|
* @package qbehaviour_informationitem
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qbehaviour_informationitem\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qbehaviour_informationitem implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,4 +24,5 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$string['pluginname'] = 'Behaviour for information items';
|
$string['pluginname'] = 'Behaviour for information items';
|
||||||
$string['seen'] = 'Seen';
|
$string['privacy:metadata'] = 'The Information items question behaviour plugin does not store any personal data.';
|
||||||
|
$string['seen'] = 'Seen';
|
||||||
|
|
46
question/behaviour/interactive/classes/privacy/provider.php
Normal file
46
question/behaviour/interactive/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qbehaviour_interactive.
|
||||||
|
*
|
||||||
|
* @package qbehaviour_interactive
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qbehaviour_interactive\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qbehaviour_interactive implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,5 +24,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$string['pluginname'] = 'Interactive with multiple tries';
|
$string['pluginname'] = 'Interactive with multiple tries';
|
||||||
|
$string['privacy:metadata'] = 'The Interactive with multiple tries question behaviour plugin does not store any personal data.';
|
||||||
$string['triesremaining'] = 'Tries remaining: {$a}';
|
$string['triesremaining'] = 'Tries remaining: {$a}';
|
||||||
$string['tryagain'] = 'Try again';
|
$string['tryagain'] = 'Try again';
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qbehaviour_interactivecountback.
|
||||||
|
*
|
||||||
|
* @package qbehaviour_interactivecountback
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qbehaviour_interactivecountback\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qbehaviour_interactivecountback implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,3 +24,4 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$string['pluginname'] = 'Interactive with multiple tries (credit for earlier tries)';
|
$string['pluginname'] = 'Interactive with multiple tries (credit for earlier tries)';
|
||||||
|
$string['privacy:metadata'] = 'The Interactive with multiple tries (credit for earlier tries) question behaviour plugin does not store any personal data.';
|
||||||
|
|
46
question/behaviour/manualgraded/classes/privacy/provider.php
Normal file
46
question/behaviour/manualgraded/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qbehaviour_manualgraded.
|
||||||
|
*
|
||||||
|
* @package qbehaviour_manualgraded
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qbehaviour_manualgraded\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qbehaviour_manualgraded implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,3 +24,4 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$string['pluginname'] = 'Manually graded';
|
$string['pluginname'] = 'Manually graded';
|
||||||
|
$string['privacy:metadata'] = 'The Manually graded question behaviour plugin does not store any personal data.';
|
||||||
|
|
46
question/behaviour/missing/classes/privacy/provider.php
Normal file
46
question/behaviour/missing/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qbehaviour_missing.
|
||||||
|
*
|
||||||
|
* @package qbehaviour_missing
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qbehaviour_missing\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qbehaviour_missing implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,3 +25,4 @@
|
||||||
|
|
||||||
$string['pluginname'] = 'Missing behaviour';
|
$string['pluginname'] = 'Missing behaviour';
|
||||||
$string['questionusedunknownmodel'] = 'This question was attempted with a behaviour that is not currently available. The question is being displayed as well as possible, but some parts may be missing or wrong.';
|
$string['questionusedunknownmodel'] = 'This question was attempted with a behaviour that is not currently available. The question is being displayed as well as possible, but some parts may be missing or wrong.';
|
||||||
|
$string['privacy:metadata'] = 'The Missing question behaviour plugin does not store any personal data.';
|
||||||
|
|
467
question/classes/privacy/provider.php
Normal file
467
question/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,467 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for core_question.
|
||||||
|
*
|
||||||
|
* @package core_question
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace core_question\privacy;
|
||||||
|
|
||||||
|
use \core_privacy\local\metadata\collection;
|
||||||
|
use \core_privacy\local\request\writer;
|
||||||
|
use \core_privacy\local\request\transform;
|
||||||
|
use \core_privacy\local\request\contextlist;
|
||||||
|
use \core_privacy\local\request\approved_contextlist;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
require_once($CFG->libdir . '/questionlib.php');
|
||||||
|
require_once($CFG->dirroot . '/question/format.php');
|
||||||
|
require_once($CFG->dirroot . '/question/editlib.php');
|
||||||
|
require_once($CFG->dirroot . '/question/engine/datalib.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for core_question.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements
|
||||||
|
// This component has data.
|
||||||
|
// We need to return all question information where the user is
|
||||||
|
// listed in either the question.createdby or question.modifiedby fields.
|
||||||
|
// We may also need to fetch this informtion from individual plugins in some cases.
|
||||||
|
// e.g. to fetch the full and other question-specific meta-data.
|
||||||
|
\core_privacy\local\metadata\provider,
|
||||||
|
|
||||||
|
// This is a subsysytem which provides information to core.
|
||||||
|
\core_privacy\local\request\subsystem\provider,
|
||||||
|
|
||||||
|
// This is a subsysytem which provides information to plugins.
|
||||||
|
\core_privacy\local\request\subsystem\plugin_provider
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describe the types of data stored by the question subsystem.
|
||||||
|
*
|
||||||
|
* @param collection $items The collection to add metadata to.
|
||||||
|
* @return collection The array of metadata
|
||||||
|
*/
|
||||||
|
public static function get_metadata(collection $items) : collection {
|
||||||
|
// Other tables link against it.
|
||||||
|
|
||||||
|
// The 'question_usages' table does not contain any user data.
|
||||||
|
// The table links the but doesn't store itself.
|
||||||
|
|
||||||
|
// The 'question_attempts' table contains data about question attempts.
|
||||||
|
// It does not contain any user ids - these are stored by the caller.
|
||||||
|
$items->add_database_table('question_attempts', [
|
||||||
|
'flagged' => 'privacy:metadata:database:question_attempts:flagged',
|
||||||
|
'responsesummary' => 'privacy:metadata:database:question_attempts:responsesummary',
|
||||||
|
'timemodified' => 'privacy:metadata:database:question_attempts:timemodified',
|
||||||
|
], 'privacy:metadata:database:question_attempts');;
|
||||||
|
|
||||||
|
// The 'question_attempt_steps' table contains data about changes to the state of a question attempt.
|
||||||
|
$items->add_database_table('question_attempt_steps', [
|
||||||
|
'state' => 'privacy:metadata:database:question_attempt_steps:state',
|
||||||
|
'timecreated' => 'privacy:metadata:database:question_attempt_steps:timecreated',
|
||||||
|
'fraction' => 'privacy:metadata:database:question_attempt_steps:fraction',
|
||||||
|
'userid' => 'privacy:metadata:database:question_attempt_steps:userid',
|
||||||
|
], 'privacy:metadata:database:question_attempt_steps');
|
||||||
|
|
||||||
|
// The 'question_attempt_step_data' table contains specific all metadata for each state.
|
||||||
|
$items->add_database_table('question_attempt_step_data', [
|
||||||
|
'name' => 'privacy:metadata:database:question_attempt_step_data:name',
|
||||||
|
'value' => 'privacy:metadata:database:question_attempt_step_data:value',
|
||||||
|
], 'privacy:metadata:database:question_attempt_step_data');
|
||||||
|
|
||||||
|
// These are all part of the set of the question definition
|
||||||
|
// The 'question' table is used to store instances of each question.
|
||||||
|
// It contains a createdby and modifiedby which related to specific users.
|
||||||
|
$items->add_database_table('question', [
|
||||||
|
'name' => 'privacy:metadata:database:question:name',
|
||||||
|
'questiontext' => 'privacy:metadata:database:question:questiontext',
|
||||||
|
'generalfeedback' => 'privacy:metadata:database:question:generalfeedback',
|
||||||
|
'timecreated' => 'privacy:metadata:database:question:timecreated',
|
||||||
|
'timemodified' => 'privacy:metadata:database:question:timemodified',
|
||||||
|
'createdby' => 'privacy:metadata:database:question:createdby',
|
||||||
|
'modifiedby' => 'privacy:metadata:database:question:modifiedby',
|
||||||
|
], 'privacy:metadata:database:question');
|
||||||
|
|
||||||
|
// The 'question_answers' table is used to store the set of answers, with appropriate feedback for each question.
|
||||||
|
// It does not contain user data.
|
||||||
|
|
||||||
|
// The 'question_hints' table is used to store hints about the correct answer for a question.
|
||||||
|
// It does not contain user data.
|
||||||
|
|
||||||
|
// The 'question_categories' table contains structural information about how questions are presented in the UI.
|
||||||
|
// It does not contain user data.
|
||||||
|
|
||||||
|
// The 'question_statistics' table contains aggregated statistics about responses.
|
||||||
|
// It does not contain any identifiable user data.
|
||||||
|
|
||||||
|
// The question subsystem makes use of the qtype, qformat, and qbehaviour plugin types.
|
||||||
|
$items->add_plugintype_link('qtype', [], 'privacy:metadata:link:qtype');
|
||||||
|
$items->add_plugintype_link('qformat', [], 'privacy:metadata:link:qformat');
|
||||||
|
$items->add_plugintype_link('qbehaviour', [], 'privacy:metadata:link:qbehaviour');
|
||||||
|
|
||||||
|
return $items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export the data for all question attempts on this question usage.
|
||||||
|
*
|
||||||
|
* Where a user is the owner of the usage, then the full detail of that usage will be included.
|
||||||
|
* Where a user has been involved in the usage, but it is not their own usage, then only their specific
|
||||||
|
* involvement will be exported.
|
||||||
|
*
|
||||||
|
* @param int $userid The userid to export.
|
||||||
|
* @param \context $context The context that the question was used within.
|
||||||
|
* @param array $usagecontext The subcontext of this usage.
|
||||||
|
* @param int $usage The question usage ID.
|
||||||
|
* @param \question_display_options $options The display options used for formatting.
|
||||||
|
* @param bool $isowner Whether the user being exported is the user who used the question.
|
||||||
|
*/
|
||||||
|
public static function export_question_usage(
|
||||||
|
int $userid,
|
||||||
|
\context $context,
|
||||||
|
array $usagecontext,
|
||||||
|
int $usage,
|
||||||
|
\question_display_options $options,
|
||||||
|
bool $isowner
|
||||||
|
) {
|
||||||
|
// Determine the questions in this usage.
|
||||||
|
$quba = \question_engine::load_questions_usage_by_activity($usage);
|
||||||
|
|
||||||
|
$basepath = $usagecontext;
|
||||||
|
$questionscontext = array_merge($usagecontext, [
|
||||||
|
get_string('questions', 'core_question'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
foreach ($quba->get_attempt_iterator() as $qa) {
|
||||||
|
$question = $qa->get_question();
|
||||||
|
$slotno = $qa->get_slot();
|
||||||
|
$questionnocontext = array_merge($questionscontext, [$slotno]);
|
||||||
|
|
||||||
|
if ($isowner) {
|
||||||
|
// This user is the overal owner of the question attempt and all data wil therefore be exported.
|
||||||
|
//
|
||||||
|
// Respect _some_ of the question_display_options to ensure that they don't have access to
|
||||||
|
// generalfeedback and mark if the display options prevent this.
|
||||||
|
// This is defensible because they can submit questions without completing a quiz and perform an SAR to
|
||||||
|
// get prior access to the feedback and mark to improve upon it.
|
||||||
|
// Export the response.
|
||||||
|
$data = (object) [
|
||||||
|
'name' => $question->name,
|
||||||
|
'question' => $qa->get_question_summary(),
|
||||||
|
'answer' => $qa->get_response_summary(),
|
||||||
|
'timemodified' => transform::datetime($qa->timemodified),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($options->marks >= \question_display_options::MARK_AND_MAX) {
|
||||||
|
$data->mark = $qa->format_mark($options->markdp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($options->flags != \question_display_options::HIDDEN) {
|
||||||
|
$data->flagged = transform::yesno($qa->is_flagged());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($options->generalfeedback != \question_display_options::HIDDEN) {
|
||||||
|
$data->generalfeedback = $question->format_generalfeedback($qa);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($options->manualcomment != \question_display_options::HIDDEN) {
|
||||||
|
$behaviour = $qa->get_behaviour();
|
||||||
|
if ($qa->has_manual_comment()) {
|
||||||
|
// Note - the export of the step data will ensure that the files are exported.
|
||||||
|
// No need to do it again here.
|
||||||
|
list($comment, $commentformat, $step) = $qa->get_manual_comment();
|
||||||
|
|
||||||
|
$comment = writer::with_context($context)
|
||||||
|
->rewrite_pluginfile_urls(
|
||||||
|
$questionnocontext,
|
||||||
|
'question',
|
||||||
|
'response_bf_comment',
|
||||||
|
$step->get_id(),
|
||||||
|
$comment
|
||||||
|
);
|
||||||
|
$data->comment = $behaviour->format_comment($comment, $commentformat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writer::with_context($context)
|
||||||
|
->export_data($questionnocontext, $data);
|
||||||
|
|
||||||
|
// Export the step data.
|
||||||
|
static::export_question_attempt_steps($userid, $context, $questionnocontext, $qa, $options, $isowner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export the data for each step transition for each question in each question attempt.
|
||||||
|
*
|
||||||
|
* Where a user is the owner of the usage, then all steps in the question usage will be exported.
|
||||||
|
* Where a user is not the owner, but has been involved in the usage, then only their specific
|
||||||
|
* involvement will be exported.
|
||||||
|
*
|
||||||
|
* @param int $userid The user to export for
|
||||||
|
* @param \context $context The context that the question was used within.
|
||||||
|
* @param array $questionnocontext The subcontext of this question number.
|
||||||
|
* @param \question_attempt $qa The attempt being checked
|
||||||
|
* @param \question_display_options $options The display options used for formatting.
|
||||||
|
* @param bool $isowner Whether the user being exported is the user who used the question.
|
||||||
|
*/
|
||||||
|
public static function export_question_attempt_steps(
|
||||||
|
int $userid,
|
||||||
|
\context $context,
|
||||||
|
array $questionnocontext,
|
||||||
|
\question_attempt $qa,
|
||||||
|
\question_display_options $options,
|
||||||
|
$isowner
|
||||||
|
) {
|
||||||
|
$attemptdata = (object) [
|
||||||
|
'steps' => [],
|
||||||
|
];
|
||||||
|
$stepno = 0;
|
||||||
|
foreach ($qa->get_step_iterator() as $i => $step) {
|
||||||
|
$stepno++;
|
||||||
|
|
||||||
|
if ($isowner || ($step->get_user_id() != $userid)) {
|
||||||
|
// The user is the owner, or the author of the step.
|
||||||
|
|
||||||
|
$restrictedqa = new \question_attempt_with_restricted_history($qa, $i, null);
|
||||||
|
$stepdata = (object) [
|
||||||
|
// Note: Do not include the user here.
|
||||||
|
'time' => transform::datetime($step->get_timecreated()),
|
||||||
|
'action' => $qa->summarise_action($step),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($options->marks >= \question_display_options::MARK_AND_MAX) {
|
||||||
|
$stepdata->mark = $qa->format_fraction_as_mark($step->get_fraction(), $options->markdp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($options->correctness != \question_display_options::HIDDEN) {
|
||||||
|
$stepdata->state = $restrictedqa->get_state_string($options->correctness);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($step->has_behaviour_var('comment')) {
|
||||||
|
$behaviour = $qa->get_behaviour();
|
||||||
|
$comment = $step->get_behaviour_var('comment');
|
||||||
|
$commentformat = $step->get_behaviour_var('commentformat');
|
||||||
|
|
||||||
|
if (empty(trim($comment))) {
|
||||||
|
// Skip empty comments.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the comment.
|
||||||
|
$comment = writer::with_context($context)
|
||||||
|
->rewrite_pluginfile_urls(
|
||||||
|
$questionnocontext,
|
||||||
|
'question',
|
||||||
|
'response_bf_comment',
|
||||||
|
$step->get_id(),
|
||||||
|
$comment
|
||||||
|
);
|
||||||
|
|
||||||
|
writer::with_context($context)
|
||||||
|
->export_area_files(
|
||||||
|
$questionnocontext,
|
||||||
|
'question',
|
||||||
|
"response_bf_comment",
|
||||||
|
$step->get_id()
|
||||||
|
);
|
||||||
|
|
||||||
|
$stepdata->comment = $behaviour->format_comment($comment, $commentformat);
|
||||||
|
}
|
||||||
|
|
||||||
|
$attemptdata->steps[$stepno] = $stepdata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($attemptdata->steps)) {
|
||||||
|
writer::with_context($context)
|
||||||
|
->export_related_data($questionnocontext, 'steps', $attemptdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of contexts where the specified user has either created, or edited a question.
|
||||||
|
*
|
||||||
|
* To export usage of a question, please call {@link provider::export_question_usage()} from the module which
|
||||||
|
* instantiated the usage of the question.
|
||||||
|
*
|
||||||
|
* @param int $userid The user to search.
|
||||||
|
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
|
||||||
|
*/
|
||||||
|
public static function get_contexts_for_userid(int $userid) : contextlist {
|
||||||
|
$contextlist = new contextlist();
|
||||||
|
|
||||||
|
// A user may have created or updated a question.
|
||||||
|
// Questions are linked against a question category, which has a contextid field.
|
||||||
|
$sql = "SELECT cat.contextid
|
||||||
|
FROM {question} q
|
||||||
|
INNER JOIN {question_categories} cat ON cat.id = q.category
|
||||||
|
WHERE
|
||||||
|
q.createdby = :useridcreated OR
|
||||||
|
q.modifiedby = :useridmodified";
|
||||||
|
$params = [
|
||||||
|
'useridcreated' => $userid,
|
||||||
|
'useridmodified' => $userid,
|
||||||
|
];
|
||||||
|
$contextlist->add_from_sql($sql, $params);
|
||||||
|
|
||||||
|
return $contextlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine related question usages for a user.
|
||||||
|
*
|
||||||
|
* @param string $prefix A unique prefix to add to the table alias
|
||||||
|
* @param string $component The name of the component to fetch usages for.
|
||||||
|
* @param string $joinfield The SQL field name to use in the JOIN ON - e.g. q.usageid
|
||||||
|
* @param int $userid The user to search.
|
||||||
|
* @return \qubaid_join
|
||||||
|
*/
|
||||||
|
public static function get_related_question_usages_for_user(string $prefix, string $component, string $joinfield, int $userid) : \qubaid_join {
|
||||||
|
return new \qubaid_join("
|
||||||
|
JOIN {question_usages} {$prefix}_qu ON {$prefix}_qu.id = {$joinfield}
|
||||||
|
AND {$prefix}_qu.component = :{$prefix}_usagecomponent
|
||||||
|
JOIN {question_attempts} {$prefix}_qa ON {$prefix}_qa.questionusageid = {$prefix}_qu.id
|
||||||
|
JOIN {question_attempt_steps} {$prefix}_qas ON {$prefix}_qas.questionattemptid = {$prefix}_qa.id",
|
||||||
|
"{$prefix}_qu.id",
|
||||||
|
"{$prefix}_qas.userid = :{$prefix}_stepuserid",
|
||||||
|
[
|
||||||
|
"{$prefix}_stepuserid" => $userid,
|
||||||
|
"{$prefix}_usagecomponent" => $component,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export all user data for the specified user, in the specified contexts.
|
||||||
|
*
|
||||||
|
* @param approved_contextlist $contextlist The approved contexts to export information for.
|
||||||
|
*/
|
||||||
|
public static function export_user_data(approved_contextlist $contextlist) {
|
||||||
|
global $CFG, $DB, $SITE;
|
||||||
|
if (empty($contextlist)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the Moodle XML Data format.
|
||||||
|
// It is the only lossless format that we support.
|
||||||
|
$format = "xml";
|
||||||
|
require_once($CFG->dirroot . "/question/format/{$format}/format.php");
|
||||||
|
|
||||||
|
// THe export system needs questions in a particular format.
|
||||||
|
// The easiest way to fetch these is with get_questions_category() which takes the details of a question
|
||||||
|
// category.
|
||||||
|
// We fetch the root question category for each context and the get_questions_category function recurses to
|
||||||
|
// After fetching them, we filter out any not created or modified by the requestor.
|
||||||
|
$user = $contextlist->get_user();
|
||||||
|
$userid = $user->id;
|
||||||
|
|
||||||
|
list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
|
||||||
|
$categories = $DB->get_records_select('question_categories', "contextid {$contextsql} AND parent = 0", $contextparams);
|
||||||
|
|
||||||
|
$classname = "qformat_{$format}";
|
||||||
|
foreach ($categories as $category) {
|
||||||
|
$context = \context::instance_by_id($category->contextid);
|
||||||
|
|
||||||
|
$questions = get_questions_category($category, true);
|
||||||
|
$questions = array_filter($questions, function($question) use ($userid) {
|
||||||
|
return ($question->createdby == $userid) || ($question->modifiedby == $userid);
|
||||||
|
}, ARRAY_FILTER_USE_BOTH);
|
||||||
|
|
||||||
|
if (empty($questions)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$qformat = new $classname();
|
||||||
|
$qformat->setQuestions($questions);
|
||||||
|
|
||||||
|
$qformat->setContexts([$context]);
|
||||||
|
$qformat->setContexttofile(true);
|
||||||
|
|
||||||
|
// We do not know which course this belongs to, and it's not actually used except in error, so use Site.
|
||||||
|
$qformat->setCourse($SITE);
|
||||||
|
$content = '';
|
||||||
|
if ($qformat->exportpreprocess()) {
|
||||||
|
$content = $qformat->exportprocess(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
$subcontext = [
|
||||||
|
get_string('questionbank', 'core_question'),
|
||||||
|
];
|
||||||
|
writer::with_context($context)->export_custom_file($subcontext, 'questions.xml', $content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all data for all users in the specified context.
|
||||||
|
*
|
||||||
|
* @param context $context The specific context to delete data for.
|
||||||
|
*/
|
||||||
|
public static function delete_data_for_all_users_in_context(\context $context) {
|
||||||
|
global $DB;
|
||||||
|
|
||||||
|
// Questions are considered to be 'owned' by the institution, even if they were originally written by a specific
|
||||||
|
// user. They are still exported in the list of a users data, but they are not removed.
|
||||||
|
// The userid is instead anonymised.
|
||||||
|
|
||||||
|
$DB->set_field_select('question', 'createdby', 0,
|
||||||
|
'category IN (SELECT id FROM {question_categories} WHERE contextid = :contextid)',
|
||||||
|
[
|
||||||
|
'contextid' => $context->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$DB->set_field_select('question', 'modifiedby', 0,
|
||||||
|
'category IN (SELECT id FROM {question_categories} WHERE contextid = :contextid)',
|
||||||
|
[
|
||||||
|
'contextid' => $context->id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all user data for the specified user, in the specified contexts.
|
||||||
|
*
|
||||||
|
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
|
||||||
|
*/
|
||||||
|
public static function delete_data_for_user(approved_contextlist $contextlist) {
|
||||||
|
global $DB;
|
||||||
|
|
||||||
|
// Questions are considered to be 'owned' by the institution, even if they were originally written by a specific
|
||||||
|
// user. They are still exported in the list of a users data, but they are not removed.
|
||||||
|
// The userid is instead anonymised.
|
||||||
|
|
||||||
|
list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
|
||||||
|
$contextparams['createdby'] = $contextlist->get_user()->id;
|
||||||
|
$DB->set_field_select('question', 'createdby', 0, "
|
||||||
|
category IN (SELECT id FROM {question_categories} WHERE contextid {$contextsql})
|
||||||
|
AND createdby = :createdby", $contextparams);
|
||||||
|
|
||||||
|
list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
|
||||||
|
$contextparams['modifiedby'] = $contextlist->get_user()->id;
|
||||||
|
$DB->set_field_select('question', 'modifiedby', 0, "
|
||||||
|
category IN (SELECT id FROM {question_categories} WHERE contextid {$contextsql})
|
||||||
|
AND modifiedby = :modifiedby", $contextparams);
|
||||||
|
}
|
||||||
|
}
|
|
@ -793,11 +793,13 @@ class qformat_default {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do the export
|
* Perform the export.
|
||||||
* For most types this should not need to be overrided
|
* For most types this should not need to be overrided.
|
||||||
* @return stored_file
|
*
|
||||||
|
* @param bool $checkcapabilities Whether to check capabilities when exporting the questions.
|
||||||
|
* @return string The content of the export.
|
||||||
*/
|
*/
|
||||||
public function exportprocess() {
|
public function exportprocess($checkcapabilities = true) {
|
||||||
global $CFG, $OUTPUT, $DB, $USER;
|
global $CFG, $OUTPUT, $DB, $USER;
|
||||||
|
|
||||||
// get the questions (from database) in this category
|
// get the questions (from database) in this category
|
||||||
|
@ -857,7 +859,7 @@ class qformat_default {
|
||||||
// export the question displaying message
|
// export the question displaying message
|
||||||
$count++;
|
$count++;
|
||||||
|
|
||||||
if (question_has_capability_on($question, 'view')) {
|
if (!$checkcapabilities || question_has_capability_on($question, 'view')) {
|
||||||
$expout .= $this->writequestion($question, $contextid) . "\n";
|
$expout .= $this->writequestion($question, $contextid) . "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
46
question/format/aiken/classes/privacy/provider.php
Normal file
46
question/format/aiken/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qformat_aiken.
|
||||||
|
*
|
||||||
|
* @package qformat_aiken
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qformat_aiken\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qformat_aiken implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,3 +25,4 @@
|
||||||
$string['pluginname'] = 'Aiken format';
|
$string['pluginname'] = 'Aiken format';
|
||||||
$string['pluginname_help'] = 'This is a simple format for importing multiple choice questions from a text file.';
|
$string['pluginname_help'] = 'This is a simple format for importing multiple choice questions from a text file.';
|
||||||
$string['pluginname_link'] = 'qformat/aiken';
|
$string['pluginname_link'] = 'qformat/aiken';
|
||||||
|
$string['privacy:metadata'] = 'The Aiken question format plugin does not store any personal data.';
|
||||||
|
|
46
question/format/blackboard_six/classes/privacy/provider.php
Normal file
46
question/format/blackboard_six/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qformat_blackboard_six.
|
||||||
|
*
|
||||||
|
* @package qformat_blackboard_six
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qformat_blackboard_six\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qformat_blackboard_six implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,4 +31,5 @@ $string['importedcategory'] = 'Imported category {$a}';
|
||||||
$string['notenoughtsubans'] = 'Unable to import matching question \'{$a}\' because a matching question must comprise at least two questions and three answers.';
|
$string['notenoughtsubans'] = 'Unable to import matching question \'{$a}\' because a matching question must comprise at least two questions and three answers.';
|
||||||
$string['pluginname'] = 'Blackboard';
|
$string['pluginname'] = 'Blackboard';
|
||||||
$string['pluginname_help'] = 'Blackboard format enables questions saved in all Blackboard export formats to be imported via a dat or zip file. For zip files, images import is supported.';
|
$string['pluginname_help'] = 'Blackboard format enables questions saved in all Blackboard export formats to be imported via a dat or zip file. For zip files, images import is supported.';
|
||||||
|
$string['privacy:metadata'] = 'The Blackbard question format plugin does not store any personal data.';
|
||||||
$string['unhandledpresblock'] = 'Unhandled presentation block';
|
$string['unhandledpresblock'] = 'Unhandled presentation block';
|
||||||
|
|
46
question/format/examview/classes/privacy/provider.php
Normal file
46
question/format/examview/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qformat_examview.
|
||||||
|
*
|
||||||
|
* @package qformat_examview
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qformat_examview\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qformat_examview implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,3 +24,4 @@
|
||||||
|
|
||||||
$string['pluginname'] = 'Examview';
|
$string['pluginname'] = 'Examview';
|
||||||
$string['pluginname_help'] = 'Examview format enables the import of questions from Examview 4 XML files. For newer versions of Examview, Blackboard format may be used.';
|
$string['pluginname_help'] = 'Examview format enables the import of questions from Examview 4 XML files. For newer versions of Examview, Blackboard format may be used.';
|
||||||
|
$string['privacy:metadata'] = 'The Examview question format plugin does not store any personal data.';
|
||||||
|
|
46
question/format/gift/classes/privacy/provider.php
Normal file
46
question/format/gift/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qformat_gift.
|
||||||
|
*
|
||||||
|
* @package qformat_gift
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qformat_gift\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qformat_gift implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,3 +34,4 @@ $string['nohandler'] = 'No handler for question type {$a}';
|
||||||
$string['pluginname'] = 'Gift format';
|
$string['pluginname'] = 'Gift format';
|
||||||
$string['pluginname_help'] = 'Gift format enables multiple-choice, true-false, short answer, matching, missing word, numerical and essay questions to be imported or exported via text file.';
|
$string['pluginname_help'] = 'Gift format enables multiple-choice, true-false, short answer, matching, missing word, numerical and essay questions to be imported or exported via text file.';
|
||||||
$string['pluginname_link'] = 'qformat/gift';
|
$string['pluginname_link'] = 'qformat/gift';
|
||||||
|
$string['privacy:metadata'] = 'The Gift question format plugin does not store any personal data.';
|
||||||
|
|
46
question/format/missingword/classes/privacy/provider.php
Normal file
46
question/format/missingword/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qformat_missingword.
|
||||||
|
*
|
||||||
|
* @package qformat_missingword
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qformat_missingword\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qformat_missingword implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,3 +28,4 @@ $string['pluginname_link'] = 'Missing word format';
|
||||||
$string['beginanswernotfound'] = 'Could not find a required "{" character in imported file content.';
|
$string['beginanswernotfound'] = 'Could not find a required "{" character in imported file content.';
|
||||||
$string['endanswernotfound'] = 'Could not find a required "}" character in imported file content.';
|
$string['endanswernotfound'] = 'Could not find a required "}" character in imported file content.';
|
||||||
$string['noanswerfound'] = 'No answers found in question';
|
$string['noanswerfound'] = 'No answers found in question';
|
||||||
|
$string['privacy:metadata'] = 'The Missing word question format plugin does not store any personal data.';
|
||||||
|
|
46
question/format/multianswer/classes/privacy/provider.php
Normal file
46
question/format/multianswer/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qformat_multianswer.
|
||||||
|
*
|
||||||
|
* @package qformat_multianswer
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qformat_multianswer\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qformat_multianswer implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,3 +25,4 @@
|
||||||
$string['pluginname'] = 'Embedded answers (Cloze)';
|
$string['pluginname'] = 'Embedded answers (Cloze)';
|
||||||
$string['pluginname_help'] = 'Embedded answers (Cloze) format enables the import of a passage of text with questions such as multiple-choice and short answer embedded within it.';
|
$string['pluginname_help'] = 'Embedded answers (Cloze) format enables the import of a passage of text with questions such as multiple-choice and short answer embedded within it.';
|
||||||
$string['pluginname_link'] = 'question/type/multianswer';
|
$string['pluginname_link'] = 'question/type/multianswer';
|
||||||
|
$string['privacy:metadata'] = 'The Embedded answers question plugin does not store any personal data.';
|
||||||
|
|
46
question/format/webct/classes/privacy/provider.php
Normal file
46
question/format/webct/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qformat_webct.
|
||||||
|
*
|
||||||
|
* @package qformat_webct
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qformat_webct\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qformat_webct implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ $string['missingquestion'] = 'Missing question label after line {$a}';
|
||||||
$string['pluginname'] = 'WebCT format';
|
$string['pluginname'] = 'WebCT format';
|
||||||
$string['pluginname_help'] = 'WebCT format enables multiple-choice and short answer questions saved in WebCT\'s text-based format to be imported.';
|
$string['pluginname_help'] = 'WebCT format enables multiple-choice and short answer questions saved in WebCT\'s text-based format to be imported.';
|
||||||
$string['pluginname_link'] = 'qformat/webct';
|
$string['pluginname_link'] = 'qformat/webct';
|
||||||
|
$string['privacy:metadata'] = 'The WebCT question format plugin does not store any personal data.';
|
||||||
$string['questionnametoolong'] = 'Question name too long at line {$a} (255 char. max). It has been truncated.';
|
$string['questionnametoolong'] = 'Question name too long at line {$a} (255 char. max). It has been truncated.';
|
||||||
$string['unknowntype'] = 'Unknown question type after line {$a}';
|
$string['unknowntype'] = 'Unknown question type after line {$a}';
|
||||||
$string['warningsdetected'] = '{$a} warning(s) detected';
|
$string['warningsdetected'] = '{$a} warning(s) detected';
|
||||||
|
|
46
question/format/xhtml/classes/privacy/provider.php
Normal file
46
question/format/xhtml/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qformat_xhtml.
|
||||||
|
*
|
||||||
|
* @package qformat_xhtml
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qformat_xhtml\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qformat_xhtml implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,3 +25,4 @@
|
||||||
$string['pluginname'] = 'XHTML format';
|
$string['pluginname'] = 'XHTML format';
|
||||||
$string['pluginname_help'] = 'XHTML format enables all questions in the category to be exported to a single page of strict XHTML for possible use in another application.';
|
$string['pluginname_help'] = 'XHTML format enables all questions in the category to be exported to a single page of strict XHTML for possible use in another application.';
|
||||||
$string['pluginname_link'] = 'qformat/xhtml';
|
$string['pluginname_link'] = 'qformat/xhtml';
|
||||||
|
$string['privacy:metadata'] = 'The XHTML question format plugin does not store any personal data.';
|
||||||
|
|
46
question/format/xml/classes/privacy/provider.php
Normal file
46
question/format/xml/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qformat_xml.
|
||||||
|
*
|
||||||
|
* @package qformat_xml
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qformat_xml\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qformat_xml implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ $string['invalidxml'] = 'Invalid XML file - string expected (use CDATA?)';
|
||||||
$string['pluginname'] = 'Moodle XML format';
|
$string['pluginname'] = 'Moodle XML format';
|
||||||
$string['pluginname_help'] = 'This is a Moodle-specific format for importing and exporting questions.';
|
$string['pluginname_help'] = 'This is a Moodle-specific format for importing and exporting questions.';
|
||||||
$string['pluginname_link'] = 'qformat/xml';
|
$string['pluginname_link'] = 'qformat/xml';
|
||||||
|
$string['privacy:metadata'] = 'The XML question format plugin does not store any personal data.';
|
||||||
$string['truefalseimporterror'] = '<b>Warning</b>: The true/false question \'{$a->questiontext}\' could not be imported properly. It was not clear whether the correct answer is true or false. The question has been imported assuming that the answer is \'{$a->answer}\'. If this is not correct, you will need to edit the question.';
|
$string['truefalseimporterror'] = '<b>Warning</b>: The true/false question \'{$a->questiontext}\' could not be imported properly. It was not clear whether the correct answer is true or false. The question has been imported assuming that the answer is \'{$a->answer}\'. If this is not correct, you will need to edit the question.';
|
||||||
$string['unsupportedexport'] = 'Question type {$a} is not supported by XML export';
|
$string['unsupportedexport'] = 'Question type {$a} is not supported by XML export';
|
||||||
$string['xmlimportnoname'] = 'Missing question name in XML file';
|
$string['xmlimportnoname'] = 'Missing question name in XML file';
|
||||||
|
|
|
@ -87,6 +87,30 @@ class core_question_generator extends component_generator_base {
|
||||||
$question->category = $fromform->category;
|
$question->category = $fromform->category;
|
||||||
$question->qtype = $qtype;
|
$question->qtype = $qtype;
|
||||||
$question->createdby = 0;
|
$question->createdby = 0;
|
||||||
|
|
||||||
|
return $this->update_question($question, $which, $overrides);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an existing question.
|
||||||
|
*
|
||||||
|
* @param stdClass $question the question data to update.
|
||||||
|
* @param string $which as for the corresponding argument of
|
||||||
|
* {@link question_test_helper::get_question_form_data}. null for the default one.
|
||||||
|
* @param array|stdClass $overrides any fields that should be different from the base example.
|
||||||
|
*/
|
||||||
|
public function update_question($question, $which = null, $overrides = null) {
|
||||||
|
global $CFG;
|
||||||
|
require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
|
||||||
|
|
||||||
|
$qtype = $question->qtype;
|
||||||
|
|
||||||
|
$fromform = test_question_maker::get_question_form_data($qtype, $which);
|
||||||
|
$fromform = (object) $this->datagenerator->combine_defaults_and_record(
|
||||||
|
(array) $question, $fromform);
|
||||||
|
$fromform = (object) $this->datagenerator->combine_defaults_and_record(
|
||||||
|
(array) $fromform, $overrides);
|
||||||
|
|
||||||
return question_bank::get_qtype($qtype)->save_question($question, $fromform);
|
return question_bank::get_qtype($qtype)->save_question($question, $fromform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
103
question/tests/privacy_helper.php
Normal file
103
question/tests/privacy_helper.php
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for privacy tests.
|
||||||
|
*
|
||||||
|
* @package core_question
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
use \core_privacy\local\request\writer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for privacy tests.
|
||||||
|
*
|
||||||
|
* @package core_question
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
trait core_question_privacy_helper {
|
||||||
|
/**
|
||||||
|
* Assert that the question usage in the supplied slot matches the expected format
|
||||||
|
* and usage for a question.
|
||||||
|
*
|
||||||
|
* @param \question_usage_by_activity $quba The Question Usage to test against.
|
||||||
|
* @param int $slotno The slot number to compare
|
||||||
|
* @param \question_display_options $options The display options used for formatting.
|
||||||
|
* @param \stdClass $data The data to check.
|
||||||
|
*/
|
||||||
|
public function assert_question_slot_equals(
|
||||||
|
\question_usage_by_activity $quba,
|
||||||
|
$slotno,
|
||||||
|
\question_display_options $options,
|
||||||
|
$data
|
||||||
|
) {
|
||||||
|
$attempt = $quba->get_question_attempt($slotno);
|
||||||
|
$question = $attempt->get_question();
|
||||||
|
|
||||||
|
// Check the question data exported.
|
||||||
|
$this->assertEquals($data->name, $question->name);
|
||||||
|
$this->assertEquals($data->question, $question->questiontext);
|
||||||
|
|
||||||
|
// Check the answer exported.
|
||||||
|
$this->assertEquals($attempt->get_response_summary(), $data->answer);
|
||||||
|
|
||||||
|
if ($options->marks != \question_display_options::HIDDEN) {
|
||||||
|
$this->assertEquals($attempt->get_mark(), $data->mark);
|
||||||
|
} else {
|
||||||
|
$this->assertFalse(isset($data->mark));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($options->flags != \question_display_options::HIDDEN) {
|
||||||
|
$this->assertEquals($attempt->is_flagged(), (int) $data->flagged);
|
||||||
|
} else {
|
||||||
|
$this->assertFalse(isset($data->flagged));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($options->generalfeedback != \question_display_options::HIDDEN) {
|
||||||
|
$this->assertEquals($question->format_generalfeedback($attempt), $data->generalfeedback);
|
||||||
|
} else {
|
||||||
|
$this->assertFalse(isset($data->generalfeedback));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert that a question attempt was exported.
|
||||||
|
*
|
||||||
|
* @param \context $context The context which the attempt should be in
|
||||||
|
* @param array $subcontext The base of the export
|
||||||
|
* @param question_usage_by_activity $quba The question usage expected
|
||||||
|
* @param \question_display_options $options The display options used for formatting.
|
||||||
|
* @param \stdClass $user The user exported
|
||||||
|
*/
|
||||||
|
public function assert_question_attempt_exported(\context $context, array $subcontext, $quba, $options, $user) {
|
||||||
|
$usagecontext = array_merge(
|
||||||
|
$subcontext,
|
||||||
|
[get_string('questions', 'core_question')]
|
||||||
|
);
|
||||||
|
|
||||||
|
$writer = writer::with_context($context);
|
||||||
|
|
||||||
|
foreach ($quba->get_slots() as $slotno) {
|
||||||
|
$data = $writer->get_data(array_merge($usagecontext, [$slotno]));
|
||||||
|
$this->assert_question_slot_equals($quba, $slotno, $options, $data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
420
question/tests/privacy_provider_test.php
Normal file
420
question/tests/privacy_provider_test.php
Normal file
|
@ -0,0 +1,420 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy provider tests.
|
||||||
|
*
|
||||||
|
* @package core_question
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
use core_privacy\local\metadata\collection;
|
||||||
|
use core_privacy\local\request\deletion_criteria;
|
||||||
|
use core_privacy\local\request\writer;
|
||||||
|
use core_question\privacy\provider;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
global $CFG;
|
||||||
|
require_once($CFG->libdir . '/xmlize.php');
|
||||||
|
require_once(__DIR__ . '/privacy_helper.php');
|
||||||
|
require_once(__DIR__ . '/../engine/tests/helpers.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy provider tests class.
|
||||||
|
*
|
||||||
|
* @package core_question
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class core_question_privacy_provider_testcase extends \core_privacy\tests\provider_testcase {
|
||||||
|
|
||||||
|
// Include the privacy helper which has assertions on it.
|
||||||
|
use core_question_privacy_helper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare a question attempt.
|
||||||
|
*
|
||||||
|
* @return question_usage_by_activity
|
||||||
|
*/
|
||||||
|
protected function prepare_question_attempt() {
|
||||||
|
// Create a question with a usage from the current user.
|
||||||
|
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||||
|
$cat = $questiongenerator->create_question_category();
|
||||||
|
$quba = question_engine::make_questions_usage_by_activity('core_question_preview', context_system::instance());
|
||||||
|
$quba->set_preferred_behaviour('deferredfeedback');
|
||||||
|
$questiondata = $questiongenerator->create_question('numerical', null, ['category' => $cat->id]);
|
||||||
|
$question = question_bank::load_question($questiondata->id);
|
||||||
|
$quba->add_question($question);
|
||||||
|
$quba->start_all_questions();
|
||||||
|
|
||||||
|
question_engine::save_questions_usage_by_activity($quba);
|
||||||
|
|
||||||
|
return $quba;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that calling export_question_usage on a usage belonging to a
|
||||||
|
* different user does not export any data.
|
||||||
|
*/
|
||||||
|
public function test_export_question_usage_no_usage() {
|
||||||
|
$this->resetAfterTest();
|
||||||
|
|
||||||
|
$quba = $this->prepare_question_attempt();
|
||||||
|
|
||||||
|
// Create a question with a usage from the current user.
|
||||||
|
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||||
|
$cat = $questiongenerator->create_question_category();
|
||||||
|
$quba = question_engine::make_questions_usage_by_activity('core_question_preview', context_system::instance());
|
||||||
|
$quba->set_preferred_behaviour('deferredfeedback');
|
||||||
|
$questiondata = $questiongenerator->create_question('numerical', null, ['category' => $cat->id]);
|
||||||
|
$question = question_bank::load_question($questiondata->id);
|
||||||
|
$quba->add_question($question);
|
||||||
|
$quba->start_all_questions();
|
||||||
|
|
||||||
|
question_engine::save_questions_usage_by_activity($quba);
|
||||||
|
|
||||||
|
// Set the user.
|
||||||
|
$testuser = $this->getDataGenerator()->create_user();
|
||||||
|
$this->setUser($testuser);
|
||||||
|
$context = $quba->get_owning_context();
|
||||||
|
$options = new \question_display_options();
|
||||||
|
|
||||||
|
provider::export_question_usage($testuser->id, $context, [], $quba->get_id(), $options, false);
|
||||||
|
$writer = writer::with_context($context);
|
||||||
|
|
||||||
|
$this->assertFalse($writer->has_any_data_in_any_context());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that calling export_question_usage on a usage belonging to a
|
||||||
|
* different user but ignoring the user match
|
||||||
|
*/
|
||||||
|
public function test_export_question_usage_with_usage() {
|
||||||
|
$this->resetAfterTest();
|
||||||
|
|
||||||
|
$quba = $this->prepare_question_attempt();
|
||||||
|
|
||||||
|
// Create a question with a usage from the current user.
|
||||||
|
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||||
|
$cat = $questiongenerator->create_question_category();
|
||||||
|
$quba = question_engine::make_questions_usage_by_activity('core_question_preview', context_system::instance());
|
||||||
|
$quba->set_preferred_behaviour('deferredfeedback');
|
||||||
|
|
||||||
|
$questiondata = $questiongenerator->create_question('truefalse', 'true', ['category' => $cat->id]);
|
||||||
|
$quba->add_question(question_bank::load_question($questiondata->id));
|
||||||
|
$questiondata = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
|
||||||
|
$quba->add_question(question_bank::load_question($questiondata->id));
|
||||||
|
|
||||||
|
// Set the user and answer the questions.
|
||||||
|
$testuser = $this->getDataGenerator()->create_user();
|
||||||
|
$this->setUser($testuser);
|
||||||
|
|
||||||
|
$quba->start_all_questions();
|
||||||
|
$quba->process_action(1, ['answer' => 1]);
|
||||||
|
$quba->process_action(2, ['answer' => 'cat']);
|
||||||
|
$quba->finish_all_questions();
|
||||||
|
|
||||||
|
question_engine::save_questions_usage_by_activity($quba);
|
||||||
|
|
||||||
|
$context = $quba->get_owning_context();
|
||||||
|
|
||||||
|
// Export all questions for this attempt.
|
||||||
|
$options = new \question_display_options();
|
||||||
|
provider::export_question_usage($testuser->id, $context, [], $quba->get_id(), $options, true);
|
||||||
|
$writer = writer::with_context($context);
|
||||||
|
|
||||||
|
$this->assertTrue($writer->has_any_data_in_any_context());
|
||||||
|
$this->assertTrue($writer->has_any_data());
|
||||||
|
|
||||||
|
$slots = $quba->get_slots();
|
||||||
|
$this->assertCount(2, $slots);
|
||||||
|
|
||||||
|
foreach ($slots as $slotno) {
|
||||||
|
$data = $writer->get_data([get_string('questions', 'core_question'), $slotno]);
|
||||||
|
$this->assertNotNull($data);
|
||||||
|
$this->assert_question_slot_equals($quba, $slotno, $options, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEmpty($writer->get_data([get_string('questions', 'core_question'), $quba->next_slot_number()]));
|
||||||
|
|
||||||
|
// Disable some options and re-export.
|
||||||
|
writer::reset();
|
||||||
|
$options = new \question_display_options();
|
||||||
|
$options->hide_all_feedback();
|
||||||
|
$options->flags = \question_display_options::HIDDEN;
|
||||||
|
$options->marks = \question_display_options::HIDDEN;
|
||||||
|
|
||||||
|
provider::export_question_usage($testuser->id, $context, [], $quba->get_id(), $options, true);
|
||||||
|
$writer = writer::with_context($context);
|
||||||
|
|
||||||
|
$this->assertTrue($writer->has_any_data_in_any_context());
|
||||||
|
$this->assertTrue($writer->has_any_data());
|
||||||
|
|
||||||
|
$slots = $quba->get_slots();
|
||||||
|
$this->assertCount(2, $slots);
|
||||||
|
|
||||||
|
foreach ($slots as $slotno) {
|
||||||
|
$data = $writer->get_data([get_string('questions', 'core_question'), $slotno]);
|
||||||
|
$this->assertNotNull($data);
|
||||||
|
$this->assert_question_slot_equals($quba, $slotno, $options, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEmpty($writer->get_data([get_string('questions', 'core_question'), $quba->next_slot_number()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that questions owned by a user are exported and never deleted.
|
||||||
|
*/
|
||||||
|
public function test_question_owned_is_handled() {
|
||||||
|
global $DB;
|
||||||
|
$this->resetAfterTest();
|
||||||
|
|
||||||
|
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||||
|
|
||||||
|
// Create the two test users.
|
||||||
|
$user = $this->getDataGenerator()->create_user();
|
||||||
|
$otheruser = $this->getDataGenerator()->create_user();
|
||||||
|
|
||||||
|
// Create one question as each user in diferent contexts.
|
||||||
|
$this->setUser($user);
|
||||||
|
$userdata = $questiongenerator->setup_course_and_questions();
|
||||||
|
$expectedcontext = \context_course::instance($userdata[1]->id);
|
||||||
|
|
||||||
|
$this->setUser($otheruser);
|
||||||
|
$otheruserdata = $questiongenerator->setup_course_and_questions();
|
||||||
|
$unexpectedcontext = \context_course::instance($otheruserdata[1]->id);
|
||||||
|
|
||||||
|
// And create another one where we'll update a question as the test user.
|
||||||
|
$moreotheruserdata = $questiongenerator->setup_course_and_questions();
|
||||||
|
$otherexpectedcontext = \context_course::instance($moreotheruserdata[1]->id);
|
||||||
|
$morequestions = $moreotheruserdata[3];
|
||||||
|
|
||||||
|
// Update the third set of questions.
|
||||||
|
$this->setUser($user);
|
||||||
|
|
||||||
|
foreach ($morequestions as $question) {
|
||||||
|
$questiongenerator->update_question($question);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the get_contexts_for_userid as default user.
|
||||||
|
$this->setUser();
|
||||||
|
|
||||||
|
// There should be two contexts returned - the first course, and the third.
|
||||||
|
$contextlist = provider::get_contexts_for_userid($user->id);
|
||||||
|
$this->assertCount(2, $contextlist);
|
||||||
|
|
||||||
|
$expectedcontexts = [
|
||||||
|
$expectedcontext->id,
|
||||||
|
$otherexpectedcontext->id,
|
||||||
|
];
|
||||||
|
$this->assertEquals($expectedcontexts, $contextlist->get_contextids(), 'Contexts not equal', 0.0, 10, true);
|
||||||
|
|
||||||
|
// Run the export_user_Data as the test user.
|
||||||
|
$this->setUser($user);
|
||||||
|
|
||||||
|
$approvedcontextlist = new \core_privacy\tests\request\approved_contextlist(
|
||||||
|
\core_user::get_user($user->id),
|
||||||
|
'core_question',
|
||||||
|
$expectedcontexts
|
||||||
|
);
|
||||||
|
provider::export_user_data($approvedcontextlist);
|
||||||
|
|
||||||
|
// There should be data for the user's question context.
|
||||||
|
$writer = writer::with_context($expectedcontext);
|
||||||
|
$this->assertTrue($writer->has_any_data());
|
||||||
|
|
||||||
|
// And for the course we updated.
|
||||||
|
$otherwriter = writer::with_context($otherexpectedcontext);
|
||||||
|
$this->assertTrue($otherwriter->has_any_data());
|
||||||
|
|
||||||
|
// But not for the other user's course.
|
||||||
|
$otherwriter = writer::with_context($unexpectedcontext);
|
||||||
|
$this->assertFalse($otherwriter->has_any_data());
|
||||||
|
|
||||||
|
// The question data is exported as an XML export in custom files.
|
||||||
|
$writer = writer::with_context($expectedcontext);
|
||||||
|
$subcontext = [get_string('questionbank', 'core_question')];
|
||||||
|
|
||||||
|
$exportfile = $writer->get_custom_file($subcontext, 'questions.xml');
|
||||||
|
$this->assertNotEmpty($exportfile);
|
||||||
|
|
||||||
|
$xmlized = xmlize($exportfile);
|
||||||
|
$xmlquestions = $xmlized['quiz']['#']['question'];
|
||||||
|
|
||||||
|
$this->assertCount(2, $xmlquestions);
|
||||||
|
|
||||||
|
// Run the delete functions as default user.
|
||||||
|
$this->setUser();
|
||||||
|
|
||||||
|
// The delete functions should do nothing here.
|
||||||
|
$this->assertCount(6, $DB->get_records('question'));
|
||||||
|
|
||||||
|
// Delete for all users in context.
|
||||||
|
provider::delete_data_for_all_users_in_context($expectedcontext);
|
||||||
|
$this->assertCount(6, $DB->get_records('question'));
|
||||||
|
|
||||||
|
provider::delete_data_for_user($approvedcontextlist);
|
||||||
|
$this->assertCount(6, $DB->get_records('question'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deleting questions should only unset their created and modified user.
|
||||||
|
*/
|
||||||
|
public function test_question_delete_data_for_user_anonymised() {
|
||||||
|
global $DB;
|
||||||
|
$this->resetAfterTest(true);
|
||||||
|
|
||||||
|
$user = \core_user::get_user_by_username('admin');
|
||||||
|
$otheruser = $this->getDataGenerator()->create_user();
|
||||||
|
|
||||||
|
$course = $this->getDataGenerator()->create_course();
|
||||||
|
$context = \context_course::instance($course->id);
|
||||||
|
$othercourse = $this->getDataGenerator()->create_course();
|
||||||
|
$othercontext = \context_course::instance($othercourse->id);
|
||||||
|
|
||||||
|
// Create a couple of questions.
|
||||||
|
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||||
|
$cat = $questiongenerator->create_question_category([
|
||||||
|
'contextid' => $context->id,
|
||||||
|
]);
|
||||||
|
$othercat = $questiongenerator->create_question_category([
|
||||||
|
'contextid' => $othercontext->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Create questions:
|
||||||
|
// Q1 - Created by the UUT, Modified by UUT.
|
||||||
|
// Q2 - Created by the UUT, Modified by the other user.
|
||||||
|
// Q3 - Created by the other user, Modified by UUT
|
||||||
|
// Q4 - Created by the other user, Modified by the other user.
|
||||||
|
// Q5 - Created by the UUT, Modified by the UUT, but in a different context.
|
||||||
|
$this->setUser($user);
|
||||||
|
$q1 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
|
||||||
|
$q2 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
|
||||||
|
|
||||||
|
$this->setUser($otheruser);
|
||||||
|
$questiongenerator->update_question($q2);
|
||||||
|
$q3 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
|
||||||
|
$q4 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
|
||||||
|
|
||||||
|
$this->setUser($user);
|
||||||
|
$questiongenerator->update_question($q3);
|
||||||
|
$q5 = $questiongenerator->create_question('shortanswer', null, array('category' => $othercat->id));
|
||||||
|
|
||||||
|
$approvedcontextlist = new \core_privacy\tests\request\approved_contextlist(
|
||||||
|
$user,
|
||||||
|
'core_question',
|
||||||
|
[$context->id]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Delete the data and check it is removed.
|
||||||
|
$this->setUser();
|
||||||
|
provider::delete_data_for_user($approvedcontextlist);
|
||||||
|
|
||||||
|
$this->assertCount(5, $DB->get_records('question'));
|
||||||
|
|
||||||
|
$qrecord = $DB->get_record('question', ['id' => $q1->id]);
|
||||||
|
$this->assertEquals(0, $qrecord->createdby);
|
||||||
|
$this->assertEquals(0, $qrecord->modifiedby);
|
||||||
|
|
||||||
|
$qrecord = $DB->get_record('question', ['id' => $q2->id]);
|
||||||
|
$this->assertEquals(0, $qrecord->createdby);
|
||||||
|
$this->assertEquals($otheruser->id, $qrecord->modifiedby);
|
||||||
|
|
||||||
|
$qrecord = $DB->get_record('question', ['id' => $q3->id]);
|
||||||
|
$this->assertEquals($otheruser->id, $qrecord->createdby);
|
||||||
|
$this->assertEquals(0, $qrecord->modifiedby);
|
||||||
|
|
||||||
|
$qrecord = $DB->get_record('question', ['id' => $q4->id]);
|
||||||
|
$this->assertEquals($otheruser->id, $qrecord->createdby);
|
||||||
|
$this->assertEquals($otheruser->id, $qrecord->modifiedby);
|
||||||
|
|
||||||
|
$qrecord = $DB->get_record('question', ['id' => $q5->id]);
|
||||||
|
$this->assertEquals($user->id, $qrecord->createdby);
|
||||||
|
$this->assertEquals($user->id, $qrecord->modifiedby);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deleting questions should only unset their created and modified user for all questions in a context.
|
||||||
|
*/
|
||||||
|
public function test_question_delete_data_for_all_users_in_context_anonymised() {
|
||||||
|
global $DB;
|
||||||
|
$this->resetAfterTest(true);
|
||||||
|
|
||||||
|
$user = \core_user::get_user_by_username('admin');
|
||||||
|
$otheruser = $this->getDataGenerator()->create_user();
|
||||||
|
|
||||||
|
$course = $this->getDataGenerator()->create_course();
|
||||||
|
$context = \context_course::instance($course->id);
|
||||||
|
$othercourse = $this->getDataGenerator()->create_course();
|
||||||
|
$othercontext = \context_course::instance($othercourse->id);
|
||||||
|
|
||||||
|
// Create a couple of questions.
|
||||||
|
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||||
|
$cat = $questiongenerator->create_question_category([
|
||||||
|
'contextid' => $context->id,
|
||||||
|
]);
|
||||||
|
$othercat = $questiongenerator->create_question_category([
|
||||||
|
'contextid' => $othercontext->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Create questions:
|
||||||
|
// Q1 - Created by the UUT, Modified by UUT.
|
||||||
|
// Q2 - Created by the UUT, Modified by the other user.
|
||||||
|
// Q3 - Created by the other user, Modified by UUT
|
||||||
|
// Q4 - Created by the other user, Modified by the other user.
|
||||||
|
// Q5 - Created by the UUT, Modified by the UUT, but in a different context.
|
||||||
|
$this->setUser($user);
|
||||||
|
$q1 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
|
||||||
|
$q2 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
|
||||||
|
|
||||||
|
$this->setUser($otheruser);
|
||||||
|
$questiongenerator->update_question($q2);
|
||||||
|
$q3 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
|
||||||
|
$q4 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
|
||||||
|
|
||||||
|
$this->setUser($user);
|
||||||
|
$questiongenerator->update_question($q3);
|
||||||
|
$q5 = $questiongenerator->create_question('shortanswer', null, array('category' => $othercat->id));
|
||||||
|
|
||||||
|
// Delete the data and check it is removed.
|
||||||
|
$this->setUser();
|
||||||
|
provider::delete_data_for_all_users_in_context($context);
|
||||||
|
|
||||||
|
$this->assertCount(5, $DB->get_records('question'));
|
||||||
|
|
||||||
|
$qrecord = $DB->get_record('question', ['id' => $q1->id]);
|
||||||
|
$this->assertEquals(0, $qrecord->createdby);
|
||||||
|
$this->assertEquals(0, $qrecord->modifiedby);
|
||||||
|
|
||||||
|
$qrecord = $DB->get_record('question', ['id' => $q2->id]);
|
||||||
|
$this->assertEquals(0, $qrecord->createdby);
|
||||||
|
$this->assertEquals(0, $qrecord->modifiedby);
|
||||||
|
|
||||||
|
$qrecord = $DB->get_record('question', ['id' => $q3->id]);
|
||||||
|
$this->assertEquals(0, $qrecord->createdby);
|
||||||
|
$this->assertEquals(0, $qrecord->modifiedby);
|
||||||
|
|
||||||
|
$qrecord = $DB->get_record('question', ['id' => $q4->id]);
|
||||||
|
$this->assertEquals(0, $qrecord->createdby);
|
||||||
|
$this->assertEquals(0, $qrecord->modifiedby);
|
||||||
|
|
||||||
|
$qrecord = $DB->get_record('question', ['id' => $q5->id]);
|
||||||
|
$this->assertEquals($user->id, $qrecord->createdby);
|
||||||
|
$this->assertEquals($user->id, $qrecord->modifiedby);
|
||||||
|
}
|
||||||
|
}
|
46
question/type/calculated/classes/privacy/provider.php
Normal file
46
question/type/calculated/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qtype_calculated.
|
||||||
|
*
|
||||||
|
* @package qtype_calculated
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qtype_calculated\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qtype_calculated implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -115,6 +115,7 @@ $string['pluginname_link'] = 'question/type/calculated';
|
||||||
$string['pluginnameadding'] = 'Adding a Calculated question';
|
$string['pluginnameadding'] = 'Adding a Calculated question';
|
||||||
$string['pluginnameediting'] = 'Editing a Calculated question';
|
$string['pluginnameediting'] = 'Editing a Calculated question';
|
||||||
$string['pluginnamesummary'] = 'Calculated questions are like numerical questions but with the numbers used selected randomly from a set when the quiz is taken.';
|
$string['pluginnamesummary'] = 'Calculated questions are like numerical questions but with the numbers used selected randomly from a set when the quiz is taken.';
|
||||||
|
$string['privacy:metadata'] = 'The Calculated question type plugin does not store any personal data.';
|
||||||
$string['possiblehdr'] = 'Possible wild cards present only in the question text';
|
$string['possiblehdr'] = 'Possible wild cards present only in the question text';
|
||||||
$string['questiondatasets'] = 'Question datasets';
|
$string['questiondatasets'] = 'Question datasets';
|
||||||
$string['questiondatasets_help'] = 'Question datasets of wild cards that will be used in each individual question';
|
$string['questiondatasets_help'] = 'Question datasets of wild cards that will be used in each individual question';
|
||||||
|
|
46
question/type/calculatedmulti/classes/privacy/provider.php
Normal file
46
question/type/calculatedmulti/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qtype_calculatedmulti.
|
||||||
|
*
|
||||||
|
* @package qtype_calculatedmulti
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qtype_calculatedmulti\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qtype_calculatedmulti implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,3 +30,4 @@ $string['pluginname_link'] = 'question/type/calculatedmulti';
|
||||||
$string['pluginnameadding'] = 'Adding a Calculated multichoice question';
|
$string['pluginnameadding'] = 'Adding a Calculated multichoice question';
|
||||||
$string['pluginnameediting'] = 'Editing a Calculated multichoice question';
|
$string['pluginnameediting'] = 'Editing a Calculated multichoice question';
|
||||||
$string['pluginnamesummary'] = 'Calculated multichoice questions are like multichoice questions which choice elements can include formula results from numeric values that are selected randomly from a set when the quiz is taken.';
|
$string['pluginnamesummary'] = 'Calculated multichoice questions are like multichoice questions which choice elements can include formula results from numeric values that are selected randomly from a set when the quiz is taken.';
|
||||||
|
$string['privacy:metadata'] = 'The Calculated multichoice question type plugin does not store any personal data.';
|
||||||
|
|
46
question/type/calculatedsimple/classes/privacy/provider.php
Normal file
46
question/type/calculatedsimple/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qtype_calculatedsimple.
|
||||||
|
*
|
||||||
|
* @package qtype_calculatedsimple
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qtype_calculatedsimple\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qtype_calculatedsimple implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,7 @@ $string['pluginname_link'] = 'question/type/calculatedsimple';
|
||||||
$string['pluginnameadding'] = 'Adding a Simple calculated question';
|
$string['pluginnameadding'] = 'Adding a Simple calculated question';
|
||||||
$string['pluginnameediting'] = 'Editing a Simple calculated question';
|
$string['pluginnameediting'] = 'Editing a Simple calculated question';
|
||||||
$string['pluginnamesummary'] = 'A simpler version of calculated questions which are like numerical questions but with the numbers used selected randomly from a set when the quiz is taken.';
|
$string['pluginnamesummary'] = 'A simpler version of calculated questions which are like numerical questions but with the numbers used selected randomly from a set when the quiz is taken.';
|
||||||
|
$string['privacy:metadata'] = 'The Calculated simple question type plugin does not store any personal data.';
|
||||||
$string['setno'] = 'Set {$a}';
|
$string['setno'] = 'Set {$a}';
|
||||||
$string['setwildcardvalues'] = 'set(s) of wild card(s) values';
|
$string['setwildcardvalues'] = 'set(s) of wild card(s) values';
|
||||||
$string['showitems'] = 'Display';
|
$string['showitems'] = 'Display';
|
||||||
|
|
46
question/type/ddimageortext/classes/privacy/provider.php
Normal file
46
question/type/ddimageortext/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qtype_ddimageortext.
|
||||||
|
*
|
||||||
|
* @package qtype_ddimageortext
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qtype_ddimageortext\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qtype_ddimageortext implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,6 +61,7 @@ $string['pluginnameediting'] = 'Editing drag and drop onto image';
|
||||||
$string['pluginnamesummary'] = 'Images or text labels are dragged and dropped into drop zones on a background image.';
|
$string['pluginnamesummary'] = 'Images or text labels are dragged and dropped into drop zones on a background image.';
|
||||||
$string['previewareaheader'] = 'Preview';
|
$string['previewareaheader'] = 'Preview';
|
||||||
$string['previewareamessage'] = 'Select a background image, specify draggable items and define drop zones on the background image into which they must be dragged.';
|
$string['previewareamessage'] = 'Select a background image, specify draggable items and define drop zones on the background image into which they must be dragged.';
|
||||||
|
$string['privacy:metadata'] = 'The Drag and drop onto image question type does not store any personal data.';
|
||||||
$string['refresh'] = 'Refresh preview';
|
$string['refresh'] = 'Refresh preview';
|
||||||
$string['shuffleimages'] = 'Shuffle drag items each time question is attempted';
|
$string['shuffleimages'] = 'Shuffle drag items each time question is attempted';
|
||||||
$string['summarisechoice'] = '{$a->no}. {$a->text}';
|
$string['summarisechoice'] = '{$a->no}. {$a->text}';
|
||||||
|
|
46
question/type/ddmarker/classes/privacy/provider.php
Normal file
46
question/type/ddmarker/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qtype_ddmarker.
|
||||||
|
*
|
||||||
|
* @package qtype_ddmarker
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qtype_ddmarker\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qtype_ddmarker implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -69,6 +69,7 @@ $string['pluginnameediting'] = 'Editing drag and drop markers';
|
||||||
$string['pluginnamesummary'] = 'Markers are dragged and dropped onto a background image.';
|
$string['pluginnamesummary'] = 'Markers are dragged and dropped onto a background image.';
|
||||||
$string['previewareaheader'] = 'Preview';
|
$string['previewareaheader'] = 'Preview';
|
||||||
$string['previewareamessage'] = 'Select a background image file, enter text labels for markers and define the drop zones on the background image to which they must be dragged.';
|
$string['previewareamessage'] = 'Select a background image file, enter text labels for markers and define the drop zones on the background image to which they must be dragged.';
|
||||||
|
$string['privacy:metadata'] = 'The Drag and drop markers question type does not store any personal data.';
|
||||||
$string['refresh'] = 'Refresh preview';
|
$string['refresh'] = 'Refresh preview';
|
||||||
$string['clearwrongparts'] = 'Move incorrectly placed markers back to default start position below image';
|
$string['clearwrongparts'] = 'Move incorrectly placed markers back to default start position below image';
|
||||||
$string['shape'] = 'Shape';
|
$string['shape'] = 'Shape';
|
||||||
|
|
46
question/type/ddwtos/classes/privacy/provider.php
Normal file
46
question/type/ddwtos/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qtype_ddwtos.
|
||||||
|
*
|
||||||
|
* @package qtype_ddwtos
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qtype_ddwtos\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qtype_ddwtos implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,3 +34,4 @@ $string['pluginname_link'] = 'question/type/ddwtos';
|
||||||
$string['pluginnameadding'] = 'Adding a drag and drop into text';
|
$string['pluginnameadding'] = 'Adding a drag and drop into text';
|
||||||
$string['pluginnameediting'] = 'Editing a drag and drop into text';
|
$string['pluginnameediting'] = 'Editing a drag and drop into text';
|
||||||
$string['pluginnamesummary'] = 'Missing words in the question text are filled in using drag and drop.';
|
$string['pluginnamesummary'] = 'Missing words in the question text are filled in using drag and drop.';
|
||||||
|
$string['privacy:metadata'] = 'The Drag and drop into text question type does not store any personal data.';
|
||||||
|
|
46
question/type/description/classes/privacy/provider.php
Normal file
46
question/type/description/classes/privacy/provider.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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/>.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem implementation for qtype_description.
|
||||||
|
*
|
||||||
|
* @package qtype_description
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace qtype_description\privacy;
|
||||||
|
|
||||||
|
defined('MOODLE_INTERNAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Privacy Subsystem for qtype_description implementing null_provider.
|
||||||
|
*
|
||||||
|
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
|
||||||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||||
|
*/
|
||||||
|
class provider implements \core_privacy\local\metadata\null_provider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the language string identifier with the component's language
|
||||||
|
* file to explain why this plugin stores no data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function get_reason() : string {
|
||||||
|
return 'privacy:metadata';
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,3 +31,4 @@ The question text is displayed both during the attempt and on the review page. A
|
||||||
$string['pluginnameadding'] = 'Adding a description';
|
$string['pluginnameadding'] = 'Adding a description';
|
||||||
$string['pluginnameediting'] = 'Editing a Description';
|
$string['pluginnameediting'] = 'Editing a Description';
|
||||||
$string['pluginnamesummary'] = 'This is not actually a question. Instead it is a way to add some instructions, rubric or other content to the activity. This is similar to the way that labels can be used to add content to the course page.';
|
$string['pluginnamesummary'] = 'This is not actually a question. Instead it is a way to add some instructions, rubric or other content to the activity. This is similar to the way that labels can be used to add content to the course page.';
|
||||||
|
$string['privacy:metadata'] = 'The Description question type plugin does not store any personal data.';
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue