MDL-32523 Duplicate questions in question bank
authorM Kassaei <m.kassaei@open.ac.uk>
Mon, 4 Nov 2013 16:35:27 +0000 (16:35 +0000)
committerTim Hunt <T.J.Hunt@open.ac.uk>
Fri, 17 Jan 2014 10:54:12 +0000 (10:54 +0000)
lang/en/question.php
mod/quiz/editlib.php
question/editlib.php
question/question.php
question/tests/behat/copy_questions.feature [new file with mode: 0644]
question/type/edit_question_form.php

index d2923b1..15d32ad 100644 (file)
@@ -380,6 +380,7 @@ $string['questionbehavioursorder'] = 'Question behaviours order';
 $string['questionbehavioursorderexplained'] = 'Enter a comma separated list of behaviours in the order you want them to appear in dropdown menu';
 $string['questionidmismatch'] = 'Question ids mismatch';
 $string['questionname'] = 'Question name';
+$string['questionnamecopy'] = '{$a} (copy)';
 $string['questionpreviewdefaults'] = 'Question preview defaults';
 $string['questionpreviewdefaults_desc'] = 'These defaults are used when a user first previews a question in the question bank. Once a user has previewed a question, their personal preferences are stored as user preferences.';
 $string['questions'] = 'Questions';
index 13a4277..c3e6f82 100644 (file)
@@ -1136,7 +1136,7 @@ class quiz_question_bank_view extends question_bank_view {
 
     protected function wanted_columns() {
         return array('addtoquizaction', 'checkbox', 'qtype', 'questionnametext',
-                'editaction', 'previewaction');
+                'editaction', 'copyaction', 'previewaction');
     }
 
     /**
index 55c4e3c..b7fc4eb 100644 (file)
@@ -691,6 +691,35 @@ class question_bank_edit_action_column extends question_bank_action_column_base
     }
 }
 
+/**
+ * Question bank column for the duplicate action icon.
+ *
+ * @copyright  2013 The Open University
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class question_bank_copy_action_column extends question_bank_action_column_base {
+    /** @var string avoids repeated calls to get_string('duplicate'). */
+    protected $strcopy;
+
+    public function init() {
+        parent::init();
+        $this->strcopy = get_string('duplicate');
+    }
+
+    public function get_name() {
+        return 'copyaction';
+    }
+
+    protected function display_content($question, $rowclasses) {
+        // To copy a question, you need permission to add a question in the same
+        // category as the existing question, and ability to access the details of
+        // the question being copied.
+        if (question_has_capability_on($question, 'add') &&
+                (question_has_capability_on($question, 'edit') || question_has_capability_on($question, 'view'))) {
+            $this->print_icon('t/copy', $this->strcopy, $this->qbank->copy_question_url($question->id));
+        }
+    }
+}
 
 /**
  * Question bank columns for the preview action icon.
@@ -957,7 +986,7 @@ class question_bank_view {
     }
 
     protected function wanted_columns() {
-        $columns = array('checkbox', 'qtype', 'questionname', 'editaction',
+        $columns = array('checkbox', 'qtype', 'questionname', 'editaction', 'copyaction',
                 'previewaction', 'moveaction', 'deleteaction', 'creatorname',
                 'modifiername');
         if (question_get_display_preference('qbshowtext', 0, PARAM_BOOL, new moodle_url(''))) {
@@ -983,6 +1012,7 @@ class question_bank_view {
             new question_bank_creator_name_column($this),
             new question_bank_modifier_name_column($this),
             new question_bank_edit_action_column($this),
+            new question_bank_copy_action_column($this),
             new question_bank_preview_action_column($this),
             new question_bank_move_action_column($this),
             new question_bank_delete_action_column($this),
@@ -1253,6 +1283,15 @@ class question_bank_view {
         return $this->editquestionurl->out(true, array('id' => $questionid));
     }
 
+    /**
+     * Get the URL for duplicating a given question.
+     * @param int $questionid the question id.
+     * @return moodle_url the URL.
+     */
+    public function copy_question_url($questionid) {
+        return $this->editquestionurl->out(true, array('id' => $questionid, 'makecopy' => 1));
+    }
+
     public function move_question_url($questionid) {
         return $this->editquestionurl->out(true, array('id' => $questionid, 'movecontext' => 1));
     }
index 7577dc2..e5fe317 100644 (file)
@@ -31,6 +31,7 @@ require_once($CFG->libdir . '/formslib.php');
 
 // Read URL parameters telling us which question to edit.
 $id = optional_param('id', 0, PARAM_INT); // question id
+$makecopy = optional_param('makecopy', 0, PARAM_INT);
 $qtype = optional_param('qtype', '', PARAM_FILE);
 $categoryid = optional_param('category', 0, PARAM_INT);
 $cmid = optional_param('cmid', 0, PARAM_INT);
@@ -47,6 +48,9 @@ $url = new moodle_url('/question/question.php');
 if ($id !== 0) {
     $url->param('id', $id);
 }
+if ($makecopy !== 0) {
+    $url->param('makecopy', $makecopy);
+}
 if ($qtype !== '') {
     $url->param('qtype', $qtype);
 }
@@ -177,6 +181,10 @@ if ($id) {
         if (!$formeditable) {
             question_require_capability_on($question, 'view');
         }
+        if ($makecopy) {
+            // If we are duplicating a question, add some indication to the question name.
+            $question->name = get_string('questionnamecopy', 'question', $question->name);
+        }
     }
 
 } else  { // creating a new question
@@ -209,6 +217,7 @@ if ($formeditable && $id){
 $toform->appendqnumstring = $appendqnumstring;
 $toform->returnurl = $originalreturnurl;
 $toform->movecontext = $movecontext;
+$toform->makecopy = $makecopy;
 if ($cm !== null){
     $toform->cmid = $cm->id;
     $toform->courseid = $cm->course;
@@ -228,10 +237,10 @@ if ($mform->is_cancelled()) {
     }
 
 } else if ($fromform = $mform->get_data()) {
-    /// If we are saving as a copy, break the connection to the old question.
-    if (!empty($fromform->makecopy)) {
+    // If we are saving as a copy, break the connection to the old question.
+    if ($makecopy) {
         $question->id = 0;
-        $question->hidden = 0; // Copies should not be hidden
+        $question->hidden = 0; // Copies should not be hidden.
     }
 
     /// Process the combination of usecurrentcat, categorymoveto and category form
diff --git a/question/tests/behat/copy_questions.feature b/question/tests/behat/copy_questions.feature
new file mode 100644 (file)
index 0000000..5de7fa9
--- /dev/null
@@ -0,0 +1,40 @@
+@core @core_question
+Feature: A teacher can duplicate questions in the question bank
+  In order to reuse questions and modify duplicated questions
+  As a teacher
+  I need to duplicate questions
+
+  @javascript
+  Scenario: copy a previously created question
+    Given the following "users" exists:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | 1 | teacher1@asd.com |
+    And the following "courses" exists:
+      | fullname | shortname | format |
+      | Course 1 | C1 | weeks |
+    And the following "course enrolments" exists:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    And I log in as "admin"
+    And I follow "Course 1"
+    And I add a "Essay" question filling the form with:
+      | Question name | Test question to be copied |
+      | Question text | Write about whatever you want |
+    And I log out
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I follow "Question bank"
+    When I click on "Duplicate" "link" in the "Test question to be copied" "table_row"
+    And I fill the moodle form with:
+      | Question name | Duplicated question name |
+      | Question text | Write a lot about duplicating questions |
+    And I press "Save changes"
+    Then I should see "Duplicated question name"
+    And I should see "Test question to be copied"
+    And I should see "Teacher 1" in the ".categoryquestionscontainer tbody tr.r0 .creatorname" "css_element"
+    And I should see "Admin User" in the ".categoryquestionscontainer tbody tr.r1 .creatorname" "css_element"
+    And I click on "Duplicate" "link" in the "Duplicated question name" "table_row"
+    And the "Question name" field should match "Duplicated question name (copy)" value
+    And I press "Cancel"
+    Then I should see "Duplicated question name"
+    And I should see "Test question to be copied"
index a186eba..d458e40 100644 (file)
@@ -241,6 +241,9 @@ abstract class question_edit_form extends question_wizard_form {
         $mform->addElement('hidden', 'qtype');
         $mform->setType('qtype', PARAM_ALPHA);
 
+        $mform->addElement('hidden', 'makecopy');
+        $mform->setType('makecopy', PARAM_INT);
+
         $buttonarray = array();
         if (!empty($this->question->id)) {
             // Editing / moving question.
@@ -251,10 +254,6 @@ abstract class question_edit_form extends question_wizard_form {
                 $buttonarray[] = $mform->createElement('submit', 'submitbutton',
                         get_string('savechanges'));
             }
-            if ($this->question->formoptions->cansaveasnew) {
-                $buttonarray[] = $mform->createElement('submit', 'makecopy',
-                        get_string('makecopy', 'question'));
-            }
             $buttonarray[] = $mform->createElement('cancel');
         } else {
             // Adding new question.
@@ -361,7 +360,7 @@ abstract class question_edit_form extends question_wizard_form {
                                 array('rows' => 5), $this->editoroptions);
             $mform->setType($feedbackname, PARAM_RAW);
             // Using setValue() as setDefault() does not work for the editor class.
-            $element->setValue(array('text'=>get_string($feedbackname.'default', 'question')));
+            $element->setValue(array('text' => get_string($feedbackname.'default', 'question')));
 
             if ($withshownumpartscorrect && $feedbackname == 'partiallycorrectfeedback') {
                 $mform->addElement('advcheckbox', 'shownumcorrect',