Skip to content

Commit

Permalink
Questionnaire: deletion area (Recycle bin) for deleted/orphaned quest…
Browse files Browse the repository at this point in the history
…ions
  • Loading branch information
toanlam committed Jun 5, 2024
1 parent b06947c commit 5590d50
Show file tree
Hide file tree
Showing 19 changed files with 641 additions and 72 deletions.
4 changes: 3 additions & 1 deletion backup/moodle2/restore_questionnaire_stepslib.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,9 @@ protected function process_questionnaire_question($data) {
$data = (object)$data;
$oldid = $data->id;
$data->surveyid = $this->get_new_parentid('questionnaire_survey');

if (!empty($data->deleted)) {
$data->deleted = time();
}
// Insert the questionnaire_question record.
$newitemid = $DB->insert_record('questionnaire_question', $data);
$this->set_mapping('questionnaire_question', $oldid, $newitemid, true);
Expand Down
10 changes: 5 additions & 5 deletions classes/question/question.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ abstract class question {
/** @var boolean $required The required flag. */
public $required = 'n';

/** @var boolean $deleted The deleted flag. */
public $deleted = 'n';
/** @var int $deleted The deleted flag. */
public $deleted = null;

/** @var mixed $extradata Any custom data for the question type. */
public $extradata = '';
Expand Down Expand Up @@ -577,7 +577,7 @@ public function response_complete($responsedata) {
// If $responsedata is webform data, check that its not empty.
$answered = isset($responsedata->{'q'.$this->id}) && ($responsedata->{'q'.$this->id} != '');
}
return !($this->required() && ($this->deleted == 'n') && !$answered);
return !($this->required() && (empty($this->deleted)) && !$answered);
}

/**
Expand Down Expand Up @@ -642,8 +642,8 @@ public function add($questionrecord, array $choicerecords = null, $calcposition
// Set the position to the end.
$sql = 'SELECT MAX(position) as maxpos '.
'FROM {questionnaire_question} '.
'WHERE surveyid = ? AND deleted = ?';
$params = ['surveyid' => $questionrecord->surveyid, 'deleted' => 'n'];
'WHERE surveyid = ? AND deleted IS NULL';
$params = ['surveyid' => $questionrecord->surveyid];
if ($record = $DB->get_record_sql($sql, $params)) {
$questionrecord->position = $record->maxpos + 1;
} else {
Expand Down
84 changes: 77 additions & 7 deletions classes/questions_form.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public function definition() {

$sid = $questionnaire->survey->id;
$mform =& $this->_form;
$qidrestore = optional_param(QUESTIONNAIRE_RESTORE_PARAM, 0, PARAM_INT);

$mform->addElement('header', 'questionhdr', get_string('addquestions', 'questionnaire'));
$mform->addHelpButton('questionhdr', 'questiontypes', 'questionnaire');
Expand Down Expand Up @@ -138,7 +139,7 @@ public function definition() {

// No page break in first position!
if ($tid == QUESPAGEBREAK && $pos == 1) {
$DB->set_field('questionnaire_question', 'deleted', 'y', ['id' => $qid, 'surveyid' => $sid]);
$DB->set_field('questionnaire_question', 'deleted', time(), ['id' => $qid, 'surveyid' => $sid]);
if ($records = $DB->get_records_select('questionnaire_question', $select, null, 'position ASC')) {
foreach ($records as $record) {
$DB->set_field('questionnaire_question', 'position', $record->position - 1, array('id' => $record->id));
Expand Down Expand Up @@ -172,7 +173,12 @@ public function definition() {
// Begin div qn-container with indent if questionnaire has child.
$mform->addElement('html', '<div class="qn-container qn-indent">');
} else {
$mform->addElement('html', '<div class="qn-container">'); // Begin div qn-container.
$containerclass = "qn-container";
if (isset($qidrestore) && $qidrestore == $question->id) {
$containerclass .= " restored-question";
}
// Begin div qn-container.
$mform->addElement('html', "<div class='$containerclass'>");
}

$mextra = array('value' => $question->id,
Expand Down Expand Up @@ -220,14 +226,15 @@ public function definition() {
// Do not allow moving or deleting a page break if immediately followed by a child question
// or immediately preceded by a question with a dependency and followed by a non-dependent question.
if ($tid == QUESPAGEBREAK) {
if ($nextquestion = $DB->get_record('questionnaire_question',
['surveyid' => $sid, 'position' => $pos + 1, 'deleted' => 'n'], 'id, name, content') ) {

$select = 'surveyid = ? AND position = ? AND deleted IS NULL';
$nextquestion = $DB->get_record_select('questionnaire_question', $select,
[$sid, $pos + 1], 'id, name, content');
if ($nextquestion) {
$nextquestiondependencies = $DB->get_records('questionnaire_dependency',
['questionid' => $nextquestion->id , 'surveyid' => $sid], 'id ASC');

if ($previousquestion = $DB->get_record('questionnaire_question',
['surveyid' => $sid, 'position' => $pos - 1, 'deleted' => 'n'], 'id, name, content')) {
if ($previousquestion = $DB->get_record_select('questionnaire_question', $select,
[$sid, $pos - 1], 'id, name, content')) {

$previousquestiondependencies = $DB->get_records('questionnaire_dependency',
['questionid' => $previousquestion->id , 'surveyid' => $sid], 'id ASC');
Expand Down Expand Up @@ -359,6 +366,66 @@ public function definition() {
}
}

// Question deletion area.
$mform->addElement('header', 'deletionq', get_string('deletionquetions', 'questionnaire'));
$mform->addHelpButton('deletionq', 'deletionquetions', 'questionnaire');
$mform->addElement('html', '<div class="qcontainer">');
if (isset($questionnaire->deletequestions)) {
$restoreimg = $questionnaire->renderer->image_url('i/up');
$deleteimg = $questionnaire->renderer->image_url('t/delete');
$rangetimecrontask = questionnaire_get_range_time_permanently();
foreach ($questionnaire->deletequestions as $deletequestion) {
$delquestiongroup = [];
// Preparing deleted time to display time permanently question.
$timedeleted = $deletequestion->deleted ?? "";
if ($rangetimecrontask == 0) {
$timedeleted = get_string('recylebindisabled', 'questionnaire');
} else {
if (!empty($timedeleted)) {
$timedeleted = get_string('timedeletednext7days', 'questionnaire',
date("D j M, Y", $timedeleted + $rangetimecrontask));
}
}
$qtypeandname = [];
$qtypeandname['name'] = $deletequestion->name;
$qtypeandname['type'] = questionnaire_get_type($deletequestion->type_id);

$content = format_text(
file_rewrite_pluginfile_urls($deletequestion->content, 'pluginfile.php',
$deletequestion->context->id,
'mod_questionnaire', 'question', $deletequestion->id),
FORMAT_HTML, ['noclean' => true]
);

$qnumber = '<div class="qn-info"><h2 class="qn-number">NA</h2></div>';
$restorextra = [
'value' => $deletequestion->id,
'alt' => get_string('restorebutton', 'questionnaire'),
'title' => get_string('restorebutton', 'questionnaire'),
];
$deleleextra = [
'value' => $deletequestion->id,
'alt' => get_string('deletepermanentlybutton', 'questionnaire'),
'title' => get_string('deletepermanentlybutton', 'questionnaire')
];
$mform->addElement('html', '<div class="qn-container">'); // Begin div qn-container.
$delquestiongroup[] =& $mform->createElement('static', 'opentag_' . $deletequestion->id, '', '');
$delquestiongroup[] =& $mform->createElement('image', 'restorebutton[' . $deletequestion->id . ']',
$restoreimg, $restorextra);
$delquestiongroup[] =& $mform->createElement('image', 'deletebutton[' . $deletequestion->id . ']',
$deleteimg, $deleleextra);
$delquestiongroup[] =& $mform->createElement('static', 'closetag_' . $deletequestion->id, '', '');
$delquestiongroup[] =& $mform->createElement('static', 'qinfo_' . $deletequestion->id, '',
get_string('questiontypeandname', 'questionnaire', $qtypeandname));
$delquestiongroup[] =& $mform->createElement('static', 'qinfo_' . $deletequestion->id, '', $timedeleted);
$mform->addGroup($delquestiongroup, 'delquestiongroup', '', '&nbsp;', false);
$mform->addElement('static', 'qcontent_'.$deletequestion->id, '',
$qnumber.'<div class="qn-question">'.$content.'</div>');
$mform->addElement('html', '</div>'); // End div qn-container.
}
}
// Question deletion area.

if ($this->moveq) {
$mform->addElement('hidden', 'moveq', $this->moveq);
}
Expand All @@ -373,6 +440,9 @@ public function definition() {
$mform->setType('moveq', PARAM_RAW);

$mform->addElement('html', '</div>');
$mform->setExpanded('questionhdr');
$mform->setExpanded('manageq');
$mform->setExpanded('deletionq');
}

/**
Expand Down
4 changes: 2 additions & 2 deletions classes/search/question.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ public function get_document($record, $options = []) {

// Because there is no database agnostic way to combine all of the possible question content data into one record in
// get_recordset_by_timestamp, I need to grab it all now and add it to the document.
$recordset = $DB->get_recordset('questionnaire_question', ['surveyid' => $record->sid, 'deleted' => 'n'],
'id', 'id,content');
$recordset = $DB->get_recordset_select('questionnaire_question',
'surveyid = ? AND deleted IS NULL', [$record->sid], 'id', 'id,content');

// If no question data, don't index this document.
if (empty($recordset)) {
Expand Down
54 changes: 54 additions & 0 deletions classes/task/cron_task.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

namespace mod_questionnaire\task;
defined('MOODLE_INTERNAL') || die();

require_once($CFG->dirroot.'/mod/questionnaire/questionnaire.class.php');
/**
* A schedule task for mod_questionnaire cron.
*
* @package mod_questionnaire
* @copyright 2022 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class cron_task extends \core\task\scheduled_task {
/**
* Get a descriptive name for this task (shown to admins).
*
* @return string
*/
public function get_name() {
return get_string('cleanrecylebin', 'mod_questionnaire');
}

/**
* Run mod_questionnaire cron.
*/
public function execute() {
global $DB;
$rangetimecrontask = questionnaire_get_range_time_permanently();
$sql = "SELECT *
FROM {questionnaire_question}
WHERE deleted IS NOT NULL
AND deleted < ?";
if ($deletequestions = $DB->get_records_sql($sql, [time() - $rangetimecrontask])) {
foreach ($deletequestions as $question) {
questionnaire_delete_permanently_questions($question->id, $question->surveyid);
}
}
}
}
2 changes: 1 addition & 1 deletion db/install.xml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
<FIELD NAME="position" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="content" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="required" TYPE="char" LENGTH="1" NOTNULL="true" DEFAULT="n" SEQUENCE="false"/>
<FIELD NAME="deleted" TYPE="char" LENGTH="1" NOTNULL="true" DEFAULT="n" SEQUENCE="false"/>
<FIELD NAME="deleted" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="The timestamp record last deleted."/>
<FIELD NAME="extradata" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="If a question needs more than the standard fields provided, use this field."/>
</FIELDS>
<KEYS>
Expand Down
11 changes: 10 additions & 1 deletion db/tasks.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,14 @@
'day' => '*',
'month' => '*',
'dayofweek' => '*'
)
),
[
'classname' => 'mod_questionnaire\task\cron_task',
'blocking' => 0,
'minute' => '*',
'hour' => '*',
'day' => '*/7',
'month' => '*',
'dayofweek' => '*'
],
);
29 changes: 29 additions & 0 deletions db/upgrade.php
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,35 @@ function xmldb_questionnaire_upgrade($oldversion=0) {
upgrade_mod_savepoint(true, 2022121600.02, 'questionnaire');
}

if ($oldversion < 2024060300.00) {
$table = new xmldb_table('questionnaire_question');
$index = new xmldb_index('quest_question_sididx', XMLDB_INDEX_NOTUNIQUE, ['surveyid', 'deleted']);
if ($dbman->index_exists($table, $index)) {
$dbman->drop_index($table, $index);
}
$field = new xmldb_field('deleted', XMLDB_TYPE_CHAR, '10', XMLDB_UNSIGNED, null, null, null, 'required');
if ($dbman->field_exists($table, $field)) {
$dbman->change_field_type($table, $field);
}
unset($field);

$field = new xmldb_field('deleted', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, 'required');
if ($dbman->field_exists($table, $field)) {
$sql = "UPDATE {questionnaire_question}
SET deleted = ?
WHERE deleted = 'y'";
$DB->execute($sql, [time()]);
$sql = "UPDATE {questionnaire_question}
SET deleted = null
WHERE deleted = 'n'";
$DB->execute($sql);
$dbman->change_field_type($table, $field);
}
unset($field);
// Questionnaire savepoint reached.
upgrade_mod_savepoint(true, 2024060300.00, 'questionnaire');
}

return true;
}

Expand Down
Loading

0 comments on commit 5590d50

Please sign in to comment.