MDL-63805 glossary: Glossary API refactor
authorJuan Leyva <juanleyvadelgado@gmail.com>
Mon, 28 Sep 2020 19:22:16 +0000 (21:22 +0200)
committerJuan Leyva <juanleyvadelgado@gmail.com>
Wed, 14 Oct 2020 10:56:43 +0000 (12:56 +0200)
mod/glossary/edit.php
mod/glossary/lib.php
mod/glossary/tests/lib_test.php

index 1e5461f..15d06e5 100644 (file)
@@ -38,23 +38,10 @@ if ($id) { // if entry is specified
         print_error('invalidentry');
     }
 
-    $ineditperiod = ((time() - $entry->timecreated <  $CFG->maxeditingtime) || $glossary->editalways);
-    if (!has_capability('mod/glossary:manageentries', $context) and !($entry->userid == $USER->id and ($ineditperiod and has_capability('mod/glossary:write', $context)))) {
-        if ($USER->id != $entry->userid) {
-            print_error('errcannoteditothers', 'glossary', "view.php?id=$cm->id&amp;mode=entry&amp;hook=$id");
-        } elseif (!$ineditperiod) {
-            print_error('erredittimeexpired', 'glossary', "view.php?id=$cm->id&amp;mode=entry&amp;hook=$id");
-        }
-    }
-
-    //prepare extra data
-    if ($aliases = $DB->get_records_menu("glossary_alias", array("entryid"=>$id), '', 'id, alias')) {
-        $entry->aliases = implode("\n", $aliases) . "\n";
-    }
-    if ($categoriesarr = $DB->get_records_menu("glossary_entries_categories", array('entryid'=>$id), '', 'id, categoryid')) {
-        // TODO: this fetches cats from both main and secondary glossary :-(
-        $entry->categories = array_values($categoriesarr);
-    }
+    // Check if the user can update the entry (trigger exception if he can't).
+    mod_glossary_can_update_entry($entry, $glossary, $context, $cm, false);
+    // Prepare extra data.
+    $entry = mod_glossary_prepare_entry_for_edition($entry);
 
 } else { // new entry
     require_capability('mod/glossary:write', $context);
index a89b01d..afae7fe 100644 (file)
@@ -4455,3 +4455,60 @@ function mod_glossary_delete_entry($entry, $glossary, $cm, $context, $course, $h
         \mod_glossary\local\concept_cache::reset_glossary($glossary);
     }
 }
+
+/**
+ * Checks if the current user can update the given glossary entry.
+ *
+ * @since Moodle 3.10
+ * @param stdClass $entry the entry database object
+ * @param stdClass $glossary the glossary database object
+ * @param stdClass $context the glossary context
+ * @param object $cm the course module object (cm record or cm_info instance)
+ * @param bool $return Whether to return a boolean value or stop the execution (exception)
+ * @return bool if the user can update the entry
+ * @throws moodle_exception
+ */
+function mod_glossary_can_update_entry(stdClass $entry, stdClass $glossary, stdClass $context, object $cm,
+        bool $return = true): bool {
+
+    global $USER, $CFG;
+
+    $ineditperiod = ((time() - $entry->timecreated < $CFG->maxeditingtime) || $glossary->editalways);
+    if (!has_capability('mod/glossary:manageentries', $context) and
+            !($entry->userid == $USER->id and ($ineditperiod and has_capability('mod/glossary:write', $context)))) {
+
+        if ($USER->id != $entry->userid) {
+            if ($return) {
+                return false;
+            }
+            throw new moodle_exception('errcannoteditothers', 'glossary', "view.php?id=$cm->id&amp;mode=entry&amp;hook=$entry->id");
+        } else if (!$ineditperiod) {
+            if ($return) {
+                return false;
+            }
+            throw new moodle_exception('erredittimeexpired', 'glossary', "view.php?id=$cm->id&amp;mode=entry&amp;hook=$entry->id");
+        }
+    }
+
+    return true;
+}
+
+/**
+ * Prepares an entry for editing, adding aliases and category information.
+ *
+ * @param  stdClass $entry the entry being edited
+ * @return stdClass the entry with the additional data
+ */
+function mod_glossary_prepare_entry_for_edition(stdClass $entry): stdClass {
+    global $DB;
+
+    if ($aliases = $DB->get_records_menu("glossary_alias", ["entryid" => $entry->id], '', 'id, alias')) {
+        $entry->aliases = implode("\n", $aliases) . "\n";
+    }
+    if ($categoriesarr = $DB->get_records_menu("glossary_entries_categories", ['entryid' => $entry->id], '', 'id, categoryid')) {
+        // TODO: this fetches cats from both main and secondary glossary :-(
+        $entry->categories = array_values($categoriesarr);
+    }
+
+    return $entry;
+}
index 74353eb..24b0811 100644 (file)
@@ -670,4 +670,100 @@ class mod_glossary_lib_testcase extends advanced_testcase {
         // Tags.
         $this->assertEmpty(core_tag_tag::get_by_name(0, 'Cats'));
     }
+
+    public function test_mod_glossary_can_update_entry_users() {
+        $this->resetAfterTest();
+
+        // Create required data.
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $anotherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
+        $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id));
+
+        $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
+        $this->setUser($student);
+        $entry = $gg->create_content($glossary);
+        $context = context_module::instance($glossary->cmid);
+        $cm = get_coursemodule_from_instance('glossary', $glossary->id);
+
+        // Test student can update.
+        $this->assertTrue(mod_glossary_can_update_entry($entry, $glossary, $context, $cm));
+
+        // Test teacher can update.
+        $this->setUser($teacher);
+        $this->assertTrue(mod_glossary_can_update_entry($entry, $glossary, $context, $cm));
+
+        // Test admin can update.
+        $this->setAdminUser();
+        $this->assertTrue(mod_glossary_can_update_entry($entry, $glossary, $context, $cm));
+
+        // Test a different student is not able to update.
+        $this->setUser($anotherstudent);
+        $this->assertFalse(mod_glossary_can_update_entry($entry, $glossary, $context, $cm));
+
+        // Test exception.
+        $this->expectExceptionMessage(get_string('errcannoteditothers', 'glossary'));
+        mod_glossary_can_update_entry($entry, $glossary, $context, $cm, false);
+    }
+
+    public function test_mod_glossary_can_update_entry_edit_period() {
+        global $CFG;
+        $this->resetAfterTest();
+
+        // Create required data.
+        $course = $this->getDataGenerator()->create_course();
+        $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+        $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id, 'editalways' => 1));
+
+        $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
+        $this->setUser($student);
+        $entry = $gg->create_content($glossary);
+        $context = context_module::instance($glossary->cmid);
+        $cm = get_coursemodule_from_instance('glossary', $glossary->id);
+
+        // Test student can always update when edit always is set to 1.
+        $entry->timecreated = time() - 2 * $CFG->maxeditingtime;
+        $this->assertTrue(mod_glossary_can_update_entry($entry, $glossary, $context, $cm));
+
+        // Test student cannot update old entries when edit always is set to 0.
+        $glossary->editalways = 0;
+        $this->assertFalse(mod_glossary_can_update_entry($entry, $glossary, $context, $cm));
+
+        // Test student can update recent entries when edit always is set to 0.
+        $entry->timecreated = time();
+        $this->assertTrue(mod_glossary_can_update_entry($entry, $glossary, $context, $cm));
+
+        // Check exception.
+        $entry->timecreated = time() - 2 * $CFG->maxeditingtime;
+        $this->expectExceptionMessage(get_string('erredittimeexpired', 'glossary'));
+        mod_glossary_can_update_entry($entry, $glossary, $context, $cm, false);
+    }
+
+    public function test_prepare_entry_for_edition() {
+        global $USER;
+        $this->resetAfterTest(true);
+
+        $course = $this->getDataGenerator()->create_course();
+        $glossary = $this->getDataGenerator()->create_module('glossary', ['course' => $course->id]);
+        $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
+
+        $this->setAdminUser();
+        $aliases = ['alias1', 'alias2'];
+        $entry = $gg->create_content(
+            $glossary,
+            ['approved' => 1, 'userid' => $USER->id],
+            $aliases
+        );
+
+        $cat1 = $gg->create_category($glossary, [], [$entry]);
+        $gg->create_category($glossary);
+
+        $entry = mod_glossary_prepare_entry_for_edition($entry);
+        $this->assertCount(1, $entry->categories);
+        $this->assertEquals($cat1->id, $entry->categories[0]);
+        $returnedaliases = array_values(explode("\n", trim($entry->aliases)));
+        sort($returnedaliases);
+        $this->assertEquals($aliases, $returnedaliases);
+    }
 }