mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 22:08:20 +01:00
Merge branch 'wip-MDL-57456-master' of git://github.com/marinaglancy/moodle
This commit is contained in:
commit
c2118c8902
@ -53,6 +53,9 @@ class backup_glossary_activity_structure_step extends backup_activity_structure_
|
||||
'teacherentry', 'sourceglossaryid', 'usedynalink', 'casesensitive',
|
||||
'fullmatch', 'approved'));
|
||||
|
||||
$tags = new backup_nested_element('entriestags');
|
||||
$tag = new backup_nested_element('tag', array('id'), array('itemid', 'rawname'));
|
||||
|
||||
$aliases = new backup_nested_element('aliases');
|
||||
|
||||
$alias = new backup_nested_element('alias', array('id'), array(
|
||||
@ -77,6 +80,9 @@ class backup_glossary_activity_structure_step extends backup_activity_structure_
|
||||
$glossary->add_child($entries);
|
||||
$entries->add_child($entry);
|
||||
|
||||
$glossary->add_child($tags);
|
||||
$tags->add_child($tag);
|
||||
|
||||
$entry->add_child($aliases);
|
||||
$aliases->add_child($alias);
|
||||
|
||||
@ -108,6 +114,18 @@ class backup_glossary_activity_structure_step extends backup_activity_structure_
|
||||
$rating->set_source_alias('rating', 'value');
|
||||
|
||||
$categoryentry->set_source_table('glossary_entries_categories', array('categoryid' => backup::VAR_PARENTID));
|
||||
|
||||
if (core_tag_tag::is_enabled('mod_glossary', 'glossary_entries')) {
|
||||
$tag->set_source_sql('SELECT t.id, ti.itemid, t.rawname
|
||||
FROM {tag} t
|
||||
JOIN {tag_instance} ti ON ti.tagid = t.id
|
||||
WHERE ti.itemtype = ?
|
||||
AND ti.component = ?
|
||||
AND ti.contextid = ?', array(
|
||||
backup_helper::is_sqlparam('glossary_entries'),
|
||||
backup_helper::is_sqlparam('mod_glossary'),
|
||||
backup::VAR_CONTEXTID));
|
||||
}
|
||||
}
|
||||
|
||||
// Define id annotations
|
||||
|
@ -40,6 +40,7 @@ class restore_glossary_activity_structure_step extends restore_activity_structur
|
||||
$paths[] = new restore_path_element('glossary_category', '/activity/glossary/categories/category');
|
||||
if ($userinfo) {
|
||||
$paths[] = new restore_path_element('glossary_entry', '/activity/glossary/entries/entry');
|
||||
$paths[] = new restore_path_element('glossary_entry_tag', '/activity/glossary/entriestags/tag');
|
||||
$paths[] = new restore_path_element('glossary_alias', '/activity/glossary/entries/entry/aliases/alias');
|
||||
$paths[] = new restore_path_element('glossary_rating', '/activity/glossary/entries/entry/ratings/rating');
|
||||
$paths[] = new restore_path_element('glossary_category_entry',
|
||||
@ -134,6 +135,23 @@ class restore_glossary_activity_structure_step extends restore_activity_structur
|
||||
$newitemid = $DB->insert_record('rating', $data);
|
||||
}
|
||||
|
||||
protected function process_glossary_entry_tag($data) {
|
||||
$data = (object)$data;
|
||||
|
||||
if (!core_tag_tag::is_enabled('mod_glossary', 'glossary_entries')) { // Tags disabled in server, nothing to process.
|
||||
return;
|
||||
}
|
||||
|
||||
$tag = $data->rawname;
|
||||
if (!$itemid = $this->get_mappingid('glossary_entry', $data->itemid)) {
|
||||
// Some orphaned tag, we could not find the glossary entry for it - ignore.
|
||||
return;
|
||||
}
|
||||
|
||||
$context = context_module::instance($this->task->get_moduleid());
|
||||
core_tag_tag::add_item_tag('mod_glossary', 'glossary_entries', $itemid, $context, $tag);
|
||||
}
|
||||
|
||||
protected function process_glossary_category($data) {
|
||||
global $DB;
|
||||
|
||||
|
35
mod/glossary/db/tag.php
Normal file
35
mod/glossary/db/tag.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Tag areas in component mod_glossary
|
||||
*
|
||||
* @package mod_glossary
|
||||
* @copyright 2017 Andrew Hancox <andrewdchancox@googlemail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
$tagareas = array(
|
||||
array(
|
||||
'itemtype' => 'glossary_entries',
|
||||
'component' => 'mod_glossary',
|
||||
'callback' => 'mod_glossary_get_tagged_entries',
|
||||
'callbackfile' => '/mod/glossary/locallib.php',
|
||||
),
|
||||
);
|
@ -120,6 +120,8 @@ if ($confirm and confirm_sesskey()) { // the operation was confirmed.
|
||||
glossary_rss_delete_file($glossary);
|
||||
}
|
||||
|
||||
core_tag_tag::remove_all_item_tags('mod_glossary', 'glossary_entries', $origentry->id);
|
||||
|
||||
$event = \mod_glossary\event\entry_deleted::create(array(
|
||||
'context' => $context,
|
||||
'objectid' => $origentry->id,
|
||||
|
@ -81,8 +81,11 @@ if ($mform->is_cancelled()){
|
||||
redirect("view.php?id=$cm->id");
|
||||
}
|
||||
|
||||
} else if ($entry = $mform->get_data()) {
|
||||
$entry = glossary_edit_entry($entry, $course, $cm, $glossary, $context);
|
||||
} else if ($data = $mform->get_data()) {
|
||||
$entry = glossary_edit_entry($data, $course, $cm, $glossary, $context);
|
||||
if (core_tag_tag::is_enabled('mod_glossary', 'glossary_entries') && isset($data->tags)) {
|
||||
core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $data->id, $context, $data->tags);
|
||||
}
|
||||
redirect("view.php?id=$cm->id&mode=entry&hook=$entry->id");
|
||||
}
|
||||
|
||||
@ -98,6 +101,10 @@ if ($glossary->intro) {
|
||||
echo $OUTPUT->box(format_module_intro('glossary', $glossary, $cm->id), 'generalbox', 'intro');
|
||||
}
|
||||
|
||||
$data = new StdClass();
|
||||
$data->tags = core_tag_tag::get_item_tags_array('mod_glossary', 'glossary_entries', $id);
|
||||
$mform->set_data($data);
|
||||
|
||||
$mform->display();
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
@ -78,6 +78,13 @@ class mod_glossary_entry_form extends moodleform {
|
||||
$mform->setDefault('fullmatch', $CFG->glossary_fullmatch);
|
||||
}
|
||||
|
||||
if (core_tag_tag::is_enabled('mod_glossary', 'glossary_entries')) {
|
||||
$mform->addElement('header', 'tagshdr', get_string('tags', 'tag'));
|
||||
|
||||
$mform->addElement('tags', 'tags', get_string('tags'),
|
||||
array('itemtype' => 'glossary_entries', 'component' => 'mod_glossary'));
|
||||
}
|
||||
|
||||
$mform->addElement('hidden', 'id');
|
||||
$mform->setType('id', PARAM_INT);
|
||||
$mform->addElement('hidden', 'cmid');
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
function glossary_show_entry_continuous($course, $cm, $glossary, $entry, $mode='', $hook='', $printicons=1, $aliases=false) {
|
||||
|
||||
global $USER;
|
||||
global $USER, $OUTPUT;
|
||||
|
||||
echo '<table class="glossarypost continuous" cellspacing="0">';
|
||||
echo '<tr valign="top">';
|
||||
@ -13,6 +13,11 @@ function glossary_show_entry_continuous($course, $cm, $glossary, $entry, $mode='
|
||||
echo '</div> ';
|
||||
glossary_print_entry_definition($entry, $glossary, $cm);
|
||||
glossary_print_entry_attachment($entry, $cm, 'html');
|
||||
|
||||
if (core_tag_tag::is_enabled('mod_glossary', 'glossary_entries')) {
|
||||
echo $OUTPUT->tag_list(core_tag_tag::get_item_tags(
|
||||
'mod_glossary', 'glossary_entries', $entry->id), null, 'glossary-tags');
|
||||
}
|
||||
$entry->alias = '';
|
||||
echo '</td></tr>';
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
function glossary_show_entry_dictionary($course, $cm, $glossary, $entry, $mode='', $hook='', $printicons=1, $aliases=true) {
|
||||
|
||||
global $CFG, $USER;
|
||||
global $CFG, $USER, $OUTPUT;
|
||||
|
||||
echo '<table class="glossarypost dictionary" cellspacing="0">';
|
||||
echo '<tr valign="top">';
|
||||
@ -13,6 +13,9 @@ function glossary_show_entry_dictionary($course, $cm, $glossary, $entry, $mode='
|
||||
echo '</div> ';
|
||||
glossary_print_entry_definition($entry, $glossary, $cm);
|
||||
glossary_print_entry_attachment($entry, $cm, 'html');
|
||||
if (core_tag_tag::is_enabled('mod_glossary', 'glossary_entries')) {
|
||||
echo $OUTPUT->tag_list(core_tag_tag::get_item_tags('mod_glossary', 'glossary_entries', $entry->id), null, 'glossary-tags');
|
||||
}
|
||||
echo '</td></tr>';
|
||||
echo '<tr valign="top"><td class="entrylowersection">';
|
||||
glossary_print_entry_lower_section($course, $cm, $glossary, $entry, $mode, $hook, $printicons, $aliases);
|
||||
|
@ -40,6 +40,10 @@ function glossary_show_entry_encyclopedia($course, $cm, $glossary, $entry, $mode
|
||||
|
||||
glossary_print_entry_definition($entry, $glossary, $cm);
|
||||
glossary_print_entry_attachment($entry, $cm, null);
|
||||
if (core_tag_tag::is_enabled('mod_glossary', 'glossary_entries')) {
|
||||
echo $OUTPUT->tag_list(
|
||||
core_tag_tag::get_item_tags('mod_glossary', 'glossary_entries', $entry->id), null, 'glossary-tags');
|
||||
}
|
||||
|
||||
if ($printicons or $aliases) {
|
||||
echo '</td></tr>';
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
function glossary_show_entry_faq($course, $cm, $glossary, $entry, $mode="", $hook="", $printicons=1, $aliases=true) {
|
||||
global $USER;
|
||||
global $USER, $OUTPUT;
|
||||
if ( $entry ) {
|
||||
|
||||
echo '<table class="glossarypost faq" cellspacing="0">';
|
||||
@ -31,6 +31,11 @@ function glossary_show_entry_faq($course, $cm, $glossary, $entry, $mode="", $hoo
|
||||
glossary_print_entry_definition($entry, $glossary, $cm);
|
||||
glossary_print_entry_attachment($entry, $cm, 'html');
|
||||
|
||||
if (core_tag_tag::is_enabled('mod_glossary', 'glossary_entries')) {
|
||||
echo $OUTPUT->tag_list(
|
||||
core_tag_tag::get_item_tags('mod_glossary', 'glossary_entries', $entry->id), null, 'glossary-tags');
|
||||
}
|
||||
|
||||
echo '</td></tr>';
|
||||
echo '<tr valign="top"><td colspan="3" class="entrylowersection">';
|
||||
glossary_print_entry_lower_section($course, $cm, $glossary, $entry, $mode, $hook, $printicons, $aliases);
|
||||
|
@ -42,6 +42,11 @@ function glossary_show_entry_fullwithauthor($course, $cm, $glossary, $entry, $mo
|
||||
glossary_print_entry_definition($entry, $glossary, $cm);
|
||||
glossary_print_entry_attachment($entry, $cm, 'html');
|
||||
|
||||
if (core_tag_tag::is_enabled('mod_glossary', 'glossary_entries')) {
|
||||
echo $OUTPUT->tag_list(
|
||||
core_tag_tag::get_item_tags('mod_glossary', 'glossary_entries', $entry->id), null, 'glossary-tags');
|
||||
}
|
||||
|
||||
echo '</td></tr>';
|
||||
echo '<tr valign="top">';
|
||||
echo '<td class="left"> </td>';
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
function glossary_show_entry_fullwithoutauthor($course, $cm, $glossary, $entry, $mode="", $hook="", $printicons=1, $aliases=true) {
|
||||
global $CFG, $USER;
|
||||
global $CFG, $USER, $OUTPUT;
|
||||
|
||||
|
||||
if ($entry) {
|
||||
@ -30,6 +30,11 @@ function glossary_show_entry_fullwithoutauthor($course, $cm, $glossary, $entry,
|
||||
glossary_print_entry_definition($entry, $glossary, $cm);
|
||||
glossary_print_entry_attachment($entry, $cm, 'html');
|
||||
|
||||
if (core_tag_tag::is_enabled('mod_glossary', 'glossary_entries')) {
|
||||
echo $OUTPUT->tag_list(
|
||||
core_tag_tag::get_item_tags('mod_glossary', 'glossary_entries', $entry->id), null, 'glossary-tags');
|
||||
}
|
||||
|
||||
echo '</td></tr>';
|
||||
echo '<tr valign="top"><td colspan="2" class="entrylowersection">';
|
||||
glossary_print_entry_lower_section($course, $cm, $glossary, $entry, $mode, $hook, $printicons, $aliases);
|
||||
|
@ -269,6 +269,7 @@ $string['printviewnotallowed'] = 'Print view isn\'t allowed';
|
||||
$string['question'] = 'Question';
|
||||
$string['rejectedentries'] = 'Rejected entries';
|
||||
$string['rejectionrpt'] = 'Rejection report';
|
||||
$string['removeallglossarytags'] = 'Remove all glossary tags';
|
||||
$string['resetglossaries'] = 'Delete entries from';
|
||||
$string['resetglossariesall'] = 'Delete entries from all glossaries';
|
||||
$string['rssarticles'] = 'Number of RSS recent articles';
|
||||
@ -293,6 +294,9 @@ $string['sortchronogically'] = 'Sort chronologically';
|
||||
$string['special'] = 'Special';
|
||||
$string['standardview'] = 'Browse by alphabet';
|
||||
$string['studentcanpost'] = 'Students can add entries';
|
||||
$string['tagarea_glossary_entries'] = 'Glossary entries';
|
||||
$string['tagsdeleted'] = 'Glossary tags have been deleted';
|
||||
$string['tagtitle'] = 'See the "{$a}" tag';
|
||||
$string['totalentries'] = 'Total entries';
|
||||
$string['usedynalink'] = 'Automatically link glossary entries';
|
||||
$string['usedynalink_help'] = 'If site-wide glossary auto-linking has been enabled by an administrator and this setting is enabled, the "Add a new entry" form includes the option to automatically link the entry wherever the concept words and phrases appear throughout the rest of the course.';
|
||||
|
@ -2173,7 +2173,7 @@ function glossary_print_entry_ratings($course, $entry) {
|
||||
* @param int $displayformat
|
||||
*/
|
||||
function glossary_print_dynaentry($courseid, $entries, $displayformat = -1) {
|
||||
global $USER,$CFG, $DB;
|
||||
global $USER, $CFG, $DB, $OUTPUT;
|
||||
|
||||
echo '<div class="boxaligncenter">';
|
||||
echo '<table class="glossarypopup" cellspacing="0"><tr>';
|
||||
|
@ -635,3 +635,118 @@ class glossary_file_info_container extends file_info {
|
||||
return $this->browser->get_file_info($this->context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns glossary entries tagged with a specified tag.
|
||||
*
|
||||
* This is a callback used by the tag area mod_glossary/glossary_entries to search for glossary entries
|
||||
* tagged with a specific tag.
|
||||
*
|
||||
* @param core_tag_tag $tag
|
||||
* @param bool $exclusivemode if set to true it means that no other entities tagged with this tag
|
||||
* are displayed on the page and the per-page limit may be bigger
|
||||
* @param int $fromctx context id where the link was displayed, may be used by callbacks
|
||||
* to display items in the same context first
|
||||
* @param int $ctx context id where to search for records
|
||||
* @param bool $rec search in subcontexts as well
|
||||
* @param int $page 0-based number of page being displayed
|
||||
* @return \core_tag\output\tagindex
|
||||
*/
|
||||
function mod_glossary_get_tagged_entries($tag, $exclusivemode = false, $fromctx = 0, $ctx = 0, $rec = 1, $page = 0) {
|
||||
global $OUTPUT;
|
||||
$perpage = $exclusivemode ? 20 : 5;
|
||||
|
||||
// Build the SQL query.
|
||||
$ctxselect = context_helper::get_preload_record_columns_sql('ctx');
|
||||
$query = "SELECT ge.id, ge.concept, ge.glossaryid, ge.approved,
|
||||
cm.id AS cmid, c.id AS courseid, c.shortname, c.fullname, $ctxselect
|
||||
FROM {glossary_entries} ge
|
||||
JOIN {glossary} g ON g.id = ge.glossaryid
|
||||
JOIN {modules} m ON m.name='glossary'
|
||||
JOIN {course_modules} cm ON cm.module = m.id AND cm.instance = g.id
|
||||
JOIN {tag_instance} tt ON ge.id = tt.itemid
|
||||
JOIN {course} c ON cm.course = c.id
|
||||
JOIN {context} ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = :coursemodulecontextlevel
|
||||
WHERE tt.itemtype = :itemtype AND tt.tagid = :tagid AND tt.component = :component
|
||||
AND cm.deletioninprogress = 0
|
||||
AND ge.id %ITEMFILTER% AND c.id %COURSEFILTER%";
|
||||
|
||||
$params = array('itemtype' => 'glossary_entries', 'tagid' => $tag->id, 'component' => 'mod_glossary',
|
||||
'coursemodulecontextlevel' => CONTEXT_MODULE);
|
||||
|
||||
if ($ctx) {
|
||||
$context = $ctx ? context::instance_by_id($ctx) : context_system::instance();
|
||||
$query .= $rec ? ' AND (ctx.id = :contextid OR ctx.path LIKE :path)' : ' AND ctx.id = :contextid';
|
||||
$params['contextid'] = $context->id;
|
||||
$params['path'] = $context->path.'/%';
|
||||
}
|
||||
|
||||
$query .= " ORDER BY ";
|
||||
if ($fromctx) {
|
||||
// In order-clause specify that modules from inside "fromctx" context should be returned first.
|
||||
$fromcontext = context::instance_by_id($fromctx);
|
||||
$query .= ' (CASE WHEN ctx.id = :fromcontextid OR ctx.path LIKE :frompath THEN 0 ELSE 1 END),';
|
||||
$params['fromcontextid'] = $fromcontext->id;
|
||||
$params['frompath'] = $fromcontext->path.'/%';
|
||||
}
|
||||
$query .= ' c.sortorder, cm.id, ge.id';
|
||||
|
||||
$totalpages = $page + 1;
|
||||
|
||||
// Use core_tag_index_builder to build and filter the list of items.
|
||||
$builder = new core_tag_index_builder('mod_glossary', 'glossary_entries', $query, $params, $page * $perpage, $perpage + 1);
|
||||
while ($item = $builder->has_item_that_needs_access_check()) {
|
||||
context_helper::preload_from_record($item);
|
||||
$courseid = $item->courseid;
|
||||
if (!$builder->can_access_course($courseid)) {
|
||||
$builder->set_accessible($item, false);
|
||||
continue;
|
||||
}
|
||||
$modinfo = get_fast_modinfo($builder->get_course($courseid));
|
||||
// Set accessibility of this item and all other items in the same course.
|
||||
$builder->walk(function ($taggeditem) use ($courseid, $modinfo, $builder) {
|
||||
if ($taggeditem->courseid == $courseid) {
|
||||
$accessible = false;
|
||||
if (($cm = $modinfo->get_cm($taggeditem->cmid)) && $cm->uservisible) {
|
||||
if ($taggeditem->approved) {
|
||||
$accessible = true;
|
||||
} else {
|
||||
$accessible = has_capability('mod/glossary:approve', context_module::instance($cm->id));
|
||||
}
|
||||
}
|
||||
$builder->set_accessible($taggeditem, $accessible);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$items = $builder->get_items();
|
||||
if (count($items) > $perpage) {
|
||||
$totalpages = $page + 2; // We don't need exact page count, just indicate that the next page exists.
|
||||
array_pop($items);
|
||||
}
|
||||
|
||||
// Build the display contents.
|
||||
if ($items) {
|
||||
$tagfeed = new core_tag\output\tagfeed();
|
||||
foreach ($items as $item) {
|
||||
context_helper::preload_from_record($item);
|
||||
$modinfo = get_fast_modinfo($item->courseid);
|
||||
$cm = $modinfo->get_cm($item->cmid);
|
||||
$pageurl = new moodle_url('/mod/glossary/showentry.php', array('eid' => $item->id, 'displayformat' => 'dictionary'));
|
||||
$pagename = format_string($item->concept, true, array('context' => context_module::instance($item->cmid)));
|
||||
$pagename = html_writer::link($pageurl, $pagename);
|
||||
$courseurl = course_get_url($item->courseid, $cm->sectionnum);
|
||||
$cmname = html_writer::link($cm->url, $cm->get_formatted_name());
|
||||
$coursename = format_string($item->fullname, true, array('context' => context_course::instance($item->courseid)));
|
||||
$coursename = html_writer::link($courseurl, $coursename);
|
||||
$icon = html_writer::link($pageurl, html_writer::empty_tag('img', array('src' => $cm->get_icon_url())));
|
||||
$tagfeed->add($icon, $pagename, $cmname.'<br>'.$coursename);
|
||||
}
|
||||
|
||||
$content = $OUTPUT->render_from_template('core_tag/tagfeed',
|
||||
$tagfeed->export_for_template($OUTPUT));
|
||||
|
||||
return new core_tag\output\tagindex($tag, 'mod_glossary', 'glossary_entries', $content,
|
||||
$exclusivemode, $fromctx, $ctx, $rec, $page, $totalpages);
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +73,11 @@ if ($entries) {
|
||||
$options->context = $context;
|
||||
$entries[$key]->definition = format_text($definition, $entry->definitionformat, $options);
|
||||
|
||||
if (core_tag_tag::is_enabled('mod_glossary', 'glossary_entries')) {
|
||||
$entries[$key]->definition .= $OUTPUT->tag_list(
|
||||
core_tag_tag::get_item_tags('mod_glossary', 'glossary_entries', $entry->id), null, 'glossary-tags');
|
||||
}
|
||||
|
||||
$entries[$key]->attachments = '';
|
||||
if (!empty($entries[$key]->attachment)) {
|
||||
$attachments = glossary_print_attachments($entry, $cm, 'html');
|
||||
|
76
mod/glossary/tests/behat/edit_tags.feature
Normal file
76
mod/glossary/tests/behat/edit_tags.feature
Normal file
@ -0,0 +1,76 @@
|
||||
@mod @mod_glossary @core_tag @javascript
|
||||
Feature: Edited glossary entries handle tags correctly
|
||||
In order to get glossary entries properly labelled
|
||||
As a user
|
||||
I need to introduce the tags while editing
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | format |
|
||||
| Course 1 | C1 | topics |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Glossary" to section "1" and I fill the form with:
|
||||
| Name | Test glossary |
|
||||
| Description | A glossary about dreams! |
|
||||
And I log out
|
||||
|
||||
Scenario: Glossary entry edition of custom tags works as expected
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test glossary"
|
||||
And I press "Add a new entry"
|
||||
And I set the following fields to these values:
|
||||
| Concept | Dummy first entry |
|
||||
| Definition | Dream is the start of a journey |
|
||||
| Tags | Example, Entry, Cool |
|
||||
And I press "Save changes"
|
||||
Then I should see "Example" in the ".glossary-tags" "css_element"
|
||||
And I should see "Entry" in the ".glossary-tags" "css_element"
|
||||
And I should see "Cool" in the ".glossary-tags" "css_element"
|
||||
And I click on "Edit" "link" in the ".entrylowersection" "css_element"
|
||||
And I expand all fieldsets
|
||||
Then I should see "Example" in the ".form-autocomplete-selection" "css_element"
|
||||
Then I should see "Entry" in the ".form-autocomplete-selection" "css_element"
|
||||
Then I should see "Cool" in the ".form-autocomplete-selection" "css_element"
|
||||
|
||||
@javascript
|
||||
Scenario: Glossary entry edition of standard tags works as expected
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Appearance > Manage tags" in site administration
|
||||
And I follow "Default collection"
|
||||
And I follow "Add standard tags"
|
||||
And I set the field "Enter comma-separated list of new tags" to "OT1, OT2, OT3"
|
||||
And I press "Continue"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test glossary"
|
||||
And I press "Add a new entry"
|
||||
And I expand all fieldsets
|
||||
And I click on ".form-autocomplete-downarrow" "css_element"
|
||||
And I should see "OT1" in the ".form-autocomplete-suggestions" "css_element"
|
||||
And I should see "OT2" in the ".form-autocomplete-suggestions" "css_element"
|
||||
And I should see "OT3" in the ".form-autocomplete-suggestions" "css_element"
|
||||
When I set the following fields to these values:
|
||||
| Concept | Dummy first entry |
|
||||
| Definition | Dream is the start of a journey |
|
||||
| Tags | OT1, OT3 |
|
||||
And I press "Save changes"
|
||||
Then I should see "OT1" in the ".glossary-tags" "css_element"
|
||||
And I should see "OT3" in the ".glossary-tags" "css_element"
|
||||
And I should not see "OT2" in the ".glossary-tags" "css_element"
|
||||
And I click on "Edit" "link" in the ".entrylowersection" "css_element"
|
||||
And I expand all fieldsets
|
||||
And I should see "OT1" in the ".form-autocomplete-selection" "css_element"
|
||||
And I should see "OT3" in the ".form-autocomplete-selection" "css_element"
|
||||
And I should not see "OT2" in the ".form-autocomplete-selection" "css_element"
|
@ -145,6 +145,13 @@ class mod_glossary_generator extends testing_module_generator {
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists('tags', $record)) {
|
||||
$tags = is_array($record['tags']) ? $record['tags'] : preg_split('/,/', $record['tags']);
|
||||
|
||||
core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $id,
|
||||
context_module::instance($glossary->cmid), $tags);
|
||||
}
|
||||
|
||||
return $DB->get_record('glossary_entries', array('id' => $id), '*', MUST_EXIST);
|
||||
}
|
||||
}
|
||||
|
@ -64,12 +64,15 @@ class mod_glossary_generator_testcase extends advanced_testcase {
|
||||
$glossarygenerator = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
|
||||
|
||||
$entry1 = $glossarygenerator->create_content($glossary);
|
||||
$entry2 = $glossarygenerator->create_content($glossary, array('concept' => 'Custom concept'), array('alias1', 'alias2'));
|
||||
$entry2 = $glossarygenerator->create_content($glossary,
|
||||
array('concept' => 'Custom concept', 'tags' => array('Cats', 'mice')), array('alias1', 'alias2'));
|
||||
$records = $DB->get_records('glossary_entries', array('glossaryid' => $glossary->id), 'id');
|
||||
$this->assertCount(2, $records);
|
||||
$this->assertEquals($entry1->id, $records[$entry1->id]->id);
|
||||
$this->assertEquals($entry2->id, $records[$entry2->id]->id);
|
||||
$this->assertEquals('Custom concept', $records[$entry2->id]->concept);
|
||||
$this->assertEquals(array('Cats', 'mice'),
|
||||
array_values(core_tag_tag::get_item_tags_array('mod_glossary', 'glossary_entries', $entry2->id)));
|
||||
$aliases = $DB->get_records_menu('glossary_alias', array('entryid' => $entry2->id), 'id ASC', 'id, alias');
|
||||
$this->assertSame(array('alias1', 'alias2'), array_values($aliases));
|
||||
|
||||
|
@ -26,6 +26,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/glossary/lib.php');
|
||||
require_once($CFG->dirroot . '/mod/glossary/locallib.php');
|
||||
|
||||
/**
|
||||
* Glossary lib testcase.
|
||||
@ -232,4 +233,94 @@ class mod_glossary_lib_testcase extends advanced_testcase {
|
||||
$this->assertEquals(mod_glossary_get_completion_active_rule_descriptions($moddefaults), $activeruledescriptions);
|
||||
$this->assertEquals(mod_glossary_get_completion_active_rule_descriptions(new stdClass()), []);
|
||||
}
|
||||
|
||||
public function test_mod_glossary_get_tagged_entries() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
// Setup test data.
|
||||
$glossarygenerator = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
|
||||
$course3 = $this->getDataGenerator()->create_course();
|
||||
$course2 = $this->getDataGenerator()->create_course();
|
||||
$course1 = $this->getDataGenerator()->create_course();
|
||||
$glossary1 = $this->getDataGenerator()->create_module('glossary', array('course' => $course1->id));
|
||||
$glossary2 = $this->getDataGenerator()->create_module('glossary', array('course' => $course2->id));
|
||||
$glossary3 = $this->getDataGenerator()->create_module('glossary', array('course' => $course3->id));
|
||||
$entry11 = $glossarygenerator->create_content($glossary1, array('tags' => array('Cats', 'Dogs')));
|
||||
$entry12 = $glossarygenerator->create_content($glossary1, array('tags' => array('Cats', 'mice')));
|
||||
$entry13 = $glossarygenerator->create_content($glossary1, array('tags' => array('Cats')));
|
||||
$entry14 = $glossarygenerator->create_content($glossary1);
|
||||
$entry15 = $glossarygenerator->create_content($glossary1, array('tags' => array('Cats')));
|
||||
$entry16 = $glossarygenerator->create_content($glossary1, array('tags' => array('Cats'), 'approved' => false));
|
||||
$entry21 = $glossarygenerator->create_content($glossary2, array('tags' => array('Cats')));
|
||||
$entry22 = $glossarygenerator->create_content($glossary2, array('tags' => array('Cats', 'Dogs')));
|
||||
$entry23 = $glossarygenerator->create_content($glossary2, array('tags' => array('mice', 'Cats')));
|
||||
$entry31 = $glossarygenerator->create_content($glossary3, array('tags' => array('mice', 'Cats')));
|
||||
|
||||
$tag = core_tag_tag::get_by_name(0, 'Cats');
|
||||
|
||||
// Admin can see everything.
|
||||
$res = mod_glossary_get_tagged_entries($tag, /*$exclusivemode = */false,
|
||||
/*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$entry = */0);
|
||||
$this->assertRegExp('/'.$entry11->concept.'</', $res->content);
|
||||
$this->assertRegExp('/'.$entry12->concept.'</', $res->content);
|
||||
$this->assertRegExp('/'.$entry13->concept.'</', $res->content);
|
||||
$this->assertNotRegExp('/'.$entry14->concept.'</', $res->content);
|
||||
$this->assertRegExp('/'.$entry15->concept.'</', $res->content);
|
||||
$this->assertRegExp('/'.$entry16->concept.'</', $res->content);
|
||||
$this->assertNotRegExp('/'.$entry21->concept.'</', $res->content);
|
||||
$this->assertNotRegExp('/'.$entry22->concept.'</', $res->content);
|
||||
$this->assertNotRegExp('/'.$entry23->concept.'</', $res->content);
|
||||
$this->assertNotRegExp('/'.$entry31->concept.'</', $res->content);
|
||||
$this->assertEmpty($res->prevpageurl);
|
||||
$this->assertNotEmpty($res->nextpageurl);
|
||||
$res = mod_glossary_get_tagged_entries($tag, /*$exclusivemode = */false,
|
||||
/*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$entry = */1);
|
||||
$this->assertNotRegExp('/'.$entry11->concept.'</', $res->content);
|
||||
$this->assertNotRegExp('/'.$entry12->concept.'</', $res->content);
|
||||
$this->assertNotRegExp('/'.$entry13->concept.'</', $res->content);
|
||||
$this->assertNotRegExp('/'.$entry14->concept.'</', $res->content);
|
||||
$this->assertNotRegExp('/'.$entry15->concept.'</', $res->content);
|
||||
$this->assertNotRegExp('/'.$entry16->concept.'</', $res->content);
|
||||
$this->assertRegExp('/'.$entry21->concept.'</', $res->content);
|
||||
$this->assertRegExp('/'.$entry22->concept.'</', $res->content);
|
||||
$this->assertRegExp('/'.$entry23->concept.'</', $res->content);
|
||||
$this->assertRegExp('/'.$entry31->concept.'</', $res->content);
|
||||
$this->assertNotEmpty($res->prevpageurl);
|
||||
$this->assertEmpty($res->nextpageurl);
|
||||
|
||||
// Create and enrol a user.
|
||||
$student = self::getDataGenerator()->create_user();
|
||||
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
|
||||
$this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual');
|
||||
$this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual');
|
||||
$this->setUser($student);
|
||||
core_tag_index_builder::reset_caches();
|
||||
|
||||
// User can not see entries in course 3 because he is not enrolled.
|
||||
$res = mod_glossary_get_tagged_entries($tag, /*$exclusivemode = */false,
|
||||
/*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$entry = */1);
|
||||
$this->assertRegExp('/'.$entry22->concept.'/', $res->content);
|
||||
$this->assertRegExp('/'.$entry23->concept.'/', $res->content);
|
||||
$this->assertNotRegExp('/'.$entry31->concept.'/', $res->content);
|
||||
|
||||
// User can search glossary entries inside a course.
|
||||
$coursecontext = context_course::instance($course1->id);
|
||||
$res = mod_glossary_get_tagged_entries($tag, /*$exclusivemode = */false,
|
||||
/*$fromctx = */0, /*$ctx = */$coursecontext->id, /*$rec = */1, /*$entry = */0);
|
||||
$this->assertRegExp('/'.$entry11->concept.'/', $res->content);
|
||||
$this->assertRegExp('/'.$entry12->concept.'/', $res->content);
|
||||
$this->assertRegExp('/'.$entry13->concept.'/', $res->content);
|
||||
$this->assertNotRegExp('/'.$entry14->concept.'/', $res->content);
|
||||
$this->assertRegExp('/'.$entry15->concept.'/', $res->content);
|
||||
$this->assertNotRegExp('/'.$entry21->concept.'/', $res->content);
|
||||
$this->assertNotRegExp('/'.$entry22->concept.'/', $res->content);
|
||||
$this->assertNotRegExp('/'.$entry23->concept.'/', $res->content);
|
||||
$this->assertEmpty($res->nextpageurl);
|
||||
|
||||
// User cannot see hidden entries.
|
||||
$this->assertNotRegExp('/'.$entry16->concept.'/', $res->content);
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2016120500; // The current module version (Date: YYYYMMDDXX)
|
||||
$plugin->version = 2016120502; // The current module version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2016112900; // Requires this Moodle version
|
||||
$plugin->component = 'mod_glossary'; // Full name of the plugin (used for diagnostics)
|
||||
$plugin->cron = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user