Ejemplo n.º 1
0
 /**
  * Test ampersands.
  */
 public function test_ampersands()
 {
     global $CFG;
     $this->resetAfterTest(true);
     // Enable glossary filter at top level.
     filter_set_global_state('glossary', TEXTFILTER_ON);
     $CFG->glossary_linkentries = 1;
     // Create a test course.
     $course = $this->getDataGenerator()->create_course();
     $context = context_course::instance($course->id);
     // Create a glossary.
     $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id, 'mainglossary' => 1));
     // Create two entries with ampersands and one normal entry.
     /** @var mod_glossary_generator $generator */
     $generator = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
     $normal = $generator->create_content($glossary, array('concept' => 'normal'));
     $amp1 = $generator->create_content($glossary, array('concept' => 'A&B'));
     $amp2 = $generator->create_content($glossary, array('concept' => 'C&D'));
     filter_manager::reset_caches();
     \mod_glossary\local\concept_cache::reset_caches();
     // Format text with all three entries in HTML.
     $html = '<p>A&amp;B C&amp;D normal</p>';
     $filtered = format_text($html, FORMAT_HTML, array('context' => $context));
     // Find all the glossary links in the result.
     $matches = array();
     preg_match_all('~eid=([0-9]+).*?title="(.*?)"~', $filtered, $matches);
     // There should be 3 glossary links.
     $this->assertEquals(3, count($matches[1]));
     $this->assertEquals($amp1->id, $matches[1][0]);
     $this->assertEquals($amp2->id, $matches[1][1]);
     $this->assertEquals($normal->id, $matches[1][2]);
     // Check text and escaping of title attribute.
     $this->assertEquals($glossary->name . ': A&amp;B', $matches[2][0]);
     $this->assertEquals($glossary->name . ': C&amp;D', $matches[2][1]);
     $this->assertEquals($glossary->name . ': normal', $matches[2][2]);
 }
Ejemplo n.º 2
0
$context = context_module::instance($cm->id);
require_capability('mod/glossary:approve', $context);
if ($newstate != $entry->approved && confirm_sesskey()) {
    $newentry = new stdClass();
    $newentry->id = $entry->id;
    $newentry->approved = $newstate;
    $newentry->timemodified = time();
    // wee need this date here to speed up recent activity, TODO: use timestamp in approved field instead in 2.0
    $DB->update_record("glossary_entries", $newentry);
    // Trigger event about entry approval/disapproval.
    $params = array('context' => $context, 'objectid' => $entry->id);
    if ($newstate) {
        $event = \mod_glossary\event\entry_approved::create($params);
    } else {
        $event = \mod_glossary\event\entry_disapproved::create($params);
    }
    $entry->approved = $newstate ? 1 : 0;
    $entry->timemodified = $newentry->timemodified;
    $event->add_record_snapshot('glossary_entries', $entry);
    $event->trigger();
    // Update completion state
    $completion = new completion_info($course);
    if ($completion->is_enabled($cm) == COMPLETION_TRACKING_AUTOMATIC && $glossary->completionentries) {
        $completion->update_state($cm, COMPLETION_COMPLETE, $entry->userid);
    }
    // Reset caches.
    if ($entry->usedynalink) {
        \mod_glossary\local\concept_cache::reset_glossary($glossary);
    }
}
redirect("view.php?id={$cm->id}&amp;mode={$mode}&amp;hook={$hook}");
Ejemplo n.º 3
0
Archivo: lib.php Proyecto: ruddj/moodle
/**
 * Given an ID of an instance of this module,
 * this function will permanently delete the instance
 * and any data that depends on it.
 *
 * @global object
 * @param int $id glossary id
 * @return bool success
 */
function glossary_delete_instance($id) {
    global $DB, $CFG;

    if (!$glossary = $DB->get_record('glossary', array('id'=>$id))) {
        return false;
    }

    if (!$cm = get_coursemodule_from_instance('glossary', $id)) {
        return false;
    }

    if (!$context = context_module::instance($cm->id, IGNORE_MISSING)) {
        return false;
    }

    $fs = get_file_storage();

    if ($glossary->mainglossary) {
        // unexport entries
        $sql = "SELECT ge.id, ge.sourceglossaryid, cm.id AS sourcecmid
                  FROM {glossary_entries} ge
                  JOIN {modules} m ON m.name = 'glossary'
                  JOIN {course_modules} cm ON (cm.module = m.id AND cm.instance = ge.sourceglossaryid)
                 WHERE ge.glossaryid = ? AND ge.sourceglossaryid > 0";

        if ($exported = $DB->get_records_sql($sql, array($id))) {
            foreach ($exported as $entry) {
                $entry->glossaryid = $entry->sourceglossaryid;
                $entry->sourceglossaryid = 0;
                $newcontext = context_module::instance($entry->sourcecmid);
                if ($oldfiles = $fs->get_area_files($context->id, 'mod_glossary', 'attachment', $entry->id)) {
                    foreach ($oldfiles as $oldfile) {
                        $file_record = new stdClass();
                        $file_record->contextid = $newcontext->id;
                        $fs->create_file_from_storedfile($file_record, $oldfile);
                    }
                    $fs->delete_area_files($context->id, 'mod_glossary', 'attachment', $entry->id);
                    $entry->attachment = '1';
                } else {
                    $entry->attachment = '0';
                }
                $DB->update_record('glossary_entries', $entry);
            }
        }
    } else {
        // move exported entries to main glossary
        $sql = "UPDATE {glossary_entries}
                   SET sourceglossaryid = 0
                 WHERE sourceglossaryid = ?";
        $DB->execute($sql, array($id));
    }

    // Delete any dependent records
    $entry_select = "SELECT id FROM {glossary_entries} WHERE glossaryid = ?";
    $DB->delete_records_select('comments', "contextid=? AND commentarea=? AND itemid IN ($entry_select)", array($id, 'glossary_entry', $context->id));
    $DB->delete_records_select('glossary_alias',    "entryid IN ($entry_select)", array($id));

    $category_select = "SELECT id FROM {glossary_categories} WHERE glossaryid = ?";
    $DB->delete_records_select('glossary_entries_categories', "categoryid IN ($category_select)", array($id));
    $DB->delete_records('glossary_categories', array('glossaryid'=>$id));
    $DB->delete_records('glossary_entries', array('glossaryid'=>$id));

    // delete all files
    $fs->delete_area_files($context->id);

    glossary_grade_item_delete($glossary);

    $DB->delete_records('glossary', array('id'=>$id));

    // Reset caches.
    \mod_glossary\local\concept_cache::reset_glossary($glossary);

    return true;
}
Ejemplo n.º 4
0
/**
 * Creates or updates a glossary entry
 *
 * @param  stdClass $entry entry data
 * @param  stdClass $course course object
 * @param  stdClass $cm course module object
 * @param  stdClass $glossary glossary object
 * @param  stdClass $context context object
 * @return stdClass the complete new or updated entry
 * @since  Moodle 3.2
 */
function glossary_edit_entry($entry, $course, $cm, $glossary, $context) {
    global $DB, $USER;

    list($definitionoptions, $attachmentoptions) = glossary_get_editor_and_attachment_options($course, $context, $entry);

    $timenow = time();

    $categories = empty($entry->categories) ? array() : $entry->categories;
    unset($entry->categories);
    $aliases = trim($entry->aliases);
    unset($entry->aliases);

    if (empty($entry->id)) {
        $entry->glossaryid       = $glossary->id;
        $entry->timecreated      = $timenow;
        $entry->userid           = $USER->id;
        $entry->timecreated      = $timenow;
        $entry->sourceglossaryid = 0;
        $entry->teacherentry     = has_capability('mod/glossary:manageentries', $context);
        $isnewentry              = true;
    } else {
        $isnewentry              = false;
    }

    $entry->concept          = trim($entry->concept);
    $entry->definition       = '';          // Updated later.
    $entry->definitionformat = FORMAT_HTML; // Updated later.
    $entry->definitiontrust  = 0;           // Updated later.
    $entry->timemodified     = $timenow;
    $entry->approved         = 0;
    $entry->usedynalink      = isset($entry->usedynalink) ? $entry->usedynalink : 0;
    $entry->casesensitive    = isset($entry->casesensitive) ? $entry->casesensitive : 0;
    $entry->fullmatch        = isset($entry->fullmatch) ? $entry->fullmatch : 0;

    if ($glossary->defaultapproval or has_capability('mod/glossary:approve', $context)) {
        $entry->approved = 1;
    }

    if ($isnewentry) {
        // Add new entry.
        $entry->id = $DB->insert_record('glossary_entries', $entry);
    } else {
        // Update existing entry.
        $DB->update_record('glossary_entries', $entry);
    }

    // Save and relink embedded images and save attachments.
    if (!empty($entry->definition_editor)) {
        $entry = file_postupdate_standard_editor($entry, 'definition', $definitionoptions, $context, 'mod_glossary', 'entry',
            $entry->id);
    }
    if (!empty($entry->attachment_filemanager)) {
        $entry = file_postupdate_standard_filemanager($entry, 'attachment', $attachmentoptions, $context, 'mod_glossary',
            'attachment', $entry->id);
    }

    // Store the updated value values.
    $DB->update_record('glossary_entries', $entry);

    // Refetch complete entry.
    $entry = $DB->get_record('glossary_entries', array('id' => $entry->id));

    // Update entry categories.
    $DB->delete_records('glossary_entries_categories', array('entryid' => $entry->id));
    // TODO: this deletes cats from both both main and secondary glossary :-(.
    if (!empty($categories) and array_search(0, $categories) === false) {
        foreach ($categories as $catid) {
            $newcategory = new stdClass();
            $newcategory->entryid    = $entry->id;
            $newcategory->categoryid = $catid;
            $DB->insert_record('glossary_entries_categories', $newcategory, false);
        }
    }

    // Update aliases.
    $DB->delete_records('glossary_alias', array('entryid' => $entry->id));
    if ($aliases !== '') {
        $aliases = explode("\n", $aliases);
        foreach ($aliases as $alias) {
            $alias = trim($alias);
            if ($alias !== '') {
                $newalias = new stdClass();
                $newalias->entryid = $entry->id;
                $newalias->alias   = $alias;
                $DB->insert_record('glossary_alias', $newalias, false);
            }
        }
    }

    // Trigger event and update completion (if entry was created).
    $eventparams = array(
        'context' => $context,
        'objectid' => $entry->id,
        'other' => array('concept' => $entry->concept)
    );
    if ($isnewentry) {
        $event = \mod_glossary\event\entry_created::create($eventparams);
    } else {
        $event = \mod_glossary\event\entry_updated::create($eventparams);
    }
    $event->add_record_snapshot('glossary_entries', $entry);
    $event->trigger();
    if ($isnewentry) {
        // Update completion state.
        $completion = new completion_info($course);
        if ($completion->is_enabled($cm) == COMPLETION_TRACKING_AUTOMATIC && $glossary->completionentries && $entry->approved) {
            $completion->update_state($cm, COMPLETION_COMPLETE);
        }
    }

    // Reset caches.
    if ($isnewentry) {
        if ($entry->usedynalink and $entry->approved) {
            \mod_glossary\local\concept_cache::reset_glossary($glossary);
        }
    } else {
        // So many things may affect the linking, let's just purge the cache always on edit.
        \mod_glossary\local\concept_cache::reset_glossary($glossary);
    }
    return $entry;
}
Ejemplo n.º 5
0
 public function filter($text, array $options = array())
 {
     global $CFG, $USER, $GLOSSARY_EXCLUDEENTRY;
     // Try to get current course.
     $coursectx = $this->context->get_course_context(false);
     if (!$coursectx) {
         // Only global glossaries will be linked.
         $courseid = 0;
     } else {
         $courseid = $coursectx->instanceid;
     }
     if ($this->cachecourseid != $courseid or $this->cacheuserid != $USER->id) {
         // Invalidate the page cache.
         $this->cacheconceptlist = null;
     }
     if (is_array($this->cacheconceptlist) and empty($GLOSSARY_EXCLUDEENTRY)) {
         if (empty($this->cacheconceptlist)) {
             return $text;
         }
         return filter_phrases($text, $this->cacheconceptlist);
     }
     list($glossaries, $allconcepts) = \mod_glossary\local\concept_cache::get_concepts($courseid);
     if (!$allconcepts) {
         $this->cacheuserid = $USER->id;
         $this->cachecourseid = $courseid;
         $this->cacheconcepts = array();
         return $text;
     }
     $strcategory = get_string('category', 'glossary');
     $conceptlist = array();
     $excluded = false;
     foreach ($allconcepts as $concepts) {
         foreach ($concepts as $concept) {
             if (!empty($GLOSSARY_EXCLUDEENTRY) and $concept->id == $GLOSSARY_EXCLUDEENTRY) {
                 $excluded = true;
                 continue;
             }
             if ($concept->category) {
                 // Link to a category.
                 // TODO: Fix this string usage.
                 $title = $glossaries[$concept->glossaryid] . ': ' . $strcategory . ' ' . $concept->concept;
                 $link = new moodle_url('/mod/glossary/view.php', array('g' => $concept->glossaryid, 'mode' => 'cat', 'hook' => $concept->id));
                 $attributes = array('href' => $link, 'title' => $title, 'class' => 'glossary autolink category glossaryid' . $concept->glossaryid);
             } else {
                 // Link to entry or alias
                 $title = $glossaries[$concept->glossaryid] . ': ' . $concept->concept;
                 // Hardcoding dictionary format in the URL rather than defaulting
                 // to the current glossary format which may not work in a popup.
                 // for example "entry list" means the popup would only contain
                 // a link that opens another popup.
                 $link = new moodle_url('/mod/glossary/showentry.php', array('eid' => $concept->id, 'displayformat' => 'dictionary'));
                 $attributes = array('href' => $link, 'title' => str_replace('&amp;', '&', $title), 'class' => 'glossary autolink concept glossaryid' . $concept->glossaryid);
             }
             // This flag is optionally set by resource_pluginfile()
             // if processing an embedded file use target to prevent getting nested Moodles.
             if (!empty($CFG->embeddedsoforcelinktarget)) {
                 $attributes['target'] = '_top';
             }
             $href_tag_begin = html_writer::start_tag('a', $attributes);
             $conceptlist[] = new filterobject($concept->concept, $href_tag_begin, '</a>', $concept->casesensitive, $concept->fullmatch);
         }
     }
     usort($conceptlist, 'filter_glossary::sort_entries_by_length');
     if (!$excluded) {
         // Do not cache the excluded list here, it is used once per page only.
         $this->cacheuserid = $USER->id;
         $this->cachecourseid = $courseid;
         $this->cacheconceptlist = $conceptlist;
     }
     if (empty($conceptlist)) {
         return $text;
     }
     return filter_phrases($text, $conceptlist);
     // Actually search for concepts!
 }
Ejemplo n.º 6
0
 /**
  * Test convect fetching.
  */
 public function test_concept_fetching()
 {
     global $CFG, $DB;
     $this->resetAfterTest(true);
     $this->setAdminUser();
     $CFG->glossary_linkbydefault = 1;
     $CFG->glossary_linkentries = 0;
     // Create a test courses.
     $course1 = $this->getDataGenerator()->create_course();
     $course2 = $this->getDataGenerator()->create_course();
     $site = $DB->get_record('course', array('id' => SITEID));
     // Create a glossary.
     $glossary1a = $this->getDataGenerator()->create_module('glossary', array('course' => $course1->id, 'mainglossary' => 1, 'usedynalink' => 1));
     $glossary1b = $this->getDataGenerator()->create_module('glossary', array('course' => $course1->id, 'mainglossary' => 1, 'usedynalink' => 1));
     $glossary1c = $this->getDataGenerator()->create_module('glossary', array('course' => $course1->id, 'mainglossary' => 1, 'usedynalink' => 0));
     $glossary2 = $this->getDataGenerator()->create_module('glossary', array('course' => $course2->id, 'mainglossary' => 1, 'usedynalink' => 1));
     $glossary3 = $this->getDataGenerator()->create_module('glossary', array('course' => $site->id, 'mainglossary' => 1, 'usedynalink' => 1, 'globalglossary' => 1));
     /** @var mod_glossary_generator $generator */
     $generator = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
     $entry1a1 = $generator->create_content($glossary1a, array('concept' => 'first', 'usedynalink' => 1), array('prvni', 'erste'));
     $entry1a2 = $generator->create_content($glossary1a, array('concept' => 'A&B', 'usedynalink' => 1));
     $entry1a3 = $generator->create_content($glossary1a, array('concept' => 'neee', 'usedynalink' => 0));
     $entry1b1 = $generator->create_content($glossary1b, array('concept' => 'second', 'usedynalink' => 1));
     $entry1c1 = $generator->create_content($glossary1c, array('concept' => 'third', 'usedynalink' => 1));
     $entry31 = $generator->create_content($glossary3, array('concept' => 'global', 'usedynalink' => 1), array('globalni'));
     $cat1 = $generator->create_category($glossary1a, array('name' => 'special'), array($entry1a1, $entry1a2));
     \mod_glossary\local\concept_cache::reset_caches();
     $concepts1 = \mod_glossary\local\concept_cache::get_concepts($course1->id);
     $this->assertCount(3, $concepts1[0]);
     $this->arrayHasKey($concepts1[0], $glossary1a->id);
     $this->arrayHasKey($concepts1[0], $glossary1b->id);
     $this->arrayHasKey($concepts1[0], $glossary3->id);
     $this->assertCount(3, $concepts1[1]);
     $this->arrayHasKey($concepts1[1], $glossary1a->id);
     $this->arrayHasKey($concepts1[1], $glossary1b->id);
     $this->arrayHasKey($concepts1[0], $glossary3->id);
     $this->assertCount(5, $concepts1[1][$glossary1a->id]);
     foreach ($concepts1[1][$glossary1a->id] as $concept) {
         $this->assertSame(array('id', 'glossaryid', 'concept', 'casesensitive', 'category', 'fullmatch'), array_keys((array) $concept));
         if ($concept->concept === 'first') {
             $this->assertEquals($entry1a1->id, $concept->id);
             $this->assertEquals($glossary1a->id, $concept->glossaryid);
             $this->assertEquals(0, $concept->category);
         } else {
             if ($concept->concept === 'prvni') {
                 $this->assertEquals($entry1a1->id, $concept->id);
                 $this->assertEquals($glossary1a->id, $concept->glossaryid);
                 $this->assertEquals(0, $concept->category);
             } else {
                 if ($concept->concept === 'erste') {
                     $this->assertEquals($entry1a1->id, $concept->id);
                     $this->assertEquals($glossary1a->id, $concept->glossaryid);
                     $this->assertEquals(0, $concept->category);
                 } else {
                     if ($concept->concept === 'A&amp;B') {
                         $this->assertEquals($entry1a2->id, $concept->id);
                         $this->assertEquals($glossary1a->id, $concept->glossaryid);
                         $this->assertEquals(0, $concept->category);
                     } else {
                         if ($concept->concept === 'special') {
                             $this->assertEquals($cat1->id, $concept->id);
                             $this->assertEquals($glossary1a->id, $concept->glossaryid);
                             $this->assertEquals(1, $concept->category);
                         } else {
                             $this->fail('Unexpected concept: ' . $concept->concept);
                         }
                     }
                 }
             }
         }
     }
     $this->assertCount(1, $concepts1[1][$glossary1b->id]);
     foreach ($concepts1[1][$glossary1b->id] as $concept) {
         $this->assertSame(array('id', 'glossaryid', 'concept', 'casesensitive', 'category', 'fullmatch'), array_keys((array) $concept));
         if ($concept->concept === 'second') {
             $this->assertEquals($entry1b1->id, $concept->id);
             $this->assertEquals($glossary1b->id, $concept->glossaryid);
             $this->assertEquals(0, $concept->category);
         } else {
             $this->fail('Unexpected concept: ' . $concept->concept);
         }
     }
     $this->assertCount(2, $concepts1[1][$glossary3->id]);
     foreach ($concepts1[1][$glossary3->id] as $concept) {
         $this->assertSame(array('id', 'glossaryid', 'concept', 'casesensitive', 'category', 'fullmatch'), array_keys((array) $concept));
         if ($concept->concept === 'global') {
             $this->assertEquals($entry31->id, $concept->id);
             $this->assertEquals($glossary3->id, $concept->glossaryid);
             $this->assertEquals(0, $concept->category);
         } else {
             if ($concept->concept === 'globalni') {
                 $this->assertEquals($entry31->id, $concept->id);
                 $this->assertEquals($glossary3->id, $concept->glossaryid);
                 $this->assertEquals(0, $concept->category);
             } else {
                 $this->fail('Unexpected concept: ' . $concept->concept);
             }
         }
     }
     $concepts3 = \mod_glossary\local\concept_cache::get_concepts($site->id);
     $this->assertCount(1, $concepts3[0]);
     $this->arrayHasKey($concepts3[0], $glossary3->id);
     $this->assertCount(1, $concepts3[1]);
     $this->arrayHasKey($concepts3[0], $glossary3->id);
     foreach ($concepts3[1][$glossary3->id] as $concept) {
         $this->assertSame(array('id', 'glossaryid', 'concept', 'casesensitive', 'category', 'fullmatch'), array_keys((array) $concept));
         if ($concept->concept === 'global') {
             $this->assertEquals($entry31->id, $concept->id);
             $this->assertEquals($glossary3->id, $concept->glossaryid);
             $this->assertEquals(0, $concept->category);
         } else {
             if ($concept->concept === 'globalni') {
                 $this->assertEquals($entry31->id, $concept->id);
                 $this->assertEquals($glossary3->id, $concept->glossaryid);
                 $this->assertEquals(0, $concept->category);
             } else {
                 $this->fail('Unexpected concept: ' . $concept->concept);
             }
         }
     }
     $concepts2 = \mod_glossary\local\concept_cache::get_concepts($course2->id);
     $this->assertEquals($concepts3, $concepts2);
     // Test uservisible flag.
     set_config('enableavailability', 1);
     $glossary1d = $this->getDataGenerator()->create_module('glossary', array('course' => $course1->id, 'mainglossary' => 1, 'usedynalink' => 1, 'availability' => json_encode(\core_availability\tree::get_root_json(array(\availability_group\condition::get_json())))));
     $entry1d1 = $generator->create_content($glossary1d, array('concept' => 'membersonly', 'usedynalink' => 1));
     $user = $this->getDataGenerator()->create_user();
     $this->getDataGenerator()->enrol_user($user->id, $course1->id);
     $this->getDataGenerator()->enrol_user($user->id, $course2->id);
     \mod_glossary\local\concept_cache::reset_caches();
     $concepts1 = \mod_glossary\local\concept_cache::get_concepts($course1->id);
     $this->assertCount(4, $concepts1[0]);
     $this->assertCount(4, $concepts1[1]);
     $this->setUser($user);
     course_modinfo::clear_instance_cache();
     \mod_glossary\local\concept_cache::reset_caches();
     $concepts1 = \mod_glossary\local\concept_cache::get_concepts($course1->id);
     $this->assertCount(3, $concepts1[0]);
     $this->assertCount(3, $concepts1[1]);
 }