Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Questionnaire option to auto-delete responses after X time #490930 #375

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backup/moodle2/backup_questionnaire_stepslib.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ protected function define_structure() {
$questionnaire = new backup_nested_element('questionnaire', array('id'), array(
'course', 'name', 'intro', 'introformat', 'qtype',
'respondenttype', 'resp_eligible', 'resp_view', 'notifications', 'opendate',
'closedate', 'resume', 'navigate', 'grade', 'sid', 'timemodified', 'completionsubmit', 'autonum'));
'closedate', 'resume', 'navigate', 'grade', 'sid', 'timemodified', 'completionsubmit', 'autonum', 'removeafter'));

$surveys = new backup_nested_element('surveys');

Expand Down
1 change: 1 addition & 0 deletions classes/task/cleanup.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ public function execute() {
require_once($CFG->dirroot . '/mod/questionnaire/locallib.php');

questionnaire_cleanup();
questionnaire_delete_old_responses();
}
}
1 change: 1 addition & 0 deletions db/install.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<FIELD NAME="completionsubmit" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Questionnaire marked as 'complete' when submitted."/>
<FIELD NAME="autonum" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="3" SEQUENCE="false" COMMENT="option for auto numbering questions and pages (both selected by default)"/>
<FIELD NAME="progressbar" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Display a progress bar at top of questionnaire."/>
<FIELD NAME="removeafter" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Remove old responses after certain period. 1 for one month, 2 for two months...12 for one year, 13 for two years and 14 for three years."/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
Expand Down
14 changes: 14 additions & 0 deletions db/upgrade.php
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,20 @@ function xmldb_questionnaire_upgrade($oldversion=0) {
upgrade_mod_savepoint(true, 2020062301, 'questionnaire');
}

if ($oldversion < 2021092800) {
// Add removeafter fields.
$table = new xmldb_table('questionnaire');
$field = new xmldb_field('removeafter', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, 0, 'progressbar');

// Conditionally launch add field.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}

// Questionnaire savepoint reached.
upgrade_mod_savepoint(true, 2021092800, 'questionnaire');
}

return $result;
}

Expand Down
6 changes: 6 additions & 0 deletions lang/en/questionnaire.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
$string['createcontent_help'] = 'Select one of the radio button options. \'Create new\' is the default.';
$string['createcontent_link'] = 'mod/questionnaire/mod#Content_Options';
$string['createnew'] = 'Create new';
$string['configremoveoldresponses'] = 'Setting which will be used as default on all new questionares.';
$string['date'] = 'Date';
$string['date_help'] = 'Use this question type if you expect the response to be a correctly formatted date.';
$string['date_link'] = 'mod/questionnaire/questions#Date';
Expand Down Expand Up @@ -385,6 +386,7 @@
$string['overviewnumrespvw'] = 'responses';
$string['overviewnumrespvw1'] = 'response';
$string['owner'] = 'Owner';
$string['onemonth'] = '1 month';
$string['page'] = 'Page';
$string['pageof'] = 'Page {$a->page} of {$a->totpages}';
$string['parent'] = 'Parent';
Expand Down Expand Up @@ -548,6 +550,10 @@
$string['resume_link'] = 'mod/questionnaire/mod#Save/Resume_answers';
$string['resumesurvey'] = 'Resume questionnaire';
$string['return'] = 'Return';
$string['removeoldresponsesdefault'] = 'Never remove';
$string['removeoldresponses'] = 'Manage old responses';
$string['removeoldresponsesafter'] = 'Manage old responses after';
$string['removeoldresponses_help'] = 'The system can automatically remove responses after a certain length of time.';
$string['save'] = 'Save';
$string['saveasnew'] = 'Save as New Question';
$string['savedbutnotsubmitted'] = 'This questionnaire has been saved but not yet submitted.';
Expand Down
60 changes: 60 additions & 0 deletions locallib.php
Original file line number Diff line number Diff line change
Expand Up @@ -879,3 +879,63 @@ function questionnaire_get_standard_page_items($id = null, $a = null) {

return (array($cm, $course, $questionnaire));
}


/**
* Create options for remove old responses in the questionare.
*
* @return array
*/
function questionnaire_create_remove_options() {
$options = [];
$options[0] = get_string('removeoldresponsesdefault', 'questionnaire');
for ($i = 1; $i <= 36; $i++) {
$options[$i * 2592000] = $i > 1 ? get_string('nummonths', 'moodle', $i) : get_string('onemonth', 'questionnaire');
}
return $options;
}

/**
* Delete all the old responses when we have setting the questionnaire.
*
* @throws coding_exception
* @throws dml_exception
*/
function questionnaire_delete_old_responses() {
global $DB;
$currenttime = time();

$sql = "SELECT qr.id
FROM {questionnaire} q
JOIN {questionnaire_response} qr ON qr.questionnaireid = q.id AND qr.complete = 'y'
WHERE q.removeafter <> 0 AND (q.removeafter < :currettime - qr.submitted)";
// Get all old response from questionnaires.
$oldresponsesid = $DB->get_records_sql($sql, ['currettime' => $currenttime]);
if (!empty($oldresponsesid)) {
try {
$oldresponsesid = array_keys($oldresponsesid);
$count = count($oldresponsesid);
if (!PHPUNIT_TEST) {
mtrace("\nBeginning deleting $count old responses requests");
}
// Delete all of the response data for a response.
$responsetables = [
'questionnaire_response_bool', 'questionnaire_response_date', 'questionnaire_resp_multiple',
'questionnaire_response_other', 'questionnaire_response_rank', 'questionnaire_resp_single',
'questionnaire_response_text'];
list ($sqlparam, $params) = $DB->get_in_or_equal($oldresponsesid, SQL_PARAMS_QM);
foreach ($responsetables as $tablename) {
$sql = "DELETE FROM {{$tablename}} r WHERE r.response_id $sqlparam";
$DB->execute($sql, $params);
}
// Delete the response from the main table.
$sql = "DELETE FROM {questionnaire_response} r WHERE r.id $sqlparam";
$DB->execute($sql, $params);
if (!PHPUNIT_TEST) {
mtrace("\nCompleted deleting $count old responses requests");
}
} catch (\dml_exception $ex) {
debugging('Error: ' . $ex->getMessage(), DEBUG_DEVELOPER);
}
}
}
27 changes: 26 additions & 1 deletion mod_form.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
class mod_questionnaire_mod_form extends moodleform_mod {

protected function definition() {
global $COURSE;
global $COURSE, $CFG;
global $questionnairetypes, $questionnairerespondents, $questionnaireresponseviewers, $autonumbering;

$questionnaire = new questionnaire($this->_instance, null, $COURSE, $this->_cm);
Expand Down Expand Up @@ -139,6 +139,17 @@ protected function definition() {
$mform->setDefault('create', 'new-0');
}

// Remove old responses.
$options = questionnaire_create_remove_options();
$mform->addElement('header', 'responsehdr', get_string('removeoldresponses', 'questionnaire'));
$mform->addElement('select', 'removeafter',
get_string('removeoldresponsesafter', 'questionnaire'), $options);
$mform->addHelpButton('removeafter', 'removeoldresponses', 'questionnaire');
// Just set default value when creating a new questionare.
if (empty($questionnaire->sid)) {
$defaultconfig = get_config('questionnaire', 'removeoldresponses');
$mform->setDefault('removeafter', $defaultconfig);
}
$this->standard_coursemodule_elements();

// Buttons.
Expand Down Expand Up @@ -198,4 +209,18 @@ public function completion_rule_enabled($data) {
return !empty($data['completionsubmit']);
}

/**
* Create options for remove old responses in the questionare.
*
* @return array
*/
public function create_remove_options() {
$options = [];
$options[0] = get_string('removeoldresponsesdefault', 'questionnaire');
for ($i = 1; $i <= 36; $i++) {
$options[$i * 2592000] = $i > 1 ? get_string('nummonths', 'moodle', $i) : get_string('onemonth', 'questionnaire');
}
return $options;
}

}
7 changes: 7 additions & 0 deletions settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/

defined('MOODLE_INTERNAL') || die;
require_once($CFG->dirroot . '/mod/questionnaire/locallib.php');

if ($ADMIN->fulltree) {
$options = array(0 => get_string('no'), 1 => get_string('yes'));
Expand Down Expand Up @@ -50,4 +51,10 @@

$settings->add(new admin_setting_configcheckbox('questionnaire/allowemailreporting',
get_string('configemailreporting', 'questionnaire'), get_string('configemailreportinglong', 'questionnaire'), 0));

// Manage old responses after. The default value is 24 months.
$options = questionnaire_create_remove_options();
$settings->add(new admin_setting_configselect('questionnaire/removeoldresponses',
get_string('removeoldresponsesafter', 'questionnaire'),
get_string('configremoveoldresponses', 'questionnaire'), 0, $options));
}
51 changes: 51 additions & 0 deletions tests/responsetypes_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -316,4 +316,55 @@ private function response_tests($questionnaireid, $responseid, $userid,
$this->assertArrayHasKey($responseid, $responses);
$this->assertEquals($responseid, $responses[$responseid]->id);
}

public function test_create_old_response_boolean() {
global $DB;

$this->resetAfterTest();

// Some common variables used below.
$userid = 1;

// Set up a questinnaire with one boolean response question.
$course = $this->getDataGenerator()->create_course();
$generator = $this->getDataGenerator()->get_plugin_generator('mod_questionnaire');
// Add a questionnaire that will delete old responses after one month.
$questionnaire1 = $generator->create_test_questionnaire($course, QUESYESNO, ['content' => 'Enter yes or no']);
$question1 = reset($questionnaire1->questions);
$response1 = $generator->create_question_response($questionnaire1, $question1, 'y', $userid);

$questionnaire2 = $generator->create_test_questionnaire($course, QUESYESNO, ['content' => 'Enter yes or no']);
$question2 = reset($questionnaire2->questions);
$response2 = $generator->create_question_response($questionnaire2, $question2, 'y', $userid);

$this->response_tests($questionnaire1->id, $response1->id, $userid);
$this->response_tests($questionnaire2->id, $response2->id, $userid);

// Set the removeafterfield for questionnaires.
$newquestionairre1 = new stdClass();
$newquestionairre1->id = $questionnaire1->id;
$newquestionairre1->removeafter = 2592000;
$newquestionairre2 = new stdClass();
$newquestionairre2->id = $questionnaire2->id;
$newquestionairre2->removeafter = 2592000;
$DB->update_record('questionnaire', $newquestionairre1);
$DB->update_record('questionnaire', $newquestionairre2);
// Retrieve the specific boolean response.
$booleanresponses1 = $DB->get_record('questionnaire_response', ['id' => $response1->id]);
$booleanresponses2 = $DB->get_record('questionnaire_response', ['id' => $response2->id]);
// Set the submitted time to 31 day in the past.
$booleanresponses1->submitted = $booleanresponses1->submitted - 2592000 - 86400;
$booleanresponses2->submitted = $booleanresponses2->submitted - 2592000 - 86400;
$DB->update_record('questionnaire_response', $booleanresponses1);
$DB->update_record('questionnaire_response', $booleanresponses2);
questionnaire_delete_old_responses();
$responseresult1 = $DB->record_exists('questionnaire_response', ['id' => $response1->id]);
$responseresult2 = $DB->record_exists('questionnaire_response', ['id' => $response2->id]);
$this->assertEmpty($responseresult1);
$this->assertEmpty($responseresult2);
$boolresponseresult1 = $DB->record_exists('questionnaire_response_bool', ['response_id' => $response1->id]);
$boolresponseresult2 = $DB->record_exists('questionnaire_response_bool', ['response_id' => $response2->id]);
$this->assertEmpty($boolresponseresult1);
$this->assertEmpty($boolresponseresult2);
}
}
2 changes: 1 addition & 1 deletion version.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

defined('MOODLE_INTERNAL') || die();

$plugin->version = 2020111101; // The current module version (Date: YYYYMMDDXX).
$plugin->version = 2021092800; // The current module version (Date: YYYYMMDDXX).
$plugin->requires = 2020061500; // Moodle version (3.9).

$plugin->component = 'mod_questionnaire';
Expand Down