MDL-61364 question: add support for course tags on modal
authorSimey Lameze <simey@moodle.com>
Mon, 26 Mar 2018 03:24:50 +0000 (11:24 +0800)
committerSimey Lameze <simey@moodle.com>
Mon, 26 Mar 2018 03:24:50 +0000 (11:24 +0800)
question/amd/build/edit_tags.min.js
question/amd/build/repository.min.js
question/amd/src/edit_tags.js
question/amd/src/repository.js
question/classes/bank/tags_action_column.php
question/classes/external.php
question/lib.php
question/type/tags_form.php

index cb3dc19..f452866 100644 (file)
Binary files a/question/amd/build/edit_tags.min.js and b/question/amd/build/edit_tags.min.js differ
index 35de00b..b86aedc 100644 (file)
Binary files a/question/amd/build/repository.min.js and b/question/amd/build/repository.min.js differ
index 6bfabe0..f4aabc1 100644 (file)
@@ -98,6 +98,46 @@ define([
         loadingIconContainer.addClass('hidden');
     };
 
         loadingIconContainer.addClass('hidden');
     };
 
+    /**
+     * Set the context Id data attribute on the modal.
+     *
+     * @param {Promise} modal The modal promise.
+     * @param {int} contextId The context id.
+     */
+    var setContextId = function(modal, contextId) {
+        modal.getBody().attr('data-contextid', contextId);
+    };
+
+    /**
+     * Get the context Id data attribute value from the modal body.
+     *
+     * @param {Promise} modal The modal promise.
+     * @return {int} The context id.
+     */
+    var getContextId = function(modal) {
+        return modal.getBody().data('contextid');
+    };
+
+    /**
+     * Set the question Id data attribute on the modal.
+     *
+     * @param {Promise} modal The modal promise.
+     * @param {int} questionId The question Id.
+     */
+    var setQuestionId = function(modal, questionId) {
+        modal.getBody().attr('data-questionid', questionId);
+    };
+
+    /**
+     * Get the question Id data attribute value from the modal body.
+     *
+     * @param {Promise} modal The modal promise.
+     * @return {int} The question Id.
+     */
+    var getQuestionId = function(modal) {
+        return modal.getBody().data('questionid');
+    };
+
     /**
      * Register event listeners for the module.
      *
     /**
      * Register event listeners for the module.
      *
@@ -186,6 +226,9 @@ define([
                     modal.getRoot().find(QuestionSelectors.actions.save).hide();
                 }
 
                     modal.getRoot().find(QuestionSelectors.actions.save).hide();
                 }
 
+                setQuestionId(modal, questionId);
+                setContextId(modal, contextId);
+
                 return modal;
             }).fail(Notification.exception);
 
                 return modal;
             }).fail(Notification.exception);
 
@@ -207,9 +250,11 @@ define([
         startLoading(root);
 
         var formData = getFormData(modal);
         startLoading(root);
 
         var formData = getFormData(modal);
+        var questionId = getQuestionId(modal);
+        var contextId = getContextId(modal);
 
         // Send the form data to the server for processing.
 
         // Send the form data to the server for processing.
-        return Repository.submitTagCreateUpdateForm(formData)
+        return Repository.submitTagCreateUpdateForm(questionId, contextId, formData)
             .always(function() {
                 // Regardless of success or error we should always stop
                 // the loading icon and re-enable the buttons.
             .always(function() {
                 // Regardless of success or error we should always stop
                 // the loading icon and re-enable the buttons.
index 42e7272..6848577 100644 (file)
@@ -31,10 +31,12 @@ define(['jquery', 'core/ajax'], function($, Ajax) {
      * @param {string} formdata The URL encoded values from the form
      * @return {promise}
      */
      * @param {string} formdata The URL encoded values from the form
      * @return {promise}
      */
-    var submitTagCreateUpdateForm = function(formdata) {
+    var submitTagCreateUpdateForm = function(questionId, contextId, formdata) {
         var request = {
             methodname: 'core_question_submit_tags_form',
             args: {
         var request = {
             methodname: 'core_question_submit_tags_form',
             args: {
+                questionid: questionId,
+                contextid: contextId,
                 formdata: formdata
             }
         };
                 formdata: formdata
             }
         };
index 7ff372b..79a7cbc 100644 (file)
@@ -56,10 +56,11 @@ class tags_action_column extends action_column_base {
                 question_has_capability_on($question, 'view')) {
 
             $cantag = question_has_capability_on($question, 'tag');
                 question_has_capability_on($question, 'view')) {
 
             $cantag = question_has_capability_on($question, 'tag');
-            $category = $DB->get_record('question_categories', ['id' => $question->category], 'contextid');
-            $url = $this->qbank->edit_question_url($question->id);
+            $qbank = $this->qbank;
+            $url = $qbank->edit_question_url($question->id);
+            $editingcontext = $qbank->get_most_specific_context();
 
 
-            $this->print_tag_icon($question->id, $url, $cantag, $category->contextid);
+            $this->print_tag_icon($question->id, $url, $cantag, $editingcontext->id);
         }
     }
 
         }
     }
 
index ecc4876..f2011d4 100644 (file)
@@ -122,6 +122,8 @@ class core_question_external extends external_api {
      */
     public static function submit_tags_form_parameters() {
         return new external_function_parameters([
      */
     public static function submit_tags_form_parameters() {
         return new external_function_parameters([
+                'questionid' => new external_value(PARAM_INT, 'The question id'),
+                'contextid' => new external_value(PARAM_INT, 'The editing context id'),
                 'formdata' => new external_value(PARAM_RAW, 'The data from the tag form'),
         ]);
     }
                 'formdata' => new external_value(PARAM_RAW, 'The data from the tag form'),
         ]);
     }
@@ -129,51 +131,67 @@ class core_question_external extends external_api {
     /**
      * Handles the tags form submission.
      *
     /**
      * Handles the tags form submission.
      *
+     * @param int $questionid The question id.
+     * @param int $contextid The editing context id.
      * @param string $formdata The question tag form data in a URI encoded param string
      * @return array The created or modified question tag
      * @param string $formdata The question tag form data in a URI encoded param string
      * @return array The created or modified question tag
-     * @throws moodle_exception
      */
      */
-    public static function submit_tags_form($formdata) {
-        global $USER, $DB, $CFG;
+    public static function submit_tags_form($questionid, $contextid, $formdata) {
+        global $DB, $CFG;
 
         $data = [];
         $result = ['status' => false];
 
         // Parameter validation.
 
         $data = [];
         $result = ['status' => false];
 
         // Parameter validation.
-        $params = self::validate_parameters(self::submit_tags_form_parameters(), ['formdata' => $formdata]);
-        $context = \context_user::instance($USER->id);
+        $params = self::validate_parameters(self::submit_tags_form_parameters(), [
+            'questionid' => $questionid,
+            'contextid' => $contextid,
+            'formdata' => $formdata
+        ]);
 
 
-        self::validate_context($context);
+        $editingcontext = \context::instance_by_id($contextid);
+        self::validate_context($editingcontext);
         parse_str($params['formdata'], $data);
 
         parse_str($params['formdata'], $data);
 
-        if (!empty($data['id'])) {
-            $questionid = clean_param($data['id'], PARAM_INT);
-            $question = $DB->get_record('question', array('id' => $questionid));
+        if (!$question = $DB->get_record_sql('
+                SELECT q.*, qc.contextid
+                FROM {question} q
+                JOIN {question_categories} qc ON qc.id = q.category
+                WHERE q.id = ?', [$questionid])) {
+            print_error('questiondoesnotexist', 'question');
+        }
+
+        require_once($CFG->libdir . '/questionlib.php');
+        require_once($CFG->dirroot . '/question/type/tags_form.php');
 
 
-            require_once($CFG->libdir . '/questionlib.php');
-            $cantag = question_has_capability_on($question, 'tag');
+        $cantag = question_has_capability_on($question, 'tag');
+        $questioncontext = \context::instance_by_id($question->contextid);
+        $formoptions = [
+            'editingcontext' => $editingcontext,
+            'questioncontext' => $questioncontext
+        ];
 
 
-            require_once($CFG->dirroot . '/question/type/tags_form.php');
-            $mform = new \core_question\form\tags(null, null, 'post', '', null, $cantag, $data);
+        $mform = new \core_question\form\tags(null, $formoptions, 'post', '', null, $cantag, $data);
 
 
-            if ($validateddata = $mform->get_data()) {
-                // Due to a mform bug, if there's no tags set on the tag element, it submits the name as the value.
-                // The only way to discover is checking if the tag element is an array.
-                if ($cantag) {
-                    if (is_array($validateddata->tags)) {
-                        $categorycontext = context::instance_by_id($validateddata->contextid);
+        if ($validateddata = $mform->get_data()) {
+            if ($cantag) {
+                if (isset($validateddata->tags)) {
+                    // Due to a mform bug, if there's no tags set on the tag element, it submits the name as the value.
+                    // The only way to discover is checking if the tag element is an array.
+                    $tags = is_array($validateddata->tags) ? $validateddata->tags : [];
 
 
-                        core_tag_tag::set_item_tags('core_question', 'question', $validateddata->id,
-                            $categorycontext, $validateddata->tags);
+                    core_tag_tag::set_item_tags('core_question', 'question', $validateddata->id,
+                        $questioncontext, $tags);
+
+                    $result['status'] = true;
+                }
 
 
-                        $result['status'] = true;
-                    } else {
-                        // If the tags element is not array, this means we don't have any tags to be set.
-                        // This is the only way to assume the user removed all tags from the question.
-                        core_tag_tag::remove_all_item_tags('core_question', 'question', $validateddata->id);
+                if (isset($validateddata->coursetags)) {
+                    $coursetags = is_array($validateddata->coursetags) ? $validateddata->coursetags : [];
+                    core_tag_tag::set_item_tags('core_question', 'question', $validateddata->id,
+                        $editingcontext->get_course_context(false), $coursetags);
 
 
-                        $result['status'] = true;
-                    }
+                    $result['status'] = true;
                 }
             }
         }
                 }
             }
         }
index 842e050..5a731c4 100644 (file)
@@ -41,26 +41,42 @@ function core_question_output_fragment_tags_form($args) {
         require_once($CFG->dirroot . '/question/type/tags_form.php');
         require_once($CFG->libdir . '/questionlib.php');
         $id = clean_param($args['id'], PARAM_INT);
         require_once($CFG->dirroot . '/question/type/tags_form.php');
         require_once($CFG->libdir . '/questionlib.php');
         $id = clean_param($args['id'], PARAM_INT);
+        $editingcontext = $args['context'];
 
         $question = $DB->get_record('question', ['id' => $id]);
 
         $question = $DB->get_record('question', ['id' => $id]);
-        $category = $DB->get_record('question_categories', array('id' => $question->category));
-        $context = \context::instance_by_id($category->contextid);
 
 
-        $toform = new stdClass();
-        $toform->id = $question->id;
-        $toform->questioncategory = $category->name;
-        $toform->questionname = $question->name;
-        $toform->categoryid = $category->id;
-        $toform->contextid = $category->contextid;
-        $toform->context = $context->get_context_name();
-
-        if (core_tag_tag::is_enabled('core_question', 'question')) {
-            $toform->tags = core_tag_tag::get_item_tags_array('core_question', 'question', $question->id);
+        if ($coursecontext = $editingcontext->get_course_context(false)) {
+            $course = $DB->get_record('course', ['id' => $coursecontext->instanceid]);
+            $filtercourses = [$course];
+        } else {
+            $filtercourses = null;
         }
 
         }
 
+        // Load the question tags and filter the course tags by the current
+        // course.
+        get_question_options($question, true, $filtercourses);
+
+        $category = $question->categoryobject;
+        $questioncontext = \context::instance_by_id($category->contextid);
+
+        $formoptions = [
+            'editingcontext' => $editingcontext,
+            'questioncontext' => $questioncontext
+        ];
+        $data = [
+            'id' => $question->id,
+            'questioncategory' => $category->name,
+            'questionname' => $question->name,
+            'categoryid' => $category->id,
+            'contextid' => $category->contextid,
+            'context' => $questioncontext->get_context_name(),
+            'tags' => isset($question->tags) ? $question->tags : [],
+            'coursetags' => isset($question->coursetags) ? $question->coursetags : [],
+        ];
+
         $cantag = question_has_capability_on($question, 'tag');
         $cantag = question_has_capability_on($question, 'tag');
-        $mform = new \core_question\form\tags(null, null, 'post', '', null, $cantag, $toform);
-        $mform->set_data($toform);
+        $mform = new \core_question\form\tags(null, $formoptions, 'post', '', null, $cantag, $data);
+        $mform->set_data($data);
 
         return $mform->render();
     }
 
         return $mform->render();
     }
index a3af411..bcc2fc5 100644 (file)
@@ -41,6 +41,8 @@ class tags extends \moodleform {
      */
     public function definition() {
         $mform = $this->_form;
      */
     public function definition() {
         $mform = $this->_form;
+        $customdata = $this->_customdata;
+
         $mform->disable_form_change_checker();
 
         $mform->addElement('hidden', 'id');
         $mform->disable_form_change_checker();
 
         $mform->addElement('hidden', 'id');
@@ -56,7 +58,29 @@ class tags extends \moodleform {
         $mform->addElement('static', 'questioncategory', get_string('categorycurrent', 'question'));
         $mform->addElement('static', 'context', '');
 
         $mform->addElement('static', 'questioncategory', get_string('categorycurrent', 'question'));
         $mform->addElement('static', 'context', '');
 
-        $mform->addElement('tags', 'tags', get_string('tags'),
-                ['itemtype' => 'question', 'component' => 'core_question']);
+        if (\core_tag_tag::is_enabled('core_question', 'question')) {
+            $mform->addElement('tags', 'tags', get_string('tags'),
+                    ['itemtype' => 'question', 'component' => 'core_question']);
+
+            // Is the question category in a course context?
+            $qcontext = $customdata['questioncontext'];
+            $qcoursecontext = $qcontext->get_course_context(false);
+            $iscourseoractivityquestion = !empty($qcoursecontext);
+            // Is the current context we're editing in a course context?
+            $editingcontext = $customdata['editingcontext'];
+            $editingcoursecontext = $editingcontext->get_course_context(false);
+            $iseditingcontextcourseoractivity = !empty($editingcoursecontext);
+
+            if ($iseditingcontextcourseoractivity && !$iscourseoractivityquestion) {
+                // If the question is being edited in a course or activity context
+                // and the question isn't a course or activity level question then
+                // allow course tags to be added to the course.
+                $coursetagheader = get_string('questionformtagheader', 'core_question',
+                    $editingcoursecontext->get_context_name(true));
+                $mform->addElement('tags', 'coursetags', $coursetagheader,
+                        array('itemtype' => 'question', 'component' => 'core_question'));
+
+            }
+        }
     }
 }
     }
 }