Skip to content

Commit 08a415f

Browse files
mchurchwardtai.letan
andauthored
Nash tech open university wip490930 (#634)
* Questionnaire: option to auto-delete responses after X time * Questionnaire: option to auto-delete responses after X time (Fixed code review) * PR590 Correcting version. --------- Co-authored-by: tai.letan <[email protected]>
1 parent 8ed9ad7 commit 08a415f

File tree

10 files changed

+189
-3
lines changed

10 files changed

+189
-3
lines changed

backup/moodle2/backup_questionnaire_stepslib.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ protected function define_structure() {
3939
$questionnaire = new backup_nested_element('questionnaire', array('id'), array(
4040
'course', 'name', 'intro', 'introformat', 'qtype',
4141
'respondenttype', 'resp_eligible', 'resp_view', 'notifications', 'opendate',
42-
'closedate', 'resume', 'navigate', 'grade', 'sid', 'timemodified', 'completionsubmit', 'autonum'));
42+
'closedate', 'resume', 'navigate', 'grade', 'sid', 'timemodified', 'completionsubmit', 'autonum', 'removeafter'));
4343

4444
$surveys = new backup_nested_element('surveys');
4545

classes/task/cleanup.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,9 @@ public function execute() {
4343
require_once($CFG->dirroot . '/mod/questionnaire/locallib.php');
4444

4545
questionnaire_cleanup();
46+
$isautodelete = (bool) get_config('questionnaire', 'autodeleteresponse');
47+
if ($isautodelete) {
48+
questionnaire_delete_old_responses();
49+
}
4650
}
4751
}

db/install.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
<FIELD NAME="completionsubmit" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Questionnaire marked as 'complete' when submitted."/>
2727
<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)"/>
2828
<FIELD NAME="progressbar" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Display a progress bar at top of questionnaire."/>
29+
<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."/>
2930
</FIELDS>
3031
<KEYS>
3132
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>

db/upgrade.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,20 @@ function xmldb_questionnaire_upgrade($oldversion=0) {
10021002
upgrade_mod_savepoint(true, 2022121600.02, 'questionnaire');
10031003
}
10041004

1005+
if ($oldversion < 2022121601.01) {
1006+
// Add removeafter fields.
1007+
$table = new xmldb_table('questionnaire');
1008+
$field = new xmldb_field('removeafter', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, 0, 'progressbar');
1009+
1010+
// Conditionally launch add field.
1011+
if (!$dbman->field_exists($table, $field)) {
1012+
$dbman->add_field($table, $field);
1013+
}
1014+
1015+
// Questionnaire savepoint reached.
1016+
upgrade_mod_savepoint(true, 2022121601.01, 'questionnaire');
1017+
}
1018+
10051019
return true;
10061020
}
10071021

lang/en/questionnaire.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
$string['attempted'] = 'This questionnaire has been submitted.';
5353
$string['attemptsallowed'] = 'Attempts allowed: {$a}';
5454
$string['attemptstillinprogress'] = 'In progress. Saved on:';
55+
$string['autodeletereponse'] = 'Auto delete responses after [?]';
56+
$string['autodeletereponse_desc'] = 'Enable this setting to automatically delete old responses based on the time set in “Delete old responses after.” Disable to retain all responses.';
5557
$string['autonumbering'] = 'Auto numbering';
5658
$string['autonumbering_help'] = 'Automatic numbering of questions and pages. You might want to disable automatic numbering
5759
for questionnaires with conditional branching.';
@@ -70,6 +72,7 @@
7072
$string['boxesnbreq'] = 'For this question you must tick ';
7173
$string['by'] = ' by ';
7274
$string['daily'] = '1 per day';
75+
$string['disabled'] = 'Disabled';
7376
$string['missingname'] = 'Question {$a} cannot be used in this feedback section because it does not have a name.';
7477
$string['missingrequired'] = 'Question {$a} cannot be used in this feedback section because it is not required.';
7578
$string['missingnameandrequired'] = 'Question {$a} cannot be used in this feedback section because it does not have a name and it is not required.';
@@ -122,6 +125,7 @@
122125
$string['createcontent_help'] = 'Select one of the radio button options. \'Create new\' is the default.';
123126
$string['createcontent_link'] = 'mod/questionnaire/mod#Content_Options';
124127
$string['createnew'] = 'Create new';
128+
$string['configremoveoldresponses'] = 'Setting which will be used as default on all new questionares.';
125129
$string['centerlabel'] = 'Centre label';
126130
$string['date'] = 'Date';
127131
$string['date_help'] = 'Use this question type if you expect the response to be a correctly formatted date.';
@@ -172,6 +176,7 @@
172176
\'allowemailreporting\' must be enabled in module settings to access this.';
173177
$string['emailsend'] = 'Send reports';
174178
$string['emailssent'] = 'Downloads sent to specified email(s).';
179+
$string['enabled'] = 'Enabled';
175180
$string['errnewname'] = 'Sorry, name already in use. Pick a new name.';
176181
$string['erroropening'] = 'Error opening questionnaire.';
177182
$string['errortable'] = 'Error system table corrupt.';
@@ -411,6 +416,7 @@
411416
$string['overviewnumrespvw'] = 'responses';
412417
$string['overviewnumrespvw1'] = 'response';
413418
$string['owner'] = 'Owner';
419+
$string['onemonth'] = '1 month';
414420
$string['page'] = 'Page';
415421
$string['pageof'] = 'Page {$a->page} of {$a->totpages}';
416422
$string['parent'] = 'Parent';
@@ -577,6 +583,10 @@
577583
$string['resume_link'] = 'mod/questionnaire/mod#Save/Resume_answers';
578584
$string['resumesurvey'] = 'Resume questionnaire';
579585
$string['return'] = 'Return';
586+
$string['removeoldresponsesdefault'] = 'Never remove';
587+
$string['removeoldresponses'] = 'Delete old responses';
588+
$string['removeoldresponsesafter'] = 'Delete old responses after';
589+
$string['removeoldresponses_help'] = 'The system can automatically remove responses after a certain length of time.';
580590
$string['rightlabel'] = 'Right label';
581591
$string['rightpart'] = ' and {$a->max} is {$a->rightlabel}';
582592
$string['rightpartdefault'] = ' and {$a->max} is maximum slider range';

locallib.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,3 +949,65 @@ function questionnaire_get_standard_page_items($id = null, $a = null) {
949949

950950
return (array($cm, $course, $questionnaire));
951951
}
952+
953+
954+
/**
955+
* Create options for remove old responses in the questionare.
956+
*
957+
* @return array
958+
*/
959+
function questionnaire_create_remove_options() {
960+
$options = [];
961+
$options[0] = get_string('removeoldresponsesdefault', 'questionnaire');
962+
for ($i = 1; $i <= 36; $i++) {
963+
$options[$i * 2592000] = $i > 1 ? get_string('nummonths', 'moodle', $i) : get_string('onemonth', 'questionnaire');
964+
}
965+
return $options;
966+
}
967+
968+
/**
969+
* Delete all the old responses when we have setting the questionnaire.
970+
*
971+
* @throws coding_exception
972+
* @throws dml_exception
973+
*/
974+
function questionnaire_delete_old_responses() {
975+
global $DB;
976+
$currenttime = time();
977+
978+
$sql = "SELECT qr.id
979+
FROM {questionnaire} q
980+
JOIN {questionnaire_response} qr ON qr.questionnaireid = q.id AND qr.complete = 'y'
981+
WHERE q.removeafter <> 0 AND (q.removeafter < :currenttime - qr.submitted)";
982+
983+
// Get all old response IDs from questionnaires.
984+
$oldresponses = $DB->get_records_sql($sql, ['currenttime' => $currenttime]);
985+
986+
if (!empty($oldresponses)) {
987+
try {
988+
$oldresponsesid = array_keys($oldresponses);
989+
$count = count($oldresponsesid);
990+
if (!PHPUNIT_TEST) {
991+
mtrace("\nBeginning deleting $count old responses requests");
992+
}
993+
// Tables to delete responses from.
994+
$responsetables = [
995+
'questionnaire_response_bool', 'questionnaire_response_date', 'questionnaire_resp_multiple',
996+
'questionnaire_response_other', 'questionnaire_response_rank', 'questionnaire_resp_single',
997+
'questionnaire_response_text'];
998+
999+
// Delete related response data.
1000+
foreach ($responsetables as $tablename) {
1001+
$DB->delete_records_list($tablename, 'response_id', $oldresponsesid);
1002+
}
1003+
1004+
// Delete from the main response table.
1005+
$DB->delete_records_list('questionnaire_response', 'id', $oldresponsesid);
1006+
if (!PHPUNIT_TEST) {
1007+
mtrace("\nCompleted deleting $count old responses requests");
1008+
}
1009+
} catch (\dml_exception $ex) {
1010+
debugging('Error: ' . $ex->getMessage(), DEBUG_DEVELOPER);
1011+
}
1012+
}
1013+
}

mod_form.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class mod_questionnaire_mod_form extends moodleform_mod {
3434
* Form definition.
3535
*/
3636
protected function definition() {
37-
global $COURSE;
37+
global $COURSE, $CFG;
3838
global $questionnairetypes, $questionnairerespondents, $questionnaireresponseviewers, $autonumbering;
3939

4040
$questionnaire = new questionnaire($COURSE, $this->_cm, $this->_instance, null);
@@ -142,6 +142,20 @@ protected function definition() {
142142
$mform->setDefault('create', 'new-0');
143143
}
144144

145+
// Remove old responses.
146+
$isautodelete = (bool) get_config('questionnaire', 'autodeleteresponse');
147+
if ($isautodelete) {
148+
$options = $this->create_remove_options();
149+
$mform->addElement('header', 'responsehdr', get_string('removeoldresponses', 'questionnaire'));
150+
$mform->addElement('select', 'removeafter',
151+
get_string('removeoldresponsesafter', 'questionnaire'), $options);
152+
$mform->addHelpButton('removeafter', 'removeoldresponses', 'questionnaire');
153+
// Just set default value when creating a new questionare.
154+
if (empty($questionnaire->sid)) {
155+
$defaultconfig = get_config('questionnaire', 'removeoldresponses');
156+
$mform->setDefault('removeafter', $defaultconfig);
157+
}
158+
}
145159
$this->standard_coursemodule_elements();
146160

147161
// Buttons.
@@ -223,4 +237,18 @@ public function completion_rule_enabled($data) {
223237
return !empty($data['completionsubmit']);
224238
}
225239

240+
/**
241+
* Create options for remove old responses in the questionare.
242+
*
243+
* @return array
244+
*/
245+
public function create_remove_options() {
246+
$options = [];
247+
$options[0] = get_string('removeoldresponsesdefault', 'questionnaire');
248+
for ($i = 1; $i <= 36; $i++) {
249+
$options[$i * 2592000] = $i > 1 ? get_string('nummonths', 'moodle', $i) : get_string('onemonth', 'questionnaire');
250+
}
251+
return $options;
252+
}
253+
226254
}

settings.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525

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

2829
if ($ADMIN->fulltree) {
2930
$options = array(0 => get_string('no'), 1 => get_string('yes'));
@@ -52,4 +53,19 @@
5253

5354
$settings->add(new admin_setting_configcheckbox('questionnaire/allowemailreporting',
5455
get_string('configemailreporting', 'questionnaire'), get_string('configemailreportinglong', 'questionnaire'), 0));
56+
57+
// Delete old responses after. The default value is 24 months.
58+
$options = [
59+
'0' => new lang_string('disabled', 'questionnaire'),
60+
'1' => new lang_string('enabled', 'questionnaire'),
61+
];
62+
$name = get_string('autodeletereponse', 'questionnaire');
63+
$desc = get_string('autodeletereponse_desc', 'questionnaire');
64+
$setting = new admin_setting_configselect('questionnaire/autodeleteresponse', $name, $desc, 0, $options);
65+
$settings->add($setting);
66+
67+
$options = questionnaire_create_remove_options();
68+
$settings->add(new admin_setting_configselect('questionnaire/removeoldresponses',
69+
get_string('removeoldresponsesafter', 'questionnaire'),
70+
get_string('configremoveoldresponses', 'questionnaire'), 0, $options));
5571
}

tests/responsetypes_test.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,4 +419,55 @@ private function response_tests($questionnaireid, $responseid, $userid,
419419
$this->assertArrayHasKey($responseid, $responses);
420420
$this->assertEquals($responseid, $responses[$responseid]->id);
421421
}
422+
423+
public function test_create_old_response_boolean() {
424+
global $DB;
425+
426+
$this->resetAfterTest();
427+
428+
// Some common variables used below.
429+
$userid = 1;
430+
431+
// Set up a questionnaire with one boolean response question.
432+
$course = $this->getDataGenerator()->create_course();
433+
$generator = $this->getDataGenerator()->get_plugin_generator('mod_questionnaire');
434+
// Add a questionnaire that will delete old responses after one month.
435+
$questionnaire1 = $generator->create_test_questionnaire($course, QUESYESNO, ['content' => 'Enter yes or no']);
436+
$question1 = reset($questionnaire1->questions);
437+
$response1 = $generator->create_question_response($questionnaire1, $question1, 'y', $userid);
438+
439+
$questionnaire2 = $generator->create_test_questionnaire($course, QUESYESNO, ['content' => 'Enter yes or no']);
440+
$question2 = reset($questionnaire2->questions);
441+
$response2 = $generator->create_question_response($questionnaire2, $question2, 'y', $userid);
442+
443+
$this->response_tests($questionnaire1->id, $response1->id, $userid);
444+
$this->response_tests($questionnaire2->id, $response2->id, $userid);
445+
446+
// Set the removeafterfield for questionnaires.
447+
$newquestionairre1 = new \stdClass();
448+
$newquestionairre1->id = $questionnaire1->id;
449+
$newquestionairre1->removeafter = 2592000;
450+
$newquestionairre2 = new \stdClass();
451+
$newquestionairre2->id = $questionnaire2->id;
452+
$newquestionairre2->removeafter = 2592000;
453+
$DB->update_record('questionnaire', $newquestionairre1);
454+
$DB->update_record('questionnaire', $newquestionairre2);
455+
// Retrieve the specific boolean response.
456+
$booleanresponses1 = $DB->get_record('questionnaire_response', ['id' => $response1->id]);
457+
$booleanresponses2 = $DB->get_record('questionnaire_response', ['id' => $response2->id]);
458+
// Set the submitted time to 31 day in the past.
459+
$booleanresponses1->submitted = $booleanresponses1->submitted - 2592000 - 86400;
460+
$booleanresponses2->submitted = $booleanresponses2->submitted - 2592000 - 86400;
461+
$DB->update_record('questionnaire_response', $booleanresponses1);
462+
$DB->update_record('questionnaire_response', $booleanresponses2);
463+
questionnaire_delete_old_responses();
464+
$responseresult1 = $DB->record_exists('questionnaire_response', ['id' => $response1->id]);
465+
$responseresult2 = $DB->record_exists('questionnaire_response', ['id' => $response2->id]);
466+
$this->assertEmpty($responseresult1);
467+
$this->assertEmpty($responseresult2);
468+
$boolresponseresult1 = $DB->record_exists('questionnaire_response_bool', ['response_id' => $response1->id]);
469+
$boolresponseresult2 = $DB->record_exists('questionnaire_response_bool', ['response_id' => $response2->id]);
470+
$this->assertEmpty($boolresponseresult1);
471+
$this->assertEmpty($boolresponseresult2);
472+
}
422473
}

version.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

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

28-
$plugin->version = 2022121601; // The current module version (Date: YYYYMMDDXX).
28+
$plugin->version = 2022121601.01; // The current module version (Date: YYYYMMDDXX).
2929
$plugin->requires = 2024042200.00; // Moodle version (4.4.0).
3030

3131
$plugin->component = 'mod_questionnaire';

0 commit comments

Comments
 (0)