Skip to content

Commit

Permalink
Merge branch 'MDL-68597_311' of https://github.com/timhunt/moodle int…
Browse files Browse the repository at this point in the history
…o MOODLE_311_STABLE
  • Loading branch information
abgreeve committed Jan 14, 2021
2 parents 7cd9a3c + 8306fc3 commit e07bba3
Show file tree
Hide file tree
Showing 16 changed files with 496 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,9 @@ protected function define_question_plugin_structure() {

// Now create the qtype own structures.
$essay = new backup_nested_element('essay', array('id'), array(
'responseformat', 'responserequired', 'responsefieldlines',
'attachments', 'attachmentsrequired', 'graderinfo',
'graderinfoformat', 'responsetemplate', 'responsetemplateformat',
'filetypeslist', 'maxbytes'));
'responseformat', 'responserequired', 'responsefieldlines', 'minwordlimit', 'maxwordlimit',
'attachments', 'attachmentsrequired', 'graderinfo', 'graderinfoformat', 'responsetemplate',
'responsetemplateformat', 'filetypeslist', 'maxbytes'));

// Now the own qtype tree.
$pluginwrapper->add_child($essay);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ public function process_essay($data) {
if (!isset($data->responserequired)) {
$data->responserequired = 1;
}
if (!isset($data->minwordlimit)) {
$data->minwordlimit = null;
}
if (!isset($data->maxwordlimit)) {
$data->maxwordlimit = null;
}
if (!isset($data->attachmentsrequired)) {
$data->attachmentsrequired = 0;
}
Expand Down Expand Up @@ -111,6 +117,8 @@ protected function after_execute_question() {
$defaultoptions->responseformat = 'editor';
$defaultoptions->responserequired = 1;
$defaultoptions->responsefieldlines = 15;
$defaultoptions->minwordlimit = null;
$defaultoptions->maxwordlimit = null;
$defaultoptions->attachments = 0;
$defaultoptions->attachmentsrequired = 0;
$defaultoptions->graderinfo = '';
Expand Down
2 changes: 2 additions & 0 deletions question/type/essay/db/install.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
<FIELD NAME="responseformat" TYPE="char" LENGTH="16" NOTNULL="true" DEFAULT="editor" SEQUENCE="false" COMMENT="The type of input area students should be given for their response."/>
<FIELD NAME="responserequired" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false" COMMENT="Nonzero if an online text response is optional"/>
<FIELD NAME="responsefieldlines" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="15" SEQUENCE="false" COMMENT="Approximate height, in lines, of the input box the students should be given for their response."/>
<FIELD NAME="minwordlimit" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Minimum number of words"/>
<FIELD NAME="maxwordlimit" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Maximum number of words"/>
<FIELD NAME="attachments" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether, and how many, attachments a student is allowed to include with their response. -1 means unlimited."/>
<FIELD NAME="attachmentsrequired" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The number of attachments that should be required"/>
<FIELD NAME="graderinfo" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Information shown to people with permission to manually grade the question, when they are grading."/>
Expand Down
24 changes: 24 additions & 0 deletions question/type/essay/db/upgrade.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,29 @@ function xmldb_qtype_essay_upgrade($oldversion) {
// Automatically generated Moodle v3.10.0 release upgrade line.
// Put any upgrade step following this.

if ($oldversion < 2021011100) {

// Define field minwordlimit to be added to qtype_essay_options.
$table = new xmldb_table('qtype_essay_options');
$field = new xmldb_field('minwordlimit', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'responsefieldlines');

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

// Define field maxwordlimit to be added to qtype_essay_options.
$table = new xmldb_table('qtype_essay_options');
$field = new xmldb_field('maxwordlimit', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'minwordlimit');

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

// Essay savepoint reached.
upgrade_plugin_savepoint(true, 2021011100, 'qtype', 'essay');
}

return true;
}
66 changes: 61 additions & 5 deletions question/type/essay/edit_essay_form.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,34 @@ protected function definition_inner($mform) {
$mform->addElement('select', 'responserequired',
get_string('responserequired', 'qtype_essay'), $qtype->response_required_options());
$mform->setDefault('responserequired', 1);
$mform->disabledIf('responserequired', 'responseformat', 'eq', 'noinline');
$mform->hideIf('responserequired', 'responseformat', 'eq', 'noinline');

$mform->addElement('select', 'responsefieldlines',
get_string('responsefieldlines', 'qtype_essay'), $qtype->response_sizes());
$mform->setDefault('responsefieldlines', 15);
$mform->disabledIf('responsefieldlines', 'responseformat', 'eq', 'noinline');
$mform->hideIf('responsefieldlines', 'responseformat', 'eq', 'noinline');

// Create a text box that can be enabled/disabled for max/min word limits options.
$wordlimitoptions = ['size' => '6', 'maxlength' => '6'];
$mingrp[] = $mform->createElement('text', 'minwordlimit', '', $wordlimitoptions);
$mform->setType('minwordlimit', PARAM_INT);
$mingrp[] = $mform->createElement('checkbox', 'minwordenabled', '', get_string('enable'));
$mform->setDefault('minwordenabled', 0);
$mform->addGroup($mingrp, 'mingroup', get_string('minwordlimit', 'qtype_essay'), ' ', false);
$mform->addHelpButton('mingroup', 'minwordlimit', 'qtype_essay');
$mform->disabledIf('minwordlimit', 'minwordenabled', 'notchecked');
$mform->hideIf('mingroup', 'responserequired', 'eq', '0');
$mform->hideIf('mingroup', 'responseformat', 'eq', 'noinline');

$maxgrp[] = $mform->createElement('text', 'maxwordlimit', '', $wordlimitoptions);
$mform->setType('maxwordlimit', PARAM_INT);
$maxgrp[] = $mform->createElement('checkbox', 'maxwordenabled', '', get_string('enable'));
$mform->setDefault('maxwordenabled', 0);
$mform->addGroup($maxgrp, 'maxgroup', get_string('maxwordlimit', 'qtype_essay'), ' ', false);
$mform->addHelpButton('maxgroup', 'maxwordlimit', 'qtype_essay');
$mform->disabledIf('maxwordlimit', 'maxwordenabled', 'notchecked');
$mform->hideIf('maxgroup', 'responserequired', 'eq', '0');
$mform->hideIf('maxgroup', 'responseformat', 'eq', 'noinline');

$mform->addElement('select', 'attachments',
get_string('allowattachments', 'qtype_essay'), $qtype->attachment_options());
Expand All @@ -63,15 +85,15 @@ protected function definition_inner($mform) {
get_string('attachmentsrequired', 'qtype_essay'), $qtype->attachments_required_options());
$mform->setDefault('attachmentsrequired', 0);
$mform->addHelpButton('attachmentsrequired', 'attachmentsrequired', 'qtype_essay');
$mform->disabledIf('attachmentsrequired', 'attachments', 'eq', 0);
$mform->hideIf('attachmentsrequired', 'attachments', 'eq', 0);

$mform->addElement('filetypes', 'filetypeslist', get_string('acceptedfiletypes', 'qtype_essay'));
$mform->addHelpButton('filetypeslist', 'acceptedfiletypes', 'qtype_essay');
$mform->disabledIf('filetypeslist', 'attachments', 'eq', 0);
$mform->hideIf('filetypeslist', 'attachments', 'eq', 0);

$mform->addElement('select', 'maxbytes', get_string('maxbytes', 'qtype_essay'), $qtype->max_file_size_options());
$mform->setDefault('maxbytes', '0');
$mform->disabledIf('maxbytes', 'attachments', 'eq', 0);
$mform->hideIf('maxbytes', 'attachments', 'eq', 0);

$mform->addElement('header', 'responsetemplateheader', get_string('responsetemplateheader', 'qtype_essay'));
$mform->addElement('editor', 'responsetemplate', get_string('responsetemplate', 'qtype_essay'),
Expand All @@ -94,6 +116,10 @@ protected function data_preprocessing($question) {
$question->responseformat = $question->options->responseformat;
$question->responserequired = $question->options->responserequired;
$question->responsefieldlines = $question->options->responsefieldlines;
$question->minwordenabled = $question->options->minwordlimit ? 1 : 0;
$question->minwordlimit = $question->options->minwordlimit;
$question->maxwordenabled = $question->options->maxwordlimit ? 1 : 0;
$question->maxwordlimit = $question->options->maxwordlimit;
$question->attachments = $question->options->attachments;
$question->attachmentsrequired = $question->options->attachmentsrequired;
$question->filetypeslist = $question->options->filetypeslist;
Expand Down Expand Up @@ -142,6 +168,36 @@ public function validation($fromform, $files) {
$errors['attachmentsrequired'] = get_string('mustrequirefewer', 'qtype_essay');
}

if ($fromform['responserequired']) {
if (isset($fromform['minwordenabled'])) {
if (!is_numeric($fromform['minwordlimit'])) {
$errors['mingroup'] = get_string('err_numeric', 'form');
}
if ($fromform['minwordlimit'] < 0) {
$errors['mingroup'] = get_string('err_minwordlimitnegative', 'qtype_essay');
}
if (!$fromform['minwordlimit']) {
$errors['mingroup'] = get_string('err_minwordlimit', 'qtype_essay');
}
}
if (isset($fromform['maxwordenabled'])) {
if (!is_numeric($fromform['maxwordlimit'])) {
$errors['maxgroup'] = get_string('err_numeric', 'form');
}
if ($fromform['maxwordlimit'] < 0) {
$errors['maxgroup'] = get_string('err_maxwordlimitnegative', 'qtype_essay');
}
if (!$fromform['maxwordlimit']) {
$errors['maxgroup'] = get_string('err_maxwordlimit', 'qtype_essay');
}
}
if (isset($fromform['maxwordenabled']) && isset($fromform['minwordenabled'])) {
if ($fromform['maxwordlimit'] < $fromform['minwordlimit'] &&
$fromform['maxwordlimit'] > 0 && $fromform['minwordlimit'] > 0) {
$errors['maxgroup'] = get_string('err_maxminmismatch', 'qtype_essay');
}
}
}
return $errors;
}

Expand Down
14 changes: 14 additions & 0 deletions question/type/essay/lang/en/qtype_essay.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
$string['attachmentsoptional'] = 'Attachments are optional';
$string['attachmentsrequired'] = 'Require attachments';
$string['attachmentsrequired_help'] = 'This option specifies the minimum number of attachments required for a response to be considered gradable.';
$string['err_maxminmismatch'] = 'Maximum world limit must be greater than minimum word limit';
$string['err_maxwordlimit'] = 'Maximum word limit is enabled but is not set';
$string['err_maxwordlimitnegative'] = 'Maximum word limit cannot be a negative number';
$string['err_minwordlimit'] = 'Minimum word limit is enabled but is not set';
$string['err_minwordlimitnegative'] = 'Minimum word limit cannot be a negative number';
$string['formateditor'] = 'HTML editor';
$string['formateditorfilepicker'] = 'HTML editor with file picker';
$string['formatmonospaced'] = 'Plain text, monospaced font';
Expand All @@ -37,6 +42,12 @@
$string['graderinfo'] = 'Information for graders';
$string['graderinfoheader'] = 'Grader Information';
$string['maxbytes'] = 'Maximum file size';
$string['maxwordlimit'] = 'Maximum word limit';
$string['maxwordlimit_help'] = 'If the response requires that students enter text, this is the maximum number of words that each student will be allowed to submit.';
$string['maxwordlimitboundary'] = 'The word limit for this question is {$a->limit} words and you are attempting to submit {$a->count} words. Please shorten your response and try again.';
$string['minwordlimit'] = 'Minimum word limit';
$string['minwordlimit_help'] = 'If the response requires that students enter text, this is the minimum number of words that each student will be allowed to submit.';
$string['minwordlimitboundary'] = 'This question requires a response of at least {$a->limit} words and you are attempting to submit {$a->count} words. Please expand your response and try again.';
$string['mustattach'] = 'When "No online text" is selected, or responses are optional, you must allow at least one attachment.';
$string['mustrequire'] = 'When "No online text" is selected, or responses are optional, you must require at least one attachment.';
$string['mustrequirefewer'] = 'You cannot require more attachments than you allow.';
Expand All @@ -58,3 +69,6 @@
$string['responsetemplate'] = 'Response template';
$string['responsetemplateheader'] = 'Response Template';
$string['responsetemplate_help'] = 'Any text entered here will be displayed in the response input box when a new attempt at the question starts.';
$string['wordcount'] = 'Word count: {$a}';
$string['wordcounttoofew'] = 'Word count: {$a->count}, less than the required {$a->limit} words.';
$string['wordcounttoomuch'] = 'Word count: {$a->count}, more than the limit of {$a->limit} words.';
88 changes: 88 additions & 0 deletions question/type/essay/question.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ class qtype_essay_question extends question_with_responses {
public $responserequired;

public $responsefieldlines;

/** @var int indicates whether the minimum number of words required */
public $minwordlimit;

/** @var int indicates whether the maximum number of words required */
public $maxwordlimit;

public $attachments;

/** @var int maximum file size in bytes */
Expand Down Expand Up @@ -107,6 +114,13 @@ public function get_correct_response() {
public function is_complete_response(array $response) {
// Determine if the given response has online text and attachments.
$hasinlinetext = array_key_exists('answer', $response) && ($response['answer'] !== '');

// If there is a response and min/max word limit is set in the form then validate the number of words in response.
if ($hasinlinetext) {
if ($this->check_input_word_count($response['answer'])) {
return false;
}
}
$hasattachments = array_key_exists('attachments', $response)
&& $response['attachments'] instanceof question_response_files;

Expand Down Expand Up @@ -140,6 +154,20 @@ public function is_complete_response(array $response) {
return $hascontent && $meetsinlinereq && $meetsattachmentreq;
}

/**
* Return null if is_complete_response() returns true
* otherwise, return the minmax-limit error message
*
* @param array $response
* @return string
*/
public function get_validation_error(array $response) {
if ($this->is_complete_response($response)) {
return '';
}
return $this->check_input_word_count($response['answer']);
}

public function is_gradable_response(array $response) {
// Determine if the given response has online text and attachments.
if (array_key_exists('answer', $response) && ($response['answer'] !== '')) {
Expand Down Expand Up @@ -212,4 +240,64 @@ public function get_question_definition_for_external_rendering(question_attempt

return $settings;
}

/**
* Check the input word count and return a message to user
* when the number of words are outside the boundary settings.
*
* @param string $responsestring
* @return string|null
.*/
private function check_input_word_count($responsestring) {
if (!$this->responserequired) {
return null;
}
if (!$this->minwordlimit && !$this->maxwordlimit) {
// This question does not care about the word count.
return null;
}

// Count the number of words in the response string.
$count = count_words($responsestring);
if ($this->maxwordlimit && $count > $this->maxwordlimit) {
return get_string('maxwordlimitboundary', 'qtype_essay',
['limit' => $this->maxwordlimit, 'count' => $count]);
} else if ($count < $this->minwordlimit) {
return get_string('minwordlimitboundary', 'qtype_essay',
['limit' => $this->minwordlimit, 'count' => $count]);
} else {
return null;
}
}

/**
* If this question uses word counts, then return a display of the current
* count, and whether it is within limit, for when the question is being reviewed.
*
* @param array $response responses, as returned by
* {@see question_attempt_step::get_qt_data()}.
* @return string If relevant to this question, a display of the word count.
*/
public function get_word_count_message_for_review(array $response): string {
if (!$this->minwordlimit && !$this->maxwordlimit) {
// This question does not care about the word count.
return '';
}

if (!array_key_exists('answer', $response) || ($response['answer'] === '')) {
// No response.
return '';
}

$count = count_words($response['answer']);
if ($this->maxwordlimit && $count > $this->maxwordlimit) {
return get_string('wordcounttoomuch', 'qtype_essay',
['limit' => $this->maxwordlimit, 'count' => $count]);
} else if ($count < $this->minwordlimit) {
return get_string('wordcounttoofew', 'qtype_essay',
['limit' => $this->minwordlimit, 'count' => $count]);
} else {
return get_string('wordcount', 'qtype_essay', $count);
}
}
}
4 changes: 4 additions & 0 deletions question/type/essay/questiontype.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public function save_question_options($formdata) {
$options->responseformat = $formdata->responseformat;
$options->responserequired = $formdata->responserequired;
$options->responsefieldlines = $formdata->responsefieldlines;
$options->minwordlimit = isset($formdata->minwordenabled) ? $formdata->minwordlimit : 0;
$options->maxwordlimit = isset($formdata->maxwordenabled) ? $formdata->maxwordlimit : 0;
$options->attachments = $formdata->attachments;
$options->attachmentsrequired = $formdata->attachmentsrequired;
if (!isset($formdata->filetypeslist)) {
Expand All @@ -86,6 +88,8 @@ protected function initialise_question_instance(question_definition $question, $
$question->responseformat = $questiondata->options->responseformat;
$question->responserequired = $questiondata->options->responserequired;
$question->responsefieldlines = $questiondata->options->responsefieldlines;
$question->minwordlimit = $questiondata->options->minwordlimit;
$question->maxwordlimit = $questiondata->options->maxwordlimit;
$question->attachments = $questiondata->options->attachments;
$question->attachmentsrequired = $questiondata->options->attachmentsrequired;
$question->graderinfo = $questiondata->options->graderinfo;
Expand Down
Loading

0 comments on commit e07bba3

Please sign in to comment.