first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
Glossary version 0.5 dev
------------------------
By Williams Castillo (castillow@tutopia.com)
This is the Glossary module. Created and maintained by Williams Castillo. This are my first lines in PHP... It means that, although I've tried to do my best, it might (in fact, it does) shows my inexperience... in PHP... and moodle as well.
Basically, this module allows you to maintain a repository of data in the form of concepts, Entry->Definitions, etc. Thus:
- Entries could be automatically linked from within moodle resources, labels, forum posts, etc.
- Entries can have aliases which allows to automatically link the concept to other words than itself.
- Glossaries can be viewed in a printer-friendly version format
- The display format of the entries is modular so you can create your own formats (and share them with the Moodle community!)
- Entries are posted by teachers and can be posted by students as well
- Entries can be approved before make them public.
- Entries can have an optional attached file.
- Entries can be commented by any registered user.
- Entries can be categorized (one entry can belongs to zero or more categories)
- Entries can be browsed by letters (initials), categories or by date.
- Entries can be exported and imported
Quick install instructions
1) Be sure you have at least Moodle 1.2 dev installed
2) Be sure to have the latest version of the module
3) Be sure to have the latest language for english (en) and your own language.
3) Create a directory inside you /mod directory and name it: glossary
4) Copy all the files in this directory inside the one you've created in step 3.
5) Pay a visit to your admin area
6) Have fun.
Comments and suggestions are always welcome.
All the best,
Will
+19
View File
@@ -0,0 +1,19 @@
Things that are in the inkpot yet:
==================================
- Allow grading of entries
* Evaluation
* Self-evaluation?
* Co-evaluation?
********* IN BETA RIGHT NOW *********
- Adding a way to specify default values for display formats:
* Default view
* Default Order
* Show (or do not) the group breaks.
* Default view for automatic links, entry view, etc.
* What else? Post in http://moodle.org/mod/forum/view.php?id=742
News about plugin-formats TODO (Updated: Jul 30, 2004 - Eloy)
*Include support for a customised print view in each format.
+59
View File
@@ -0,0 +1,59 @@
<?php
require_once("../../config.php");
require_once("lib.php");
$eid = required_param('eid', PARAM_INT); // Entry ID
$newstate = optional_param('newstate', 1, PARAM_BOOL);
$mode = optional_param('mode', 'approval', PARAM_ALPHA);
$hook = optional_param('hook', 'ALL', PARAM_CLEAN);
$url = new moodle_url('/mod/glossary/approve.php', array('eid' => $eid, 'mode' => $mode, 'hook' => $hook, 'newstate' => $newstate));
$PAGE->set_url($url);
$entry = $DB->get_record('glossary_entries', array('id'=> $eid), '*', MUST_EXIST);
$glossary = $DB->get_record('glossary', array('id'=> $entry->glossaryid), '*', MUST_EXIST);
$cm = get_coursemodule_from_instance('glossary', $glossary->id, 0, false, MUST_EXIST);
$course = $DB->get_record('course', array('id'=> $cm->course), '*', MUST_EXIST);
require_login($course, false, $cm);
$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");
+159
View File
@@ -0,0 +1,159 @@
<?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/>.
/**
* Provides support for the conversion of moodle1 backup to the moodle2 format
*
* @package mod_glossary
* @copyright 2011 David Mudrak <david@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Glossary conversion handler
*/
class moodle1_mod_glossary_handler extends moodle1_mod_handler {
/** @var moodle1_file_manager */
protected $fileman = null;
/** @var int cmid */
protected $moduleid = null;
/**
* Declare the paths in moodle.xml we are able to convert
*
* The method returns list of {@link convert_path} instances.
* For each path returned, the corresponding conversion method must be
* defined.
*
* Note that the path /MOODLE_BACKUP/COURSE/MODULES/MOD/GLOSSARY does not
* actually exist in the file. The last element with the module name was
* appended by the moodle1_converter class.
*
* @return array of {@link convert_path} instances
*/
public function get_paths() {
return array(
new convert_path(
'glossary', '/MOODLE_BACKUP/COURSE/MODULES/MOD/GLOSSARY',
array(
'newfields' => array(
'introformat' => FORMAT_MOODLE,
'completionentries' => 0,
),
)
),
new convert_path('glossary_categories', '/MOODLE_BACKUP/COURSE/MODULES/MOD/GLOSSARY/CATEGORIES'),
new convert_path(
'glossary_category', '/MOODLE_BACKUP/COURSE/MODULES/MOD/GLOSSARY/CATEGORIES/CATEGORY',
array(
'dropfields' => array(
'glossaryid'
)
)
)
);
}
/**
* This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/GLOSSARY
* data available
*/
public function process_glossary($data) {
global $CFG;
// get the course module id and context id
$instanceid = $data['id'];
$cminfo = $this->get_cminfo($instanceid);
$this->moduleid = $cminfo['id'];
$contextid = $this->converter->get_contextid(CONTEXT_MODULE, $this->moduleid);
// replay the upgrade step 2009042006
if ($CFG->texteditors !== 'textarea') {
$data['intro'] = text_to_html($data['intro'], false, false, true);
$data['introformat'] = FORMAT_HTML;
}
// get a fresh new file manager for this instance
$this->fileman = $this->converter->get_file_manager($contextid, 'mod_glossary');
// convert course files embedded into the intro
$this->fileman->filearea = 'intro';
$this->fileman->itemid = 0;
$data['intro'] = moodle1_converter::migrate_referenced_files($data['intro'], $this->fileman);
// start writing glossary.xml
$this->open_xml_writer("activities/glossary_{$this->moduleid}/glossary.xml");
$this->xmlwriter->begin_tag('activity', array('id' => $instanceid, 'moduleid' => $this->moduleid,
'modulename' => 'glossary', 'contextid' => $contextid));
$this->xmlwriter->begin_tag('glossary', array('id' => $instanceid));
foreach ($data as $field => $value) {
if ($field <> 'id') {
$this->xmlwriter->full_tag($field, $value);
}
}
return $data;
}
/**
* This is executed when the parser reaches the <CATEGORIES> opening element
*/
public function on_glossary_categories_start() {
$this->xmlwriter->begin_tag('categories');
}
/**
* This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/GLOSSARY/CATEGORIES/CATEGORY
* data available
*/
public function process_glossary_category($data) {
$this->write_xml('category', $data, array('/category/id'));
}
/**
* This is executed when the parser reaches the closing </CATEGORIES> element
*/
public function on_glossary_categories_end() {
$this->xmlwriter->end_tag('categories');
}
/**
* This is executed when we reach the closing </MOD> tag of our 'glossary' path
*/
public function on_glossary_end() {
// finalize glossary.xml
$this->xmlwriter->end_tag('glossary');
$this->xmlwriter->end_tag('activity');
$this->close_xml_writer();
// write inforef.xml
$this->open_xml_writer("activities/glossary_{$this->moduleid}/inforef.xml");
$this->xmlwriter->begin_tag('inforef');
$this->xmlwriter->begin_tag('fileref');
foreach ($this->fileman->get_fileids() as $fileid) {
$this->write_xml('file', array('id' => $fileid));
}
$this->xmlwriter->end_tag('fileref');
$this->xmlwriter->end_tag('inforef');
$this->close_xml_writer();
}
}
@@ -0,0 +1,74 @@
<?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/>.
/**
* Defines backup_glossary_activity_task class
*
* @package mod_glossary
* @category backup
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/mod/glossary/backup/moodle2/backup_glossary_stepslib.php');
/**
* Provides the steps to perform one complete backup of the Glossary instance
*/
class backup_glossary_activity_task extends backup_activity_task {
/**
* No specific settings for this activity
*/
protected function define_my_settings() {
}
/**
* Defines a backup step to store the instance data in the glossary.xml file
*/
protected function define_my_steps() {
$this->add_step(new backup_glossary_activity_structure_step('glossary_structure', 'glossary.xml'));
}
/**
* Encodes URLs to the index.php and view.php scripts
*
* @param string $content some HTML text that eventually contains URLs to the activity instance scripts
* @return string the content with the URLs encoded
*/
public static function encode_content_links($content) {
global $CFG;
$base = preg_quote($CFG->wwwroot,"/");
// Link to the list of glossaries
$search="/(".$base."\/mod\/glossary\/index.php\?id\=)([0-9]+)/";
$content= preg_replace($search, '$@GLOSSARYINDEX*$2@$', $content);
// Link to glossary view by moduleid
$search="/(".$base."\/mod\/glossary\/view.php\?id\=)([0-9]+)/";
$content= preg_replace($search, '$@GLOSSARYVIEWBYID*$2@$', $content);
// Link to glossary entry
$search="/(".$base."\/mod\/glossary\/showentry.php\?courseid=)([0-9]+)(&|&amp;)eid=([0-9]+)/";
$content = preg_replace($search, '$@GLOSSARYSHOWENTRY*$2*$4@$', $content);
return $content;
}
}
@@ -0,0 +1,149 @@
<?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/>.
/**
* @package mod_glossary
* @subpackage backup-moodle2
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Define all the backup steps that will be used by the backup_glossary_activity_task
*/
/**
* Define the complete glossary structure for backup, with file and id annotations
*/
class backup_glossary_activity_structure_step extends backup_activity_structure_step {
protected function define_structure() {
// To know if we are including userinfo
$userinfo = $this->get_setting_value('userinfo');
// Define each element separated
$glossary = new backup_nested_element('glossary', array('id'), array(
'name', 'intro', 'introformat', 'allowduplicatedentries', 'displayformat',
'mainglossary', 'showspecial', 'showalphabet', 'showall',
'allowcomments', 'allowprintview', 'usedynalink', 'defaultapproval',
'globalglossary', 'entbypage', 'editalways', 'rsstype',
'rssarticles', 'assessed', 'assesstimestart', 'assesstimefinish',
'scale', 'timecreated', 'timemodified', 'completionentries'));
$entries = new backup_nested_element('entries');
$entry = new backup_nested_element('entry', array('id'), array(
'userid', 'concept', 'definition', 'definitionformat',
'definitiontrust', 'attachment', 'timecreated', 'timemodified',
'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(
'alias_text'));
$ratings = new backup_nested_element('ratings');
$rating = new backup_nested_element('rating', array('id'), array(
'component', 'ratingarea', 'scaleid', 'value', 'userid', 'timecreated', 'timemodified'));
$categories = new backup_nested_element('categories');
$category = new backup_nested_element('category', array('id'), array(
'name', 'usedynalink'));
$categoryentries = new backup_nested_element('category_entries');
$categoryentry = new backup_nested_element('category_entry', array('id'), array(
'entryid'));
// Build the tree
$glossary->add_child($entries);
$entries->add_child($entry);
$glossary->add_child($tags);
$tags->add_child($tag);
$entry->add_child($aliases);
$aliases->add_child($alias);
$entry->add_child($ratings);
$ratings->add_child($rating);
$glossary->add_child($categories);
$categories->add_child($category);
$category->add_child($categoryentries);
$categoryentries->add_child($categoryentry);
// Define sources
$glossary->set_source_table('glossary', array('id' => backup::VAR_ACTIVITYID));
$category->set_source_table('glossary_categories', array('glossaryid' => backup::VAR_PARENTID));
// All the rest of elements only happen if we are including user info
if ($userinfo) {
$entry->set_source_table('glossary_entries', array('glossaryid' => backup::VAR_PARENTID));
$alias->set_source_table('glossary_alias', array('entryid' => backup::VAR_PARENTID));
$alias->set_source_alias('alias', 'alias_text');
$rating->set_source_table('rating', array('contextid' => backup::VAR_CONTEXTID,
'itemid' => backup::VAR_PARENTID,
'component' => backup_helper::is_sqlparam('mod_glossary'),
'ratingarea' => backup_helper::is_sqlparam('entry')));
$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
$glossary->annotate_ids('scale', 'scale');
$entry->annotate_ids('user', 'userid');
$rating->annotate_ids('scale', 'scaleid');
$rating->annotate_ids('user', 'userid');
// Define file annotations
$glossary->annotate_files('mod_glossary', 'intro', null); // This file area hasn't itemid
$entry->annotate_files('mod_glossary', 'entry', 'id');
$entry->annotate_files('mod_glossary', 'attachment', 'id');
// Return the root element (glossary), wrapped into standard activity structure
return $this->prepare_activity_structure($glossary);
}
}
@@ -0,0 +1,121 @@
<?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/>.
/**
* @package mod_glossary
* @subpackage backup-moodle2
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/mod/glossary/backup/moodle2/restore_glossary_stepslib.php'); // Because it exists (must)
/**
* glossary restore task that provides all the settings and steps to perform one
* complete restore of the activity
*/
class restore_glossary_activity_task extends restore_activity_task {
/**
* Define (add) particular settings this activity can have
*/
protected function define_my_settings() {
// No particular settings for this activity
}
/**
* Define (add) particular steps this activity can have
*/
protected function define_my_steps() {
// Choice only has one structure step
$this->add_step(new restore_glossary_activity_structure_step('glossary_structure', 'glossary.xml'));
}
/**
* Define the contents in the activity that must be
* processed by the link decoder
*/
public static function define_decode_contents() {
$contents = array();
$contents[] = new restore_decode_content('glossary', array('intro'), 'glossary');
$contents[] = new restore_decode_content('glossary_entries', array('definition'), 'glossary_entry');
return $contents;
}
/**
* Define the decoding rules for links belonging
* to the activity to be executed by the link decoder
*/
public static function define_decode_rules() {
$rules = array();
$rules[] = new restore_decode_rule('GLOSSARYVIEWBYID', '/mod/glossary/view.php?id=$1', 'course_module');
$rules[] = new restore_decode_rule('GLOSSARYINDEX', '/mod/glossary/index.php?id=$1', 'course');
$rules[] = new restore_decode_rule('GLOSSARYSHOWENTRY', '/mod/glossary/showentry.php?courseid=$1&eid=$2',
array('course', 'glossary_entry'));
return $rules;
}
/**
* Define the restore log rules that will be applied
* by the {@link restore_logs_processor} when restoring
* glossary logs. It must return one array
* of {@link restore_log_rule} objects
*/
public static function define_restore_log_rules() {
$rules = array();
$rules[] = new restore_log_rule('glossary', 'add', 'view.php?id={course_module}', '{glossary}');
$rules[] = new restore_log_rule('glossary', 'update', 'view.php?id={course_module}', '{glossary}');
$rules[] = new restore_log_rule('glossary', 'view', 'view.php?id={course_module}', '{glossary}');
$rules[] = new restore_log_rule('glossary', 'add category', 'editcategories.php?id={course_module}', '{glossary_category}');
$rules[] = new restore_log_rule('glossary', 'edit category', 'editcategories.php?id={course_module}', '{glossary_category}');
$rules[] = new restore_log_rule('glossary', 'delete category', 'editcategories.php?id={course_module}', '{glossary_category}');
$rules[] = new restore_log_rule('glossary', 'add entry', 'view.php?id={course_module}&mode=entry&hook={glossary_entry}', '{glossary_entry}');
$rules[] = new restore_log_rule('glossary', 'update entry', 'view.php?id={course_module}&mode=entry&hook={glossary_entry}', '{glossary_entry}');
$rules[] = new restore_log_rule('glossary', 'delete entry', 'view.php?id={course_module}&mode=entry&hook={glossary_entry}', '{glossary_entry}');
$rules[] = new restore_log_rule('glossary', 'approve entry', 'showentry.php?id={course_module}&eid={glossary_entry}', '{glossary_entry}');
$rules[] = new restore_log_rule('glossary', 'disapprove entry', 'showentry.php?id={course_module}&eid={glossary_entry}', '{glossary_entry}');
$rules[] = new restore_log_rule('glossary', 'view entry', 'showentry.php?eid={glossary_entry}', '{glossary_entry}');
return $rules;
}
/**
* Define the restore log rules that will be applied
* by the {@link restore_logs_processor} when restoring
* course logs. It must return one array
* of {@link restore_log_rule} objects
*
* Note this rules are applied when restoring course logs
* by the restore final task, but are defined here at
* activity level. All them are rules not linked to any module instance (cmid = 0)
*/
public static function define_restore_log_rules_for_course() {
$rules = array();
$rules[] = new restore_log_rule('glossary', 'view all', 'index.php?id={course}', null);
return $rules;
}
}
@@ -0,0 +1,184 @@
<?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/>.
/**
* @package mod_glossary
* @subpackage backup-moodle2
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Define all the restore steps that will be used by the restore_glossary_activity_task
*/
/**
* Structure step to restore one glossary activity
*/
class restore_glossary_activity_structure_step extends restore_activity_structure_step {
protected function define_structure() {
$paths = array();
$userinfo = $this->get_setting_value('userinfo');
$paths[] = new restore_path_element('glossary', '/activity/glossary');
$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',
'/activity/glossary/categories/category/category_entries/category_entry');
}
// Return the paths wrapped into standard activity structure
return $this->prepare_activity_structure($paths);
}
protected function process_glossary($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->course = $this->get_courseid();
// Any changes to the list of dates that needs to be rolled should be same during course restore and course reset.
// See MDL-9367.
$data->assesstimestart = $this->apply_date_offset($data->assesstimestart);
$data->assesstimefinish = $this->apply_date_offset($data->assesstimefinish);
if ($data->scale < 0) { // scale found, get mapping
$data->scale = -($this->get_mappingid('scale', abs($data->scale)));
}
$formats = get_list_of_plugins('mod/glossary/formats'); // Check format
if (!in_array($data->displayformat, $formats)) {
$data->displayformat = 'dictionary';
}
if (!empty($data->globalglossary) && !has_capability('mod/glossary:manageentries', context_system::instance())) {
$data->globalglossary = 0;
}
if (!empty($data->mainglossary) and $data->mainglossary == 1 and
$DB->record_exists('glossary', array('mainglossary' => 1, 'course' => $this->get_courseid()))) {
// Only allow one main glossary in the course
$data->mainglossary = 0;
}
// insert the glossary record
$newitemid = $DB->insert_record('glossary', $data);
$this->apply_activity_instance($newitemid);
}
protected function process_glossary_entry($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->glossaryid = $this->get_new_parentid('glossary');
$data->userid = $this->get_mappingid('user', $data->userid);
$data->sourceglossaryid = $this->get_mappingid('glossary', $data->sourceglossaryid);
// insert the entry record
$newitemid = $DB->insert_record('glossary_entries', $data);
$this->set_mapping('glossary_entry', $oldid, $newitemid, true); // childs and files by itemname
}
protected function process_glossary_alias($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->entryid = $this->get_new_parentid('glossary_entry');
$data->alias = $data->alias_text;
$newitemid = $DB->insert_record('glossary_alias', $data);
}
protected function process_glossary_rating($data) {
global $DB;
$data = (object)$data;
// Cannot use ratings API, cause, it's missing the ability to specify times (modified/created)
$data->contextid = $this->task->get_contextid();
$data->itemid = $this->get_new_parentid('glossary_entry');
if ($data->scaleid < 0) { // scale found, get mapping
$data->scaleid = -($this->get_mappingid('scale', abs($data->scaleid)));
}
$data->rating = $data->value;
$data->userid = $this->get_mappingid('user', $data->userid);
// Make sure that we have both component and ratingarea set. These were added in 2.1.
// Prior to that all ratings were for entries so we know what to set them too.
if (empty($data->component)) {
$data->component = 'mod_glossary';
}
if (empty($data->ratingarea)) {
$data->ratingarea = 'entry';
}
$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;
$data = (object)$data;
$oldid = $data->id;
$data->glossaryid = $this->get_new_parentid('glossary');
$newitemid = $DB->insert_record('glossary_categories', $data);
$this->set_mapping('glossary_category', $oldid, $newitemid);
}
protected function process_glossary_category_entry($data) {
global $DB;
$data = (object)$data;
$oldid = $data->id;
$data->categoryid = $this->get_new_parentid('glossary_category');
$data->entryid = $this->get_mappingid('glossary_entry', $data->entryid);
$newitemid = $DB->insert_record('glossary_entries_categories', $data);
}
protected function after_execute() {
// Add glossary related files, no need to match by itemname (just internally handled context)
$this->add_related_files('mod_glossary', 'intro', null);
// Add entries related files, matching by itemname (glossary_entry)
$this->add_related_files('mod_glossary', 'entry', 'glossary_entry');
$this->add_related_files('mod_glossary', 'attachment', 'glossary_entry');
}
}
@@ -0,0 +1,153 @@
<?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/>.
defined('MOODLE_INTERNAL') || die();
/**
* Class for glossary display formats management.
*
* @package mod_glossary
* @copyright 2021 Andrew Davis
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_glossary_admin_setting_display_formats extends admin_setting {
/**
* Calls parent::__construct with specific arguments
*/
public function __construct() {
$this->nosave = true;
parent::__construct('glossarydisplayformats', get_string('displayformatssetup', 'glossary'), '', '');
}
/**
* Always returns true, does nothing
*
* @return true
*/
public function get_setting() {
return true;
}
/**
* Always returns true, does nothing
*
* @return true
*/
public function get_defaultsetting() {
return true;
}
/**
* Always returns '', does not write anything
*
* @param string $data Unused
* @return string Always returns ''
*/
public function write_setting($data) {
// Do not write any setting.
return '';
}
/**
* Checks if $query is one of the available display formats
*
* @param string $query The string to search for
* @return bool Returns true if found, false if not
*/
public function is_related($query) {
global $DB;
if (parent::is_related($query)) {
return true;
}
$query = core_text::strtolower($query);
$formats = $DB->get_records("glossary_formats");
foreach ($formats as $format) {
if (strpos(core_text::strtolower($format->name), $query) !== false) {
return true;
}
$localised = get_string("displayformat$format->name", "glossary");
if (strpos(core_text::strtolower($localised), $query) !== false) {
return true;
}
}
return false;
}
/**
* Builds the XHTML to display the control
*
* @param string $data Unused
* @param string $query
* @return string
*/
public function output_html($data, $query='') {
global $CFG, $OUTPUT, $DB;
$stredit = get_string("edit");
$strhide = get_string("hide");
$strshow = get_string("show");
$str = $OUTPUT->heading(get_string('displayformatssetup', 'glossary'), 3, 'main', true);
$recformats = $DB->get_records("glossary_formats");
$formats = array();
// Build alphabetized list of formats.
foreach ($recformats as $format) {
$formats[get_string("displayformat$format->name", "glossary")] = $format;
}
ksort($formats);
$table = new html_table();
$table->align = array('left', 'center');
foreach ($formats as $formatname => $format) {
$editicon = html_writer::link(
new moodle_url(
'/mod/glossary/formats.php',
array('id' => $format->id, 'mode' => 'edit')
),
$OUTPUT->pix_icon('t/edit', $stredit),
array('title' => $stredit));
if ( $format->visible ) {
$vtitle = $strhide;
$vicon = "t/hide";
} else {
$vtitle = $strshow;
$vicon = "t/show";
}
$visibleicon = html_writer::link(
new moodle_url(
'/mod/glossary/formats.php',
array('id' => $format->id, 'mode' => 'visible', 'sesskey' => sesskey())
),
$OUTPUT->pix_icon($vicon, $vtitle),
array('title' => $vtitle)
);
$table->data[] = array(
$formatname,
$editicon . '&nbsp;&nbsp;' . $visibleicon
);
}
$str .= html_writer::table($table);
return highlight($query, $str);
}
}
@@ -0,0 +1,37 @@
<?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/>.
/**
* Activity base class.
*
* @package mod_glossary
* @copyright 2017 onwards Ankit Agarwal <ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\analytics\indicator;
defined('MOODLE_INTERNAL') || die();
/**
* Activity base class.
*
* @package mod_glossary
* @copyright 2017 onwards Ankit Agarwal <ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class activity_base extends \core_analytics\local\indicator\community_of_inquiry_activity {
}
@@ -0,0 +1,56 @@
<?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/>.
/**
* Cognitive depth indicator - glossary.
*
* @package mod_glossary
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\analytics\indicator;
defined('MOODLE_INTERNAL') || die();
/**
* Cognitive depth indicator - glossary.
*
* @package mod_glossary
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class cognitive_depth extends activity_base {
/**
* Returns the name.
*
* If there is a corresponding '_help' string this will be shown as well.
*
* @return \lang_string
*/
public static function get_name(): \lang_string {
return new \lang_string('indicator:cognitivedepth', 'mod_glossary');
}
public function get_indicator_type() {
return self::INDICATOR_COGNITIVE;
}
public function get_cognitive_depth_level(\cm_info $cm) {
return self::COGNITIVE_LEVEL_2;
}
}
@@ -0,0 +1,56 @@
<?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/>.
/**
* Social breadth indicator - glossary.
*
* @package mod_glossary
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\analytics\indicator;
defined('MOODLE_INTERNAL') || die();
/**
* Social breadth indicator - glossary.
*
* @package mod_glossary
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class social_breadth extends activity_base {
/**
* Returns the name.
*
* If there is a corresponding '_help' string this will be shown as well.
*
* @return \lang_string
*/
public static function get_name(): \lang_string {
return new \lang_string('indicator:socialbreadth', 'mod_glossary');
}
public function get_indicator_type() {
return self::INDICATOR_SOCIAL;
}
public function get_social_breadth_level(\cm_info $cm) {
return self::SOCIAL_LEVEL_1;
}
}
@@ -0,0 +1,90 @@
<?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/>.
declare(strict_types=1);
namespace mod_glossary\completion;
use core_completion\activity_custom_completion;
/**
* Activity custom completion subclass for the glossary activity.
*
* Class for defining mod_glossary's custom completion rules and fetching the completion statuses
* of the custom completion rules for a given glossary instance and a user.
*
* @package mod_glossary
* @copyright Simey Lameze <simey@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class custom_completion extends activity_custom_completion {
/**
* Fetches the completion state for a given completion rule.
*
* @param string $rule The completion rule.
* @return int The completion state.
*/
public function get_state(string $rule): int {
global $DB;
$this->validate_rule($rule);
$glossaryid = $this->cm->instance;
$userid = $this->userid;
$userentries = $DB->count_records('glossary_entries', ['glossaryid' => $glossaryid, 'userid' => $userid,
'approved' => 1]);
$completionentries = $this->cm->customdata['customcompletionrules']['completionentries'];
return ($completionentries <= $userentries) ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE;
}
/**
* Fetch the list of custom completion rules that this module defines.
*
* @return array
*/
public static function get_defined_custom_rules(): array {
return ['completionentries'];
}
/**
* Returns an associative array of the descriptions of custom completion rules.
*
* @return array
*/
public function get_custom_rule_descriptions(): array {
$completionentries = $this->cm->customdata['customcompletionrules']['completionentries'] ?? 0;
return [
'completionentries' => get_string('completiondetail:entries', 'glossary', $completionentries),
];
}
/**
* Returns an array of all completion rules, in the order they should be displayed to users.
*
* @return array
*/
public function get_sort_order(): array {
return [
'completionview',
'completionentries',
'completionusegrade',
'completionpassgrade',
];
}
}
@@ -0,0 +1,473 @@
<?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/>.
/**
* Entry query builder.
*
* @package mod_glossary
* @copyright 2015 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Entry query builder class.
*
* The purpose of this class is to avoid duplicating SQL statements to fetch entries
* which are very similar with each other. This builder is not meant to be smart, it
* will not out rule any previously set condition, or join, etc...
*
* You should be using this builder just like you would be creating your SQL query. Only
* some methods are shorthands to avoid logic duplication and common mistakes.
*
* @package mod_glossary
* @copyright 2015 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.1
*/
class mod_glossary_entry_query_builder {
/** Alias for table glossary_alias. */
const ALIAS_ALIAS = 'ga';
/** Alias for table glossary_categories. */
const ALIAS_CATEGORIES = 'gc';
/** Alias for table glossary_entries_categories. */
const ALIAS_ENTRIES_CATEGORIES = 'gec';
/** Alias for table glossary_entries. */
const ALIAS_ENTRIES = 'ge';
/** Alias for table user. */
const ALIAS_USER = 'u';
/** Include none of the entries to approve. */
const NON_APPROVED_NONE = 'na_none';
/** Including all the entries. */
const NON_APPROVED_ALL = 'na_all';
/** Including only the entries to be approved. */
const NON_APPROVED_ONLY = 'na_only';
/** Including my entries to be approved. */
const NON_APPROVED_SELF = 'na_self';
/** @var array Raw SQL statements representing the fields to select. */
protected $fields = array();
/** @var array Raw SQL statements representing the JOINs to make. */
protected $joins = array();
/** @var string Raw SQL statement representing the FROM clause. */
protected $from;
/** @var object The glossary we are fetching from. */
protected $glossary;
/** @var int The number of records to fetch from. */
protected $limitfrom = 0;
/** @var int The number of records to fetch. */
protected $limitnum = 0;
/** @var array List of SQL parameters. */
protected $params = array();
/** @var array Raw SQL statements representing the ORDER clause. */
protected $order = array();
/** @var array Raw SQL statements representing the WHERE clause. */
protected $where = array();
/**
* Constructor.
*
* @param object $glossary The glossary.
*/
public function __construct($glossary = null) {
$this->from = sprintf('FROM {glossary_entries} %s', self::ALIAS_ENTRIES);
if (!empty($glossary)) {
$this->glossary = $glossary;
$this->where[] = sprintf('(%s.glossaryid = :gid OR %s.sourceglossaryid = :gid2)',
self::ALIAS_ENTRIES, self::ALIAS_ENTRIES);
$this->params['gid'] = $glossary->id;
$this->params['gid2'] = $glossary->id;
}
}
/**
* Add a field to select.
*
* @param string $field The field, or *.
* @param string $table The table name, without the prefix 'glossary_'.
* @param string $alias An alias for the field.
*/
public function add_field($field, $table, $alias = null) {
$field = self::resolve_field($field, $table);
if (!empty($alias)) {
$field .= ' AS ' . $alias;
}
$this->fields[] = $field;
}
/**
* Adds the user fields.
*
* @return void
*/
public function add_user_fields() {
$userfieldsapi = \core_user\fields::for_userpic();
$fields = $userfieldsapi->get_sql('u', false, 'userdata', '', false)->selects;
$this->fields[] = $fields;
}
/**
* Internal method to build the query.
*
* @param bool $count Query to count?
* @return string The SQL statement.
*/
protected function build_query($count = false) {
$sql = 'SELECT ';
if ($count) {
$sql .= 'COUNT(\'x\') ';
} else {
$sql .= implode(', ', $this->fields) . ' ';
}
$sql .= $this->from . ' ';
$sql .= implode(' ', $this->joins) . ' ';
if (!empty($this->where)) {
$sql .= 'WHERE (' . implode(') AND (', $this->where) . ') ';
}
if (!$count && !empty($this->order)) {
$sql .= 'ORDER BY ' . implode(', ', $this->order);
}
return $sql;
}
/**
* Count the records.
*
* @return int The number of records.
*/
public function count_records() {
global $DB;
return $DB->count_records_sql($this->build_query(true), $this->params);
}
/**
* Filter a field using a letter.
*
* @param string $letter The letter.
* @param string $finalfield The SQL statement representing the field.
*/
protected function filter_by_letter($letter, $finalfield) {
global $DB;
$letter = core_text::strtoupper($letter);
$len = core_text::strlen($letter);
$sql = $DB->sql_substr(sprintf('upper(%s)', $finalfield), 1, $len);
$this->where[] = "$sql = :letter";
$this->params['letter'] = $letter;
}
/**
* Filter a field by special characters.
*
* @param string $finalfield The SQL statement representing the field.
*/
protected function filter_by_non_letter($finalfield) {
global $DB;
$alphabet = explode(',', get_string('alphabet', 'langconfig'));
list($nia, $aparams) = $DB->get_in_or_equal($alphabet, SQL_PARAMS_NAMED, 'nonletter', false);
$sql = $DB->sql_substr(sprintf('upper(%s)', $finalfield), 1, 1);
$this->where[] = "$sql $nia";
$this->params = array_merge($this->params, $aparams);
}
/**
* Filter the author by letter.
*
* @param string $letter The letter.
* @param bool $firstnamefirst Whether or not the firstname is first in the author's name.
*/
public function filter_by_author_letter($letter, $firstnamefirst = false) {
$field = self::get_fullname_field($firstnamefirst);
$this->filter_by_letter($letter, $field);
}
/**
* Filter the author by special characters.
*
* @param bool $firstnamefirst Whether or not the firstname is first in the author's name.
*/
public function filter_by_author_non_letter($firstnamefirst = false) {
$field = self::get_fullname_field($firstnamefirst);
$this->filter_by_non_letter($field);
}
/**
* Filter the concept by letter.
*
* @param string $letter The letter.
*/
public function filter_by_concept_letter($letter) {
$this->filter_by_letter($letter, self::resolve_field('concept', 'entries'));
}
/**
* Filter the concept by special characters.
*
* @return void
*/
public function filter_by_concept_non_letter() {
$this->filter_by_non_letter(self::resolve_field('concept', 'entries'));
}
/**
* Filter non approved entries.
*
* @param string $constant One of the NON_APPROVED_* constants.
* @param int $userid The user ID when relevant, otherwise current user.
*/
public function filter_by_non_approved($constant, $userid = null) {
global $USER;
if (!$userid) {
$userid = $USER->id;
}
if ($constant === self::NON_APPROVED_ALL) {
// Nothing to do.
} else if ($constant === self::NON_APPROVED_SELF) {
$this->where[] = sprintf('%s != 0 OR %s = :toapproveuserid',
self::resolve_field('approved', 'entries'), self::resolve_field('userid', 'entries'));
$this->params['toapproveuserid'] = $USER->id;
} else if ($constant === self::NON_APPROVED_NONE) {
$this->where[] = sprintf('%s != 0', self::resolve_field('approved', 'entries'));
} else if ($constant === self::NON_APPROVED_ONLY) {
$this->where[] = sprintf('%s = 0', self::resolve_field('approved', 'entries'));
} else {
throw new coding_exception('Invalid constant');
}
}
/**
* Filter by concept or alias.
*
* This requires the alias table to be joined in the query. See {@link self::join_alias()}.
*
* @param string $term What the concept or aliases should be.
*/
public function filter_by_term($term) {
$this->where[] = sprintf("(%s = :filterterma OR %s = :filtertermb)",
self::resolve_field('concept', 'entries'),
self::resolve_field('alias', 'alias'));
$this->params['filterterma'] = $term;
$this->params['filtertermb'] = $term;
}
/**
* Convenience method to get get the SQL statement for the full name.
*
* @param bool $firstnamefirst Whether or not the firstname is first in the author's name.
* @return string The SQL statement.
*/
public static function get_fullname_field($firstnamefirst = false) {
global $DB;
if ($firstnamefirst) {
return $DB->sql_fullname(self::resolve_field('firstname', 'user'), self::resolve_field('lastname', 'user'));
}
return $DB->sql_fullname(self::resolve_field('lastname', 'user'), self::resolve_field('firstname', 'user'));
}
/**
* Get the records.
*
* @return array
*/
public function get_records() {
global $DB;
return $DB->get_records_sql($this->build_query(), $this->params, $this->limitfrom, $this->limitnum);
}
/**
* Get the recordset.
*
* @return moodle_recordset
*/
public function get_recordset() {
global $DB;
return $DB->get_recordset_sql($this->build_query(), $this->params, $this->limitfrom, $this->limitnum);
}
/**
* Retrieve a user object from a record.
*
* This comes handy when {@link self::add_user_fields} was used.
*
* @param stdClass $record The record.
* @return stdClass A user object.
*/
public static function get_user_from_record($record) {
return user_picture::unalias($record, null, 'userdataid', 'userdata');
}
/**
* Join the alias table.
*
* Note that this may cause the same entry to be returned more than once. You might want
* to add a distinct on the entry id.
*
* @return void
*/
public function join_alias() {
$this->joins[] = sprintf('LEFT JOIN {glossary_alias} %s ON %s = %s',
self::ALIAS_ALIAS, self::resolve_field('id', 'entries'), self::resolve_field('entryid', 'alias'));
}
/**
* Join on the category tables.
*
* Depending on the category passed the joins will be different. This is due to the display
* logic that assumes that when displaying all categories the non categorised entries should
* not be returned, etc...
*
* @param int $categoryid The category ID, or GLOSSARY_SHOW_* constant.
*/
public function join_category($categoryid) {
if ($categoryid === GLOSSARY_SHOW_ALL_CATEGORIES) {
$this->joins[] = sprintf('JOIN {glossary_entries_categories} %s ON %s = %s',
self::ALIAS_ENTRIES_CATEGORIES, self::resolve_field('id', 'entries'),
self::resolve_field('entryid', 'entries_categories'));
$this->joins[] = sprintf('JOIN {glossary_categories} %s ON %s = %s',
self::ALIAS_CATEGORIES, self::resolve_field('id', 'categories'),
self::resolve_field('categoryid', 'entries_categories'));
} else if ($categoryid === GLOSSARY_SHOW_NOT_CATEGORISED) {
$this->joins[] = sprintf('LEFT JOIN {glossary_entries_categories} %s ON %s = %s',
self::ALIAS_ENTRIES_CATEGORIES, self::resolve_field('id', 'entries'),
self::resolve_field('entryid', 'entries_categories'));
} else {
$this->joins[] = sprintf('JOIN {glossary_entries_categories} %s ON %s = %s AND %s = :joincategoryid',
self::ALIAS_ENTRIES_CATEGORIES, self::resolve_field('id', 'entries'),
self::resolve_field('entryid', 'entries_categories'),
self::resolve_field('categoryid', 'entries_categories'));
$this->params['joincategoryid'] = $categoryid;
}
}
/**
* Join the user table.
*
* @param bool $strict When strict uses a JOIN rather than a LEFT JOIN.
*/
public function join_user($strict = false) {
$join = $strict ? 'JOIN' : 'LEFT JOIN';
$this->joins[] = sprintf("$join {user} %s ON %s = %s",
self::ALIAS_USER, self::resolve_field('id', 'user'), self::resolve_field('userid', 'entries'));
}
/**
* Limit the number of records to fetch.
* @param int $from Fetch from.
* @param int $num Number to fetch.
*/
public function limit($from, $num) {
$this->limitfrom = $from;
$this->limitnum = $num;
}
/**
* Normalise a direction.
*
* This ensures that the value is either ASC or DESC.
*
* @param string $direction The desired direction.
* @return string ASC or DESC.
*/
protected function normalize_direction($direction) {
$direction = core_text::strtoupper($direction);
if ($direction == 'DESC') {
return 'DESC';
}
return 'ASC';
}
/**
* Order by a field.
*
* @param string $field The field, or *.
* @param string $table The table name, without the prefix 'glossary_'.
* @param string $direction ASC, or DESC.
*/
public function order_by($field, $table, $direction = '') {
$direction = self::normalize_direction($direction);
$this->order[] = self::resolve_field($field, $table) . ' ' . $direction;
}
/**
* Order by author name.
*
* @param bool $firstnamefirst Whether or not the firstname is first in the author's name.
* @param string $direction ASC, or DESC.
*/
public function order_by_author($firstnamefirst = false, $direction = '') {
$field = self::get_fullname_field($firstnamefirst);
$direction = self::normalize_direction($direction);
$this->order[] = $field . ' ' . $direction;
}
/**
* Convenience method to transform a field into SQL statement.
*
* @param string $field The field, or *.
* @param string $table The table name, without the prefix 'glossary_'.
* @return string SQL statement.
*/
protected static function resolve_field($field, $table) {
$prefix = constant(__CLASS__ . '::ALIAS_' . core_text::strtoupper($table));
return sprintf('%s.%s', $prefix, $field);
}
/**
* Simple where conditions.
*
* @param string $field The field, or *.
* @param string $table The table name, without the prefix 'glossary_'.
* @param mixed $value The value to be equal to.
*/
public function where($field, $table, $value) {
static $i = 0;
$sql = self::resolve_field($field, $table) . ' ';
if ($value === null) {
$sql .= 'IS NULL';
} else {
$param = 'where' . $i++;
$sql .= " = :$param";
$this->params[$param] = $value;
}
$this->where[] = $sql;
}
}
@@ -0,0 +1,93 @@
<?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/>.
/**
* The mod_glossary glossary category created event.
*
* @package mod_glossary
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_glossary glossary category created event class.
*
* @package mod_glossary
* @since Moodle 2.7
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class category_created extends \core\event\base {
/**
* Init method
*/
protected function init() {
$this->data['crud'] = 'c';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
$this->data['objecttable'] = 'glossary_categories';
}
/**
* Returns localised general event name.
*
* @return string
*/
public static function get_name() {
return get_string('eventcategorycreated', 'mod_glossary');
}
/**
* Returns non-localised event description with id's for admin use only.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' created the category with id '$this->objectid' for the " .
"glossary activity with course module id '$this->contextinstanceid'.";
}
/**
* Get URL related to the action.
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url("/mod/glossary/editcategories.php",
array('id' => $this->contextinstanceid));
}
/**
* Custom validation.
*
* @throws \coding_exception
* @return void
*/
protected function validate_data() {
parent::validate_data();
// Make sure this class is never used without proper object details.
if (!$this->contextlevel === CONTEXT_MODULE) {
throw new \coding_exception('Context level must be CONTEXT_MODULE.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'glossary_categories', 'restore' => 'glossary_category');
}
}
@@ -0,0 +1,93 @@
<?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/>.
/**
* The mod_glossary glossary category deleted event.
*
* @package mod_glossary
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_glossary glossary category deleted event class.
*
* @package mod_glossary
* @since Moodle 2.7
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class category_deleted extends \core\event\base {
/**
* Init method
*/
protected function init() {
$this->data['crud'] = 'd';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
$this->data['objecttable'] = 'glossary_categories';
}
/**
* Returns localised general event name.
*
* @return string
*/
public static function get_name() {
return get_string('eventcategorydeleted', 'mod_glossary');
}
/**
* Returns non-localised event description with id's for admin use only.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' deleted the category with id '$this->objectid' in the " .
"glossary activity with course module id '$this->contextinstanceid'.";
}
/**
* Get URL related to the action.
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url("/mod/glossary/editcategories.php",
array('id' => $this->contextinstanceid));
}
/**
* Custom validation.
*
* @throws \coding_exception
* @return void
*/
protected function validate_data() {
parent::validate_data();
// Make sure this class is never used without proper object details.
if (!$this->contextlevel === CONTEXT_MODULE) {
throw new \coding_exception('Context level must be CONTEXT_MODULE.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'glossary_categories', 'restore' => 'glossary_category');
}
}
@@ -0,0 +1,93 @@
<?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/>.
/**
* The mod_glossary glossary category updated event.
*
* @package mod_glossary
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_glossary glossary category updated event class.
*
* @package mod_glossary
* @since Moodle 2.7
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class category_updated extends \core\event\base {
/**
* Init method
*/
protected function init() {
$this->data['crud'] = 'u';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
$this->data['objecttable'] = 'glossary_categories';
}
/**
* Returns localised general event name.
*
* @return string
*/
public static function get_name() {
return get_string('eventcategoryupdated', 'mod_glossary');
}
/**
* Returns non-localised event description with id's for admin use only.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' updated the category with id '$this->objectid' in the " .
"glossary activity with course module id '$this->contextinstanceid'.";
}
/**
* Get URL related to the action.
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url("/mod/glossary/editcategories.php",
array('id' => $this->contextinstanceid));
}
/**
* Custom validation.
*
* @throws \coding_exception
* @return void
*/
protected function validate_data() {
parent::validate_data();
// Make sure this class is never used without proper object details.
if (!$this->contextlevel === CONTEXT_MODULE) {
throw new \coding_exception('Context level must be CONTEXT_MODULE.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'glossary_categories', 'restore' => 'glossary_category');
}
}
@@ -0,0 +1,55 @@
<?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/>.
/**
* The mod_glossary comment created event.
*
* @package mod_glossary
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_glossary comment created event class.
*
* @package mod_glossary
* @since Moodle 2.7
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class comment_created extends \core\event\comment_created {
/**
* Get URL related to the action.
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url('/mod/glossary/view.php', array('id' => $this->contextinstanceid));
}
/**
* Returns description of what happened.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' added the comment with id '$this->objectid' to the glossary activity " .
"with course module id '$this->contextinstanceid'.";
}
}
@@ -0,0 +1,55 @@
<?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/>.
/**
* The mod_glossary comment deleted event.
*
* @package mod_glossary
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_glossary comment deleted event class.
*
* @package mod_glossary
* @since Moodle 2.7
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class comment_deleted extends \core\event\comment_deleted {
/**
* Get URL related to the action.
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url('/mod/glossary/view.php', array('id' => $this->contextinstanceid));
}
/**
* Returns description of what happened.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' deleted the comment with id '$this->objectid' from the glossary activity " .
"with course module id '$this->contextinstanceid'.";
}
}
@@ -0,0 +1,39 @@
<?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/>.
/**
* The mod_glossary instance list viewed event.
*
* @package mod_glossary
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_glossary instance list viewed event class.
*
* @package mod_glossary
* @since Moodle 2.7
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class course_module_instance_list_viewed extends \core\event\course_module_instance_list_viewed {
// No code required here as the parent class handles it all.
}
@@ -0,0 +1,74 @@
<?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/>.
/**
* The mod_glossary course module viewed event.
*
* @package mod_glossary
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_glossary course module viewed event class.
*
* @property-read array $other {
* Extra information about event.
*
* - string mode: (optional)
* }
*
* @package mod_glossary
* @since Moodle 2.7
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class course_module_viewed extends \core\event\course_module_viewed {
/**
* Init method.
*/
protected function init() {
$this->data['crud'] = 'r';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
$this->data['objecttable'] = 'glossary';
}
/**
* Get URL related to the action.
*
* @return \moodle_url
*/
public function get_url() {
$params = array('id' => $this->contextinstanceid);
if (!empty($this->other['mode'])) {
$params['mode'] = $this->other['mode'];
}
return new \moodle_url("/mod/$this->objecttable/view.php", $params);
}
public static function get_objectid_mapping() {
return array('db' => 'glossary', 'restore' => 'glossary');
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}
@@ -0,0 +1,95 @@
<?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/>.
/**
* The mod_glossary entry approved event.
*
* @package mod_glossary
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_glossary entry approved event class.
*
* @package mod_glossary
* @since Moodle 2.7
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class entry_approved extends \core\event\base {
/**
* Init method
*/
protected function init() {
$this->data['crud'] = 'u';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
$this->data['objecttable'] = 'glossary_entries';
}
/**
* Returns localised general event name.
*
* @return string
*/
public static function get_name() {
return get_string('evententryapproved', 'mod_glossary');
}
/**
* Returns non-localised event description with id's for admin use only.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' has approved the glossary entry with id '$this->objectid' for " .
"the glossary activity with course module id '$this->contextinstanceid'.";
}
/**
* Get URL related to the action.
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url("/mod/glossary/view.php",
array('id' => $this->contextinstanceid,
'mode' => 'entry',
'hook' => $this->objectid));
}
/**
* Custom validation.
*
* @throws \coding_exception
* @return void
*/
protected function validate_data() {
parent::validate_data();
// Make sure this class is never used without proper object details.
if (!$this->contextlevel === CONTEXT_MODULE) {
throw new \coding_exception('Context level must be CONTEXT_MODULE.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'glossary_entries', 'restore' => 'glossary_entry');
}
}
@@ -0,0 +1,106 @@
<?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/>.
/**
* The mod_glossary entry created event.
*
* @package mod_glossary
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_glossary entry created event class.
*
* @property-read array $other {
* Extra information about event.
*
* - string concept: (optional) the concept of created entry.
* }
*
* @package mod_glossary
* @since Moodle 2.7
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class entry_created extends \core\event\base {
/**
* Init method
*/
protected function init() {
$this->data['crud'] = 'c';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
$this->data['objecttable'] = 'glossary_entries';
}
/**
* Returns localised general event name.
*
* @return string
*/
public static function get_name() {
return get_string('evententrycreated', 'mod_glossary');
}
/**
* Returns non-localised event description with id's for admin use only.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' has created the glossary entry with id '$this->objectid' for " .
"the glossary activity with course module id '$this->contextinstanceid'.";
}
/**
* Get URL related to the action.
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url("/mod/glossary/view.php",
array('id' => $this->contextinstanceid,
'mode' => 'entry',
'hook' => $this->objectid));
}
/**
* Custom validation.
*
* @throws \coding_exception
* @return void
*/
protected function validate_data() {
parent::validate_data();
// Make sure this class is never used without proper object details.
if (!$this->contextlevel === CONTEXT_MODULE) {
throw new \coding_exception('Context level must be CONTEXT_MODULE.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'glossary_entries', 'restore' => 'glossary_entry');
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}
@@ -0,0 +1,113 @@
<?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/>.
/**
* The mod_glossary entry deleted event.
*
* @package mod_glossary
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_glossary entry deleted event class.
*
* @property-read array $other {
* Extra information about event.
*
* - string concept: (optional) the concept of deleted entry.
* - string mode: (optional) view mode user was in before deleting entry.
* - int|string hook: (optional) hook parameter in the previous view mode.
* }
*
* @package mod_glossary
* @since Moodle 2.7
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class entry_deleted extends \core\event\base {
/**
* Init method
*/
protected function init() {
$this->data['crud'] = 'd';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
$this->data['objecttable'] = 'glossary_entries';
}
/**
* Returns localised general event name.
*
* @return string
*/
public static function get_name() {
return get_string('evententrydeleted', 'mod_glossary');
}
/**
* Returns non-localised event description with id's for admin use only.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' has deleted the glossary entry with id '$this->objectid' in " .
"the glossary activity with course module id '$this->contextinstanceid'.";
}
/**
* Get URL related to the action.
*
* @return \moodle_url
*/
public function get_url() {
// Entry does not exist any more, returning link to the module view page in the mode it was before deleting entry.
$params = array('id' => $this->contextinstanceid);
if (isset($this->other['hook'])) {
$params['hook'] = $this->other['hook'];
}
if (isset($this->other['mode'])) {
$params['mode'] = $this->other['mode'];
}
return new \moodle_url("/mod/glossary/view.php", $params);
}
/**
* Custom validation.
*
* @throws \coding_exception
* @return void
*/
protected function validate_data() {
parent::validate_data();
// Make sure this class is never used without proper object details.
if (!$this->contextlevel === CONTEXT_MODULE) {
throw new \coding_exception('Context level must be CONTEXT_MODULE.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'glossary_entries', 'restore' => 'glossary_entry');
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}
@@ -0,0 +1,95 @@
<?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/>.
/**
* The mod_glossary entry disapproved event.
*
* @package mod_glossary
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_glossary entry disapproved event.
*
* @package mod_glossary
* @since Moodle 2.7
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class entry_disapproved extends \core\event\base {
/**
* Init method
*/
protected function init() {
$this->data['crud'] = 'u';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
$this->data['objecttable'] = 'glossary_entries';
}
/**
* Returns localised general event name.
*
* @return string
*/
public static function get_name() {
return get_string('evententrydisapproved', 'mod_glossary');
}
/**
* Returns non-localised event description with id's for admin use only.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' has disapproved the glossary entry with id '$this->objectid' for " .
"the glossary activity with course module id '$this->contextinstanceid'.";
}
/**
* Get URL related to the action.
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url("/mod/glossary/view.php",
array('id' => $this->contextinstanceid,
'mode' => 'entry',
'hook' => $this->objectid));
}
/**
* Custom validation.
*
* @throws \coding_exception
* @return void
*/
protected function validate_data() {
parent::validate_data();
// Make sure this class is never used without proper object details.
if (!$this->contextlevel === CONTEXT_MODULE) {
throw new \coding_exception('Context level must be CONTEXT_MODULE.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'glossary_entries', 'restore' => 'glossary_entry');
}
}
@@ -0,0 +1,106 @@
<?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/>.
/**
* The mod_glossary entry updated event.
*
* @package mod_glossary
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_glossary entry updated event.
*
* @property-read array $other {
* Extra information about event.
*
* - string concept: (optional) the concept of updated entry (after update).
* }
*
* @package mod_glossary
* @since Moodle 2.7
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class entry_updated extends \core\event\base {
/**
* Init method
*/
protected function init() {
$this->data['crud'] = 'u';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
$this->data['objecttable'] = 'glossary_entries';
}
/**
* Returns localised general event name.
*
* @return string
*/
public static function get_name() {
return get_string('evententryupdated', 'mod_glossary');
}
/**
* Returns non-localised event description with id's for admin use only.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' has updated the glossary entry with id '$this->objectid' in " .
"the glossary activity with course module id '$this->contextinstanceid'.";
}
/**
* Get URL related to the action.
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url("/mod/glossary/view.php",
array('id' => $this->contextinstanceid,
'mode' => 'entry',
'hook' => $this->objectid));
}
/**
* Custom validation.
*
* @throws \coding_exception
* @return void
*/
protected function validate_data() {
parent::validate_data();
// Make sure this class is never used without proper object details.
if (!$this->contextlevel === CONTEXT_MODULE) {
throw new \coding_exception('Context level must be CONTEXT_MODULE.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'glossary_entries', 'restore' => 'glossary_entry');
}
public static function get_other_mapping() {
// Nothing to map.
return false;
}
}
@@ -0,0 +1,95 @@
<?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/>.
/**
* The mod_glossary entry viwed event.
*
* @package mod_glossary
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\event;
defined('MOODLE_INTERNAL') || die();
/**
* The mod_glossary entry viewed event class.
*
* Triggered when glossary entry is autolinked and viewed by user from another context.
*
* @package mod_glossary
* @since Moodle 2.7
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class entry_viewed extends \core\event\base {
/**
* Init method
*/
protected function init() {
$this->data['crud'] = 'r';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
$this->data['objecttable'] = 'glossary_entries';
}
/**
* Returns localised general event name.
*
* @return string
*/
public static function get_name() {
return get_string('evententryviewed', 'mod_glossary');
}
/**
* Returns non-localised event description with id's for admin use only.
*
* @return string
*/
public function get_description() {
return "The user with id '$this->userid' has viewed the glossary entry with id '$this->objectid' in " .
"the glossary activity with course module id '$this->contextinstanceid'.";
}
/**
* Get URL related to the action.
*
* @return \moodle_url
*/
public function get_url() {
return new \moodle_url("/mod/glossary/showentry.php",
array('eid' => $this->objectid));
}
/**
* Custom validation.
*
* @throws \coding_exception
* @return void
*/
protected function validate_data() {
parent::validate_data();
// Make sure this class is never used without proper object details.
if (!$this->contextlevel === CONTEXT_MODULE) {
throw new \coding_exception('Context level must be CONTEXT_MODULE.');
}
}
public static function get_objectid_mapping() {
return array('db' => 'glossary_entries', 'restore' => 'glossary_entry');
}
}
File diff suppressed because it is too large Load Diff
+95
View File
@@ -0,0 +1,95 @@
<?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/>.
/**
* This is the external method for deleting a content.
*
* @package mod_glossary
* @since Moodle 3.10
* @copyright 2020 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/glossary/lib.php');
use core_external\external_api;
use core_external\external_function_parameters;
use core_external\external_single_structure;
use core_external\external_value;
use core_external\external_warnings;
/**
* This is the external method for deleting a content.
*
* @copyright 2020 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class delete_entry extends external_api {
/**
* Parameters.
*
* @return external_function_parameters
*/
public static function execute_parameters(): external_function_parameters {
return new external_function_parameters([
'entryid' => new external_value(PARAM_INT, 'Glossary entry id to delete'),
]);
}
/**
* Delete the indicated entry from the glossary.
*
* @param int $entryid The entry to delete
* @return array with result and warnings
* @throws moodle_exception
*/
public static function execute(int $entryid): array {
global $DB;
$params = self::validate_parameters(self::execute_parameters(), compact('entryid'));
$id = $params['entryid'];
// Get and validate the glossary.
$entry = $DB->get_record('glossary_entries', ['id' => $id], '*', MUST_EXIST);
list($glossary, $context, $course, $cm) = \mod_glossary_external::validate_glossary($entry->glossaryid);
// Check and delete.
mod_glossary_can_delete_entry($entry, $glossary, $context, false);
mod_glossary_delete_entry($entry, $glossary, $cm, $context, $course);
return [
'result' => true,
'warnings' => [],
];
}
/**
* Return.
*
* @return external_single_structure
*/
public static function execute_returns(): external_single_structure {
return new external_single_structure([
'result' => new external_value(PARAM_BOOL, 'The processing result'),
'warnings' => new external_warnings()
]);
}
}
+152
View File
@@ -0,0 +1,152 @@
<?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/>.
/**
* This is the external method for preparing a entry for edition.
*
* @package mod_glossary
* @since Moodle 3.10
* @copyright 2020 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/glossary/lib.php');
use core_external\external_api;
use core_external\external_function_parameters;
use core_external\external_multiple_structure;
use core_external\external_single_structure;
use core_external\external_value;
use core_external\external_warnings;
/**
* This is the external method for preparing a entry for edition.
*
* @copyright 2020 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class prepare_entry extends external_api {
/**
* Parameters.
*
* @return external_function_parameters
*/
public static function execute_parameters(): external_function_parameters {
return new external_function_parameters([
'entryid' => new external_value(PARAM_INT, 'Glossary entry id to update'),
]);
}
/**
* Prepare for update the indicated entry from the glossary.
*
* @param int $entryid The entry to update
* @return array with result and warnings
* @throws moodle_exception
*/
public static function execute(int $entryid): array {
global $DB;
$params = self::validate_parameters(self::execute_parameters(), compact('entryid'));
$id = $params['entryid'];
// Get and validate the glossary.
$entry = $DB->get_record('glossary_entries', ['id' => $id], '*', MUST_EXIST);
list($glossary, $context, $course, $cm) = \mod_glossary_external::validate_glossary($entry->glossaryid);
// Check permissions.
mod_glossary_can_update_entry($entry, $glossary, $context, $cm, false);
list($definitionoptions, $attachmentoptions) = glossary_get_editor_and_attachment_options($course, $context, $entry);
$entry->aliases = '';
$entry->categories = [];
$entry = mod_glossary_prepare_entry_for_edition($entry);
$entry = file_prepare_standard_editor($entry, 'definition', $definitionoptions, $context, 'mod_glossary', 'entry',
$entry->id);
$entry = file_prepare_standard_filemanager($entry, 'attachment', $attachmentoptions, $context, 'mod_glossary', 'attachment',
$entry->id);
// Just get a structure compatible with external API.
array_walk($definitionoptions, function(&$item, $key) use (&$definitionoptions) {
if (!is_scalar($item)) {
unset($definitionoptions[$key]);
return;
}
$item = ['name' => $key, 'value' => $item];
});
array_walk($attachmentoptions, function(&$item, $key) use (&$attachmentoptions) {
if (!is_scalar($item)) {
unset($attachmentoptions[$key]);
return;
}
$item = ['name' => $key, 'value' => $item];
});
return [
'inlineattachmentsid' => $entry->definition_editor['itemid'],
'attachmentsid' => $entry->attachment_filemanager,
'areas' => [
[
'area' => 'definition',
'options' => $definitionoptions,
],
[
'area' => 'attachment',
'options' => $attachmentoptions,
],
],
'aliases' => explode("\n", trim($entry->aliases)),
'categories' => $entry->categories,
];
}
/**
* Return.
*
* @return external_single_structure
*/
public static function execute_returns(): external_single_structure {
return new external_single_structure([
'inlineattachmentsid' => new external_value(PARAM_INT, 'Draft item id for the text editor.'),
'attachmentsid' => new external_value(PARAM_INT, 'Draft item id for the file manager.'),
'areas' => new external_multiple_structure(
new external_single_structure(
[
'area' => new external_value(PARAM_ALPHA, 'File area name.'),
'options' => new external_multiple_structure(
new external_single_structure(
[
'name' => new external_value(PARAM_RAW, 'Name of option.'),
'value' => new external_value(PARAM_RAW, 'Value of option.'),
]
), 'Draft file area options.'
)
]
), 'File areas including options'
),
'aliases' => new external_multiple_structure(new external_value(PARAM_RAW, 'Alias name.')),
'categories' => new external_multiple_structure(new external_value(PARAM_INT, 'Category id')),
'warnings' => new external_warnings(),
]);
}
}
+175
View File
@@ -0,0 +1,175 @@
<?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/>.
/**
* This is the external method for updating a glossary entry.
*
* @package mod_glossary
* @since Moodle 3.10
* @copyright 2020 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/mod/glossary/lib.php');
use core_external\external_api;
use core_external\external_format_value;
use core_external\external_function_parameters;
use core_external\external_multiple_structure;
use core_external\external_single_structure;
use core_external\external_value;
use core_external\external_warnings;
use core_text;
use moodle_exception;
/**
* This is the external method for updating a glossary entry.
*
* @copyright 2020 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class update_entry extends external_api {
/**
* Parameters.
*
* @return external_function_parameters
*/
public static function execute_parameters(): external_function_parameters {
return new external_function_parameters([
'entryid' => new external_value(PARAM_INT, 'Glossary entry id to update'),
'concept' => new external_value(PARAM_TEXT, 'Glossary concept'),
'definition' => new external_value(PARAM_RAW, 'Glossary concept definition'),
'definitionformat' => new external_format_value('definition'),
'options' => new external_multiple_structure (
new external_single_structure(
[
'name' => new external_value(PARAM_ALPHANUM,
'The allowed keys (value format) are:
inlineattachmentsid (int); the draft file area id for inline attachments
attachmentsid (int); the draft file area id for attachments
categories (comma separated int); comma separated category ids
aliases (comma separated str); comma separated aliases
usedynalink (bool); whether the entry should be automatically linked.
casesensitive (bool); whether the entry is case sensitive.
fullmatch (bool); whether to match whole words only.'),
'value' => new external_value(PARAM_RAW, 'the value of the option (validated inside the function)')
]
), 'Optional settings', VALUE_DEFAULT, []
)
]);
}
/**
* Update the indicated glossary entry.
*
* @param int $entryid The entry to update
* @param string $concept the glossary concept
* @param string $definition the concept definition
* @param int $definitionformat the concept definition format
* @param array $options additional settings
* @return array with result and warnings
* @throws moodle_exception
*/
public static function execute(int $entryid, string $concept, string $definition, int $definitionformat,
array $options = []): array {
global $DB;
$params = self::validate_parameters(self::execute_parameters(), compact('entryid', 'concept', 'definition',
'definitionformat', 'options'));
$id = $params['entryid'];
// Get and validate the glossary entry.
$entry = $DB->get_record('glossary_entries', ['id' => $id], '*', MUST_EXIST);
list($glossary, $context, $course, $cm) = \mod_glossary_external::validate_glossary($entry->glossaryid);
// Check if the user can update the entry.
mod_glossary_can_update_entry($entry, $glossary, $context, $cm, false);
// Check for duplicates if the concept changes.
if (!$glossary->allowduplicatedentries &&
core_text::strtolower($entry->concept) != core_text::strtolower(trim($params['concept']))) {
if (glossary_concept_exists($glossary, $params['concept'])) {
throw new moodle_exception('errconceptalreadyexists', 'glossary');
}
}
// Prepare the entry object.
$entry->aliases = '';
$entry = mod_glossary_prepare_entry_for_edition($entry);
$entry->concept = $params['concept'];
$entry->definition_editor = [
'text' => $params['definition'],
'format' => $params['definitionformat'],
];
// Options.
foreach ($params['options'] as $option) {
$name = trim($option['name']);
switch ($name) {
case 'inlineattachmentsid':
$entry->definition_editor['itemid'] = clean_param($option['value'], PARAM_INT);
break;
case 'attachmentsid':
$entry->attachment_filemanager = clean_param($option['value'], PARAM_INT);
break;
case 'categories':
$entry->categories = clean_param($option['value'], PARAM_SEQUENCE);
$entry->categories = explode(',', $entry->categories);
break;
case 'aliases':
$entry->aliases = clean_param($option['value'], PARAM_NOTAGS);
// Convert to the expected format.
$entry->aliases = str_replace(",", "\n", $entry->aliases);
break;
case 'usedynalink':
case 'casesensitive':
case 'fullmatch':
// Only allow if linking is enabled.
if ($glossary->usedynalink) {
$entry->{$name} = clean_param($option['value'], PARAM_BOOL);
}
break;
default:
throw new moodle_exception('errorinvalidparam', 'webservice', '', $name);
}
}
$entry = glossary_edit_entry($entry, $course, $cm, $glossary, $context);
return [
'result' => true,
'warnings' => [],
];
}
/**
* Return.
*
* @return external_single_structure
*/
public static function execute_returns(): external_single_structure {
return new external_single_structure([
'result' => new external_value(PARAM_BOOL, 'The update result'),
'warnings' => new external_warnings()
]);
}
}
@@ -0,0 +1,295 @@
<?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/>.
/**
* Entry caching for glossary filter.
*
* @package mod_glossary
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\local;
defined('MOODLE_INTERNAL') || die();
/**
* Concept caching for glossary filter.
*
* @package mod_glossary
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class concept_cache {
/**
* Event observer, do not call directly.
* @param \core\event\course_module_updated $event
*/
public static function cm_updated(\core\event\course_module_updated $event) {
if ($event->other['modulename'] !== 'glossary') {
return;
}
// We do not know what changed exactly, so let's reset everything that might be affected.
concept_cache::reset_course_muc($event->courseid);
concept_cache::reset_global_muc();
}
/**
* Reset concept related caches.
* @param bool $phpunitreset
*/
public static function reset_caches($phpunitreset = false) {
if ($phpunitreset) {
return;
}
$cache = \cache::make('mod_glossary', 'concepts');
$cache->purge();
}
/**
* Reset the cache for course concepts.
* @param int $courseid
*/
public static function reset_course_muc($courseid) {
if (empty($courseid)) {
return;
}
$cache = \cache::make('mod_glossary', 'concepts');
$cache->delete((int)$courseid);
}
/**
* Reset the cache for global concepts.
*/
public static function reset_global_muc() {
$cache = \cache::make('mod_glossary', 'concepts');
$cache->delete(0);
}
/**
* Utility method to purge caches related to given glossary.
* @param \stdClass $glossary
*/
public static function reset_glossary($glossary) {
if (!$glossary->usedynalink) {
return;
}
self::reset_course_muc($glossary->course);
if ($glossary->globalglossary) {
self::reset_global_muc();
}
}
/**
* Fetch concepts for given glossaries.
* @param int[] $glossaries
* @return array
*/
protected static function fetch_concepts(array $glossaries) {
global $DB;
$glossarylist = implode(',', $glossaries);
$sql = "SELECT id, glossaryid, concept, casesensitive, 0 AS category, fullmatch
FROM {glossary_entries}
WHERE glossaryid IN ($glossarylist) AND usedynalink = 1 AND approved = 1
UNION
SELECT id, glossaryid, name AS concept, 1 AS casesensitive, 1 AS category, 1 AS fullmatch
FROM {glossary_categories}
WHERE glossaryid IN ($glossarylist) AND usedynalink = 1
UNION
SELECT ge.id, ge.glossaryid, ga.alias AS concept, ge.casesensitive, 0 AS category, ge.fullmatch
FROM {glossary_alias} ga
JOIN {glossary_entries} ge ON (ga.entryid = ge.id)
WHERE ge.glossaryid IN ($glossarylist) AND ge.usedynalink = 1 AND ge.approved = 1";
$concepts = array();
$rs = $DB->get_recordset_sql($sql);
foreach ($rs as $concept) {
$currentconcept = trim(strip_tags($concept->concept));
// Concept must be HTML-escaped, so do the same as format_string to turn ampersands into &amp;.
$currentconcept = replace_ampersands_not_followed_by_entity($currentconcept);
if (empty($currentconcept)) {
continue;
}
// Rule out any small integers, see MDL-1446.
if (is_number($currentconcept) and $currentconcept < 1000) {
continue;
}
$concept->concept = $currentconcept;
$concepts[$concept->glossaryid][] = $concept;
}
$rs->close();
return $concepts;
}
/**
* Get all linked concepts from course.
* @param int $courseid
* @return array
*/
protected static function get_course_concepts($courseid) {
global $DB;
if (empty($courseid)) {
return array(array(), array());
}
$courseid = (int)$courseid;
// Get info on any glossaries in this course.
$modinfo = get_fast_modinfo($courseid);
$cminfos = $modinfo->get_instances_of('glossary');
if (!$cminfos) {
// No glossaries in this course, so don't do any work.
return array(array(), array());
}
$cache = \cache::make('mod_glossary', 'concepts');
$data = $cache->get($courseid);
if (is_array($data)) {
list($glossaries, $allconcepts) = $data;
} else {
// Find all course glossaries.
$sql = "SELECT g.id, g.name
FROM {glossary} g
JOIN {course_modules} cm ON (cm.instance = g.id)
JOIN {modules} m ON (m.name = 'glossary' AND m.id = cm.module)
WHERE g.usedynalink = 1 AND g.course = :course AND cm.visible = 1 AND m.visible = 1
ORDER BY g.globalglossary, g.id";
$glossaries = $DB->get_records_sql_menu($sql, array('course' => $courseid));
if (!$glossaries) {
$data = array(array(), array());
$cache->set($courseid, $data);
return $data;
}
foreach ($glossaries as $id => $name) {
$name = str_replace(':', '-', $name);
$glossaries[$id] = replace_ampersands_not_followed_by_entity(strip_tags($name));
}
$allconcepts = self::fetch_concepts(array_keys($glossaries));
foreach ($glossaries as $gid => $unused) {
if (!isset($allconcepts[$gid])) {
unset($glossaries[$gid]);
}
}
if (!$glossaries) {
// This means there are no interesting concepts in the existing glossaries.
$data = array(array(), array());
$cache->set($courseid, $data);
return $data;
}
$cache->set($courseid, array($glossaries, $allconcepts));
}
$concepts = $allconcepts;
// Verify access control to glossary instances.
foreach ($concepts as $modid => $unused) {
if (!isset($cminfos[$modid])) {
// This should not happen.
unset($concepts[$modid]);
unset($glossaries[$modid]);
continue;
}
if (!$cminfos[$modid]->uservisible) {
unset($concepts[$modid]);
unset($glossaries[$modid]);
continue;
}
}
return array($glossaries, $concepts);
}
/**
* Get all linked global concepts.
* @return array
*/
protected static function get_global_concepts() {
global $DB;
$cache = \cache::make('mod_glossary', 'concepts');
$data = $cache->get(0);
if (is_array($data)) {
list($glossaries, $allconcepts) = $data;
} else {
// Find all global glossaries - no access control here.
$sql = "SELECT g.id, g.name
FROM {glossary} g
JOIN {course_modules} cm ON (cm.instance = g.id)
JOIN {modules} m ON (m.name = 'glossary' AND m.id = cm.module)
WHERE g.usedynalink = 1 AND g.globalglossary = 1 AND cm.visible = 1 AND m.visible = 1
ORDER BY g.globalglossary, g.id";
$glossaries = $DB->get_records_sql_menu($sql);
if (!$glossaries) {
$data = array(array(), array());
$cache->set(0, $data);
return $data;
}
foreach ($glossaries as $id => $name) {
$name = str_replace(':', '-', $name);
$glossaries[$id] = replace_ampersands_not_followed_by_entity(strip_tags($name));
}
$allconcepts = self::fetch_concepts(array_keys($glossaries));
foreach ($glossaries as $gid => $unused) {
if (!isset($allconcepts[$gid])) {
unset($glossaries[$gid]);
}
}
$cache->set(0, array($glossaries, $allconcepts));
}
// NOTE: no access control is here because it would be way too expensive to check access
// to all courses that contain the global glossaries.
return array($glossaries, $allconcepts);
}
/**
* Get all concepts that should be linked in the given course.
* @param int $courseid
* @return array with two elements - array of glossaries and concepts for each glossary
*/
public static function get_concepts($courseid) {
list($glossaries, $concepts) = self::get_course_concepts($courseid);
list($globalglossaries, $globalconcepts) = self::get_global_concepts();
foreach ($globalconcepts as $gid => $cs) {
if (!isset($concepts[$gid])) {
$concepts[$gid] = $cs;
}
}
foreach ($globalglossaries as $gid => $name) {
if (!isset($glossaries[$gid])) {
$glossaries[$gid] = $name;
}
}
return array($glossaries, $concepts);
}
}
@@ -0,0 +1,47 @@
<?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/>.
namespace mod_glossary\navigation\views;
use core\navigation\views\secondary as core_secondary;
/**
* Class secondary_navigation_view.
*
* Custom implementation for a plugin.
*
* @package mod_glossary
* @category navigation
* @copyright 2021 onwards Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class secondary extends core_secondary {
/**
* Define a custom secondary nav order/view
*
* @return array
*/
protected function get_default_module_mapping(): array {
return [
self::TYPE_SETTING => [
'modedit' => 1,
],
self::TYPE_CUSTOM => [
'pendingapproval' => 2,
],
];
}
}
+41
View File
@@ -0,0 +1,41 @@
<?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/>.
namespace mod_glossary\output;
use plugin_renderer_base;
/**
* Class actionbar - Display the action bar
*
* @package mod_glossary
* @copyright 2021 Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class renderer extends plugin_renderer_base {
/**
* Render the glossary tertiary nav
*
* @param standard_action_bar $actionmenu
* @return bool|string
* @throws \moodle_exception
*/
public function main_action_bar(standard_action_bar $actionmenu) {
$context = $actionmenu->export_for_template($this);
return $this->render_from_template('mod_glossary/standard_action_menu', $context);
}
}
@@ -0,0 +1,289 @@
<?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/>.
namespace mod_glossary\output;
use moodle_url;
use context_module;
use renderable;
use renderer_base;
use single_button;
use templatable;
use url_select;
/**
* Class standard_action_bar - Display the action bar
*
* @package mod_glossary
* @copyright 2021 Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class standard_action_bar implements renderable, templatable {
/** @var object $cm The course module. */
private $cm;
/** @var string $mode The type of view. */
private $mode;
/** @var string $hook The term, entry, cat, etc... to look for based on mode. */
private $hook;
/** @var string $sortkey Sorted view: CREATION | UPDATE | FIRSTNAME | LASTNAME. */
private $sortkey;
/** @var string $sortorder The sort order (ASC or DESC). */
private $sortorder;
/** @var int $offset Entries to bypass (for paging purposes). */
private $offset;
/** @var int $pagelimit The page to resume with. */
private $pagelimit;
/** @var int $context The context of the glossary. */
private $context;
/** @var object $module The glossary record . */
private $module;
/** @var int $fullsearch Full search (concept and definition) when searching. */
private $fullsearch;
/** @var object $displayformat Override of the glossary display format. */
private $displayformat;
/** @var string $tab Browsing entries by categories. */
private $tab;
/**
* standard_action_bar constructor.
*
* @param object $cm
* @param object $module
* @param object $displayformat
* @param string $mode
* @param string $hook
* @param string $sortkey
* @param string $sortorder
* @param int $offset
* @param int $pagelimit
* @param int $fullsearch
* @param string $tab
* @param string $defaulttab
* @throws \coding_exception
*/
public function __construct(object $cm, object $module, object $displayformat, string $mode, string $hook,
string $sortkey, string $sortorder, int $offset, int $pagelimit, int $fullsearch,
string $tab, string $defaulttab) {
$this->cm = $cm;
$this->module = $module;
$this->displayformat = $displayformat;
$this->mode = $mode;
$this->tab = $tab;
$this->hook = $hook;
$this->sortkey = $sortkey;
$this->sortorder = $sortorder;
$this->offset = $offset;
$this->pagelimit = $pagelimit;
$this->fullsearch = $fullsearch;
$this->context = context_module::instance($this->cm->id);
if (!has_capability('mod/glossary:approve', $this->context) && $this->tab == GLOSSARY_APPROVAL_VIEW) {
// Non-teachers going to approval view go to defaulttab.
$this->tab = $defaulttab;
}
}
/**
* Export the action bar
*
* @param renderer_base $output
* @return array
*/
public function export_for_template(renderer_base $output) {
return [
'addnewbutton' => $this->create_add_button($output),
'searchbox' => $this->create_search_box(),
'tools' => $this->get_additional_tools($output),
'tabjumps' => $this->generate_tab_jumps($output)
];
}
/**
* Render the search box with the checkbox
*
* @return array
*/
private function create_search_box(): array {
global $OUTPUT;
$fullsearchchecked = false;
if ($this->fullsearch || $this->mode != 'search') {
$fullsearchchecked = true;
}
$check = [
'name' => 'fullsearch',
'id' => 'fullsearch',
'value' => '1',
'checked' => $fullsearchchecked,
'label' => get_string("searchindefinition", "glossary"),
];
$checkbox = $OUTPUT->render_from_template('core/checkbox', $check);
$hiddenfields = [
(object) ['name' => 'id', 'value' => $this->cm->id],
(object) ['name' => 'mode', 'value' => 'search'],
];
$data = [
'action' => new moodle_url('/mod/glossary/view.php'),
'hiddenfields' => $hiddenfields,
'otherfields' => $checkbox,
'inputname' => 'hook',
'query' => ($this->mode == 'search') ? s($this->hook) : '',
'searchstring' => get_string('search'),
];
return $data;
}
/**
* Render the add entry button
*
* @param renderer_base $output
* @return \stdClass|null
*/
private function create_add_button(renderer_base $output): ?\stdClass {
if (!has_capability('mod/glossary:write', $this->context)) {
return null;
}
$btn = new single_button(new moodle_url('/mod/glossary/edit.php', ['cmid' => $this->cm->id]),
get_string('addsingleentry', 'glossary'), 'post', single_button::BUTTON_PRIMARY);
return $btn->export_for_template($output);
}
/**
* Render the additional tools required by the glossary
*
* @param renderer_base $output
* @return array
*/
private function get_additional_tools(renderer_base $output): array {
global $USER, $CFG;
$items = [];
$buttons = [];
$openinnewwindow = [];
if (has_capability('mod/glossary:import', $this->context)) {
$items['button'] = new single_button(
new moodle_url('/mod/glossary/import.php', ['id' => $this->cm->id]),
get_string('importentries', 'glossary')
);
}
if (has_capability('mod/glossary:export', $this->context)) {
$url = new moodle_url('/mod/glossary/export.php', [
'id' => $this->cm->id,
'mode' => $this->mode,
'hook' => $this->hook
]);
$buttons[get_string('export', 'glossary')] = $url->out(false);
}
if (has_capability('mod/glossary:manageentries', $this->context) or $this->module->allowprintview) {
$params = array(
'id' => $this->cm->id,
'mode' => $this->mode,
'hook' => $this->hook,
'sortkey' => $this->sortkey,
'sortorder' => $this->sortorder,
'offset' => $this->offset,
'pagelimit' => $this->pagelimit
);
$printurl = new moodle_url('/mod/glossary/print.php', $params);
$buttons[get_string('printerfriendly', 'glossary')] = $printurl->out(false);
$openinnewwindow[] = $printurl->out(false);
}
if (!empty($CFG->enablerssfeeds) && !empty($CFG->glossary_enablerssfeeds)
&& $this->module->rsstype && $this->module->rssarticles
&& has_capability('mod/glossary:view', $this->context)) {
require_once("$CFG->libdir/rsslib.php");
$string = get_string('rssfeed', 'glossary');
$url = new moodle_url(rss_get_url($this->context->id, $USER->id, 'mod_glossary', $this->cm->instance));
$buttons[$string] = $url->out(false);
$openinnewwindow[] = $url->out(false);
}
foreach ($items as $key => $value) {
$items[$key] = $value->export_for_template($output);
}
if ($buttons) {
foreach ($buttons as $index => $value) {
$items['select']['options'][] = [
'url' => $value,
'string' => $index,
'openinnewwindow' => ($openinnewwindow ? in_array($value, $openinnewwindow) : false)
];
}
}
return $items;
}
/**
* Generate a url select to match any types of glossary views
*
* @param renderer_base $output
* @return \stdClass|null
*/
private function generate_tab_jumps(renderer_base $output) {
$tabs = glossary_get_visible_tabs($this->displayformat);
$validtabs = [
GLOSSARY_STANDARD => [
'mode' => 'letter',
'descriptor' => 'standardview'
],
GLOSSARY_CATEGORY => [
'mode' => 'cat',
'descriptor' => 'categoryview'
],
GLOSSARY_DATE => [
'mode' => 'date',
'descriptor' => 'dateview'
],
GLOSSARY_AUTHOR => [
'mode' => 'author',
'descriptor' => 'authorview'
],
];
$baseurl = new moodle_url('/mod/glossary/view.php', ['id' => $this->cm->id]);
$active = null;
$options = [];
foreach ($validtabs as $key => $tabinfo) {
if (in_array($key, $tabs)) {
$baseurl->params(['mode' => $tabinfo['mode']]);
$active = $active ?? $baseurl->out(false);
$active = ($tabinfo['mode'] == $this->mode ? $baseurl->out(false) : $active);
$options[get_string($tabinfo['descriptor'], 'glossary')] = $baseurl->out(false);
}
}
if ($this->tab < GLOSSARY_STANDARD_VIEW || $this->tab > GLOSSARY_AUTHOR_VIEW) {
$options[get_string('edit')] = '#';
}
if (count($options) > 1) {
$select = new url_select(array_flip($options), $active, null);
$select->set_label(get_string('explainalphabet', 'glossary'), ['class' => 'sr-only']);
return $select->export_for_template($output);
}
return null;
}
}
+467
View File
@@ -0,0 +1,467 @@
<?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/>.
/**
* Privacy Subsystem implementation for mod_glossary.
*
* @package mod_glossary
* @copyright 2018 Simey Lameze <simey@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\privacy;
use core_privacy\local\metadata\collection;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\approved_userlist;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\deletion_criteria;
use core_privacy\local\request\helper;
use core_privacy\local\request\userlist;
use core_privacy\local\request\writer;
defined('MOODLE_INTERNAL') || die();
/**
* Implementation of the privacy subsystem plugin provider for the glossary activity module.
*
* @copyright 2018 Simey Lameze <simey@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements
// This plugin stores personal data.
\core_privacy\local\metadata\provider,
// This plugin is capable of determining which users have data within it.
\core_privacy\local\request\core_userlist_provider,
// This plugin is a core_user_data_provider.
\core_privacy\local\request\plugin\provider {
/**
* Return the fields which contain personal data.
*
* @param collection $items a reference to the collection to use to store the metadata.
* @return collection the updated collection of metadata items.
*/
public static function get_metadata(collection $items): collection {
$items->add_database_table(
'glossary_entries',
[
'glossaryid' => 'privacy:metadata:glossary_entries:glossaryid',
'userid' => 'privacy:metadata:glossary_entries:userid',
'concept' => 'privacy:metadata:glossary_entries:concept',
'definition' => 'privacy:metadata:glossary_entries:definition',
'attachment' => 'privacy:metadata:glossary_entries:attachment',
'timemodified' => 'privacy:metadata:glossary_entries:timemodified',
],
'privacy:metadata:glossary_entries'
);
$items->add_subsystem_link('core_files', [], 'privacy:metadata:core_files');
$items->add_subsystem_link('core_comment', [], 'privacy:metadata:core_comments');
$items->add_subsystem_link('core_tag', [], 'privacy:metadata:core_tag');
$items->add_subsystem_link('core_rating', [], 'privacy:metadata:core_rating');
return $items;
}
/**
* Get the list of contexts that contain user information for the specified user.
*
* @param int $userid the userid.
* @return contextlist the list of contexts containing user info for the user.
*/
public static function get_contexts_for_userid(int $userid): contextlist {
$contextlist = new contextlist();
// Glossary entries.
$sql = "SELECT c.id
FROM {context} c
JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
JOIN {modules} m ON m.id = cm.module AND m.name = :modname
JOIN {glossary} g ON g.id = cm.instance
JOIN {glossary_entries} ge ON ge.glossaryid = g.id
WHERE ge.userid = :glossaryentryuserid";
$params = [
'contextlevel' => CONTEXT_MODULE,
'modname' => 'glossary',
'commentarea' => 'glossary_entry',
'glossaryentryuserid' => $userid,
];
$contextlist->add_from_sql($sql, $params);
// Where the user has rated something.
$ratingquery = \core_rating\privacy\provider::get_sql_join('r', 'mod_glossary', 'entry', 'ge.id', $userid, true);
$sql = "SELECT c.id
FROM {context} c
JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
JOIN {modules} m ON m.id = cm.module AND m.name = :modname
JOIN {glossary} g ON g.id = cm.instance
JOIN {glossary_entries} ge ON ge.glossaryid = g.id
{$ratingquery->join}
WHERE {$ratingquery->userwhere}";
$params = [
'contextlevel' => CONTEXT_MODULE,
'modname' => 'glossary',
] + $ratingquery->params;
$contextlist->add_from_sql($sql, $params);
// Comments.
$sql = "SELECT c.id
FROM {context} c
JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
JOIN {modules} m ON m.id = cm.module AND m.name = :modname
JOIN {glossary} g ON g.id = cm.instance
JOIN {glossary_entries} ge ON ge.glossaryid = g.id
JOIN {comments} com ON com.commentarea =:commentarea AND com.itemid = ge.id
WHERE com.userid = :commentuserid";
$params = [
'contextlevel' => CONTEXT_MODULE,
'modname' => 'glossary',
'commentarea' => 'glossary_entry',
'commentuserid' => $userid,
];
$contextlist->add_from_sql($sql, $params);
return $contextlist;
}
/**
* Get the list of users who have data within a context.
*
* @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
*
*/
public static function get_users_in_context(userlist $userlist) {
$context = $userlist->get_context();
if (!is_a($context, \context_module::class)) {
return;
}
// Find users with glossary entries.
$sql = "SELECT ge.userid
FROM {context} c
JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
JOIN {modules} m ON m.id = cm.module AND m.name = :modname
JOIN {glossary} g ON g.id = cm.instance
JOIN {glossary_entries} ge ON ge.glossaryid = g.id
WHERE c.id = :contextid";
$params = [
'contextid' => $context->id,
'contextlevel' => CONTEXT_MODULE,
'modname' => 'glossary',
];
$userlist->add_from_sql('userid', $sql, $params);
// Find users with glossary comments.
\core_comment\privacy\provider::get_users_in_context_from_sql($userlist, 'com', 'mod_glossary', 'glossary_entry',
$context->id);
// Find users with glossary ratings.
$sql = "SELECT ge.id
FROM {context} c
JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
JOIN {modules} m ON m.id = cm.module AND m.name = :modname
JOIN {glossary} g ON g.id = cm.instance
JOIN {glossary_entries} ge ON ge.glossaryid = g.id
WHERE c.id = :contextid";
$params = [
'contextid' => $context->id,
'contextlevel' => CONTEXT_MODULE,
'modname' => 'glossary',
];
\core_rating\privacy\provider::get_users_in_context_from_sql($userlist, 'rat', 'mod_glossary', 'entry', $sql, $params);
}
/**
* Export personal data for the given approved_contextlist.
*
* User and context information is contained within the contextlist.
*
* @param approved_contextlist $contextlist a list of contexts approved for export.
*/
public static function export_user_data(approved_contextlist $contextlist) {
global $DB;
if (empty($contextlist->count())) {
return;
}
$user = $contextlist->get_user();
list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
$ratingquery = \core_rating\privacy\provider::get_sql_join('r', 'mod_glossary', 'entry', 'ge.id', $user->id);
$sql = "SELECT ge.id as entryid,
cm.id AS cmid,
ge.userid,
ge.concept,
ge.definition,
ge.definitionformat,
ge.attachment,
ge.timecreated,
ge.timemodified
FROM {glossary_entries} ge
JOIN {glossary} g ON ge.glossaryid = g.id
JOIN {course_modules} cm ON g.id = cm.instance
JOIN {modules} m ON cm.module = m.id AND m.name = :modulename
JOIN {context} c ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
LEFT JOIN {comments} com ON com.itemid = ge.id AND com.commentarea = :commentarea AND com.userid = :commentuserid
{$ratingquery->join}
WHERE c.id {$contextsql}
AND (ge.userid = :userid OR com.id IS NOT NULL OR {$ratingquery->userwhere})
ORDER BY ge.id, cm.id";
$params = [
'userid' => $user->id,
'modulename' => 'glossary',
'contextlevel' => CONTEXT_MODULE,
'commentarea' => 'glossary_entry',
'commentuserid' => $user->id
] + $contextparams;
$params = array_merge($params, $ratingquery->params);
$glossaryentries = $DB->get_recordset_sql($sql, $params);
// Reference to the glossary activity seen in the last iteration of the loop. By comparing this with the
// current record, and because we know the results are ordered, we know when we've moved to the entries
// for a new glossary activity and therefore when we can export the complete data for the last activity.
$lastcmid = null;
$glossarydata = [];
foreach ($glossaryentries as $record) {
$concept = format_string($record->concept);
$path = array_merge([get_string('entries', 'mod_glossary'), $concept . " ({$record->entryid})"]);
// If we've moved to a new glossary, then write the last glossary data and reinit the glossary data array.
if (!is_null($lastcmid)) {
if ($lastcmid != $record->cmid) {
if (!empty($glossarydata)) {
$context = \context_module::instance($lastcmid);
self::export_glossary_data_for_user($glossarydata, $context, [], $user);
$glossarydata = [];
}
}
}
$lastcmid = $record->cmid;
$context = \context_module::instance($lastcmid);
// Export files added on the glossary entry definition field.
$definition = format_text(writer::with_context($context)->rewrite_pluginfile_urls($path, 'mod_glossary',
'entry', $record->entryid, $record->definition), $record->definitionformat);
// Export just the files attached to this user entry.
if ($record->userid == $user->id) {
// Get all files attached to the glossary attachment.
writer::with_context($context)->export_area_files($path, 'mod_glossary', 'entry', $record->entryid);
// Get all files attached to the glossary attachment.
writer::with_context($context)->export_area_files($path, 'mod_glossary', 'attachment', $record->entryid);
}
// Export associated comments.
\core_comment\privacy\provider::export_comments($context, 'mod_glossary', 'glossary_entry',
$record->entryid, $path, $record->userid != $user->id);
// Export associated tags.
\core_tag\privacy\provider::export_item_tags($user->id, $context, $path, 'mod_glossary', 'glossary_entries',
$record->entryid, $record->userid != $user->id);
// Export associated ratings.
\core_rating\privacy\provider::export_area_ratings($user->id, $context, $path, 'mod_glossary', 'entry',
$record->entryid, $record->userid != $user->id);
$glossarydata['entries'][] = [
'concept' => $record->concept,
'definition' => $definition,
'timecreated' => \core_privacy\local\request\transform::datetime($record->timecreated),
'timemodified' => \core_privacy\local\request\transform::datetime($record->timemodified)
];
}
$glossaryentries->close();
// The data for the last activity won't have been written yet, so make sure to write it now!
if (!empty($glossarydata)) {
$context = \context_module::instance($lastcmid);
self::export_glossary_data_for_user($glossarydata, $context, [], $user);
}
}
/**
* Export the supplied personal data for a single glossary activity, along with any generic data or area files.
*
* @param array $glossarydata The personal data to export for the glossary.
* @param \context_module $context The context of the glossary.
* @param array $subcontext The location within the current context that this data belongs.
* @param \stdClass $user the user record
*/
protected static function export_glossary_data_for_user(array $glossarydata, \context_module $context,
array $subcontext, \stdClass $user) {
// Fetch the generic module data for the glossary.
$contextdata = helper::get_context_data($context, $user);
// Merge with glossary data and write it.
$contextdata = (object)array_merge((array)$contextdata, $glossarydata);
writer::with_context($context)->export_data($subcontext, $contextdata);
// Write generic module intro files.
helper::export_context_files($context, $user);
}
/**
* Delete all data for all users in the specified context.
*
* @param \context $context the context to delete in.
*/
public static function delete_data_for_all_users_in_context(\context $context) {
global $DB;
if ($context->contextlevel != CONTEXT_MODULE) {
return;
}
if (!$cm = get_coursemodule_from_id('glossary', $context->instanceid)) {
return;
}
$instanceid = $cm->instance;
$entries = $DB->get_records('glossary_entries', ['glossaryid' => $instanceid], '', 'id');
// Delete related entry aliases.
$DB->delete_records_list('glossary_alias', 'entryid', array_keys($entries));
// Delete related entry categories.
$DB->delete_records_list('glossary_entries_categories', 'entryid', array_keys($entries));
// Delete entry and attachment files.
get_file_storage()->delete_area_files($context->id, 'mod_glossary', 'entry');
get_file_storage()->delete_area_files($context->id, 'mod_glossary', 'attachment');
// Delete related ratings.
\core_rating\privacy\provider::delete_ratings($context, 'mod_glossary', 'entry');
// Delete comments.
\core_comment\privacy\provider::delete_comments_for_all_users($context, 'mod_glossary', 'glossary_entry');
// Delete tags.
\core_tag\privacy\provider::delete_item_tags($context, 'mod_glossary', 'glossary_entries');
// Now delete all user related entries.
$DB->delete_records('glossary_entries', ['glossaryid' => $instanceid]);
}
/**
* Delete all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist a list of contexts approved for deletion.
*/
public static function delete_data_for_user(approved_contextlist $contextlist) {
global $DB;
if (empty($contextlist->count())) {
return;
}
$userid = $contextlist->get_user()->id;
foreach ($contextlist->get_contexts() as $context) {
if ($context->contextlevel == CONTEXT_MODULE) {
$instanceid = $DB->get_field('course_modules', 'instance', ['id' => $context->instanceid], MUST_EXIST);
$entries = $DB->get_records('glossary_entries', ['glossaryid' => $instanceid, 'userid' => $userid],
'', 'id');
if (!$entries) {
continue;
}
list($insql, $inparams) = $DB->get_in_or_equal(array_keys($entries), SQL_PARAMS_NAMED);
// Delete related entry aliases.
$DB->delete_records_list('glossary_alias', 'entryid', array_keys($entries));
// Delete related entry categories.
$DB->delete_records_list('glossary_entries_categories', 'entryid', array_keys($entries));
// Delete related entry and attachment files.
get_file_storage()->delete_area_files_select($context->id, 'mod_glossary', 'entry', $insql, $inparams);
get_file_storage()->delete_area_files_select($context->id, 'mod_glossary', 'attachment', $insql, $inparams);
// Delete user tags related to this glossary.
\core_tag\privacy\provider::delete_item_tags_select($context, 'mod_glossary', 'glossary_entries', $insql, $inparams);
// Delete related ratings.
\core_rating\privacy\provider::delete_ratings_select($context, 'mod_glossary', 'entry', $insql, $inparams);
// Delete comments.
\core_comment\privacy\provider::delete_comments_for_user($contextlist, 'mod_glossary', 'glossary_entry');
// Now delete all user related entries.
$DB->delete_records('glossary_entries', ['glossaryid' => $instanceid, 'userid' => $userid]);
}
}
}
/**
* Delete multiple users within a single context.
*
* @param approved_userlist $userlist The approved context and user information to delete information for.
*/
public static function delete_data_for_users(approved_userlist $userlist) {
global $DB;
$context = $userlist->get_context();
$userids = $userlist->get_userids();
$instanceid = $DB->get_field('course_modules', 'instance', ['id' => $context->instanceid], MUST_EXIST);
list($userinsql, $userinparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
$glossaryentrieswhere = "glossaryid = :instanceid AND userid {$userinsql}";
$userinstanceparams = $userinparams + ['instanceid' => $instanceid];
$entriesobject = $DB->get_recordset_select('glossary_entries', $glossaryentrieswhere, $userinstanceparams, 'id', 'id');
$entries = [];
foreach ($entriesobject as $entry) {
$entries[] = $entry->id;
}
$entriesobject->close();
if (!$entries) {
return;
}
list($insql, $inparams) = $DB->get_in_or_equal($entries, SQL_PARAMS_NAMED);
// Delete related entry aliases.
$DB->delete_records_list('glossary_alias', 'entryid', $entries);
// Delete related entry categories.
$DB->delete_records_list('glossary_entries_categories', 'entryid', $entries);
// Delete related entry and attachment files.
get_file_storage()->delete_area_files_select($context->id, 'mod_glossary', 'entry', $insql, $inparams);
get_file_storage()->delete_area_files_select($context->id, 'mod_glossary', 'attachment', $insql, $inparams);
// Delete user tags related to this glossary.
\core_tag\privacy\provider::delete_item_tags_select($context, 'mod_glossary', 'glossary_entries', $insql, $inparams);
// Delete related ratings.
\core_rating\privacy\provider::delete_ratings_select($context, 'mod_glossary', 'entry', $insql, $inparams);
// Delete comments.
\core_comment\privacy\provider::delete_comments_for_users($userlist, 'mod_glossary', 'glossary_entry');
// Now delete all user related entries.
$deletewhere = "glossaryid = :instanceid AND userid {$userinsql}";
$DB->delete_records_select('glossary_entries', $deletewhere, $userinstanceparams);
}
}
+46
View File
@@ -0,0 +1,46 @@
<?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/>.
/**
* Search area for mod_glossary activities.
*
* @package mod_glossary
* @copyright 2015 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\search;
defined('MOODLE_INTERNAL') || die();
/**
* Search area for mod_glossary activities.
*
* @package mod_glossary
* @copyright 2015 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class activity extends \core_search\base_activity {
/**
* Returns true if this area uses file indexing.
*
* @return bool
*/
public function uses_file_indexing() {
return true;
}
}
+225
View File
@@ -0,0 +1,225 @@
<?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/>.
/**
* Glossary entries search.
*
* @package mod_glossary
* @copyright 2015 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_glossary\search;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/mod/glossary/lib.php');
/**
* Glossary entries search.
*
* @package mod_glossary
* @copyright 2015 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class entry extends \core_search\base_mod {
/**
* @var array Internal quick static cache.
*/
protected $entriesdata = array();
/**
* Returns recordset containing required data for indexing glossary entries.
*
* @param int $modifiedfrom timestamp
* @param \context|null $context Optional context to restrict scope of returned results
* @return moodle_recordset|null Recordset (or null if no results)
*/
public function get_document_recordset($modifiedfrom = 0, \context $context = null) {
global $DB;
list ($contextjoin, $contextparams) = $this->get_context_restriction_sql(
$context, 'glossary', 'g');
if ($contextjoin === null) {
return null;
}
$sql = "SELECT ge.*, g.course FROM {glossary_entries} ge
JOIN {glossary} g ON g.id = ge.glossaryid
$contextjoin
WHERE ge.timemodified >= ? ORDER BY ge.timemodified ASC";
return $DB->get_recordset_sql($sql, array_merge($contextparams, [$modifiedfrom]));
}
/**
* Returns the documents associated with this glossary entry id.
*
* @param stdClass $entry glossary entry.
* @param array $options
* @return \core_search\document
*/
public function get_document($entry, $options = array()) {
global $DB;
$keywords = array();
if ($aliases = $DB->get_records('glossary_alias', array('entryid' => $entry->id))) {
foreach ($aliases as $alias) {
$keywords[] = $alias->alias;
}
}
try {
$cm = $this->get_cm('glossary', $entry->glossaryid, $entry->course);
$context = \context_module::instance($cm->id);
} catch (\dml_missing_record_exception $ex) {
// Notify it as we run here as admin, we should see everything.
debugging('Error retrieving mod_glossary ' . $entry->id . ' document, not all required data is available: ' .
$ex->getMessage(), DEBUG_DEVELOPER);
return false;
} catch (\dml_exception $ex) {
// Notify it as we run here as admin, we should see everything.
debugging('Error retrieving mod_glossary' . $entry->id . ' document: ' . $ex->getMessage(), DEBUG_DEVELOPER);
return false;
}
// Prepare associative array with data from DB.
$doc = \core_search\document_factory::instance($entry->id, $this->componentname, $this->areaname);
$doc->set('title', content_to_text($entry->concept, false));
$doc->set('content', content_to_text($entry->definition, $entry->definitionformat));
$doc->set('contextid', $context->id);
$doc->set('courseid', $entry->course);
$doc->set('userid', $entry->userid);
$doc->set('owneruserid', \core_search\manager::NO_OWNER_ID);
$doc->set('modified', $entry->timemodified);
// Check if this document should be considered new.
if (isset($options['lastindexedtime']) && ($options['lastindexedtime'] < $entry->timecreated)) {
// If the document was created after the last index time, it must be new.
$doc->set_is_new(true);
}
// Adding keywords as extra info.
if ($keywords) {
// No need to pass through content_to_text here as this is just a list of keywords.
$doc->set('description1', implode(' ' , $keywords));
}
return $doc;
}
/**
* Whether the user can access the document or not.
*
* @throws \dml_missing_record_exception
* @throws \dml_exception
* @param int $id Glossary entry id
* @return bool
*/
public function check_access($id) {
global $USER;
try {
$entry = $this->get_entry($id);
$cminfo = $this->get_cm('glossary', $entry->glossaryid, $entry->course);
} catch (\dml_missing_record_exception $ex) {
return \core_search\manager::ACCESS_DELETED;
} catch (\dml_exception $ex) {
return \core_search\manager::ACCESS_DENIED;
}
if (!glossary_can_view_entry($entry, $cminfo)) {
return \core_search\manager::ACCESS_DENIED;
}
return \core_search\manager::ACCESS_GRANTED;
}
/**
* Link to glossary entry.
*
* @param \core_search\document $doc
* @return \moodle_url
*/
public function get_doc_url(\core_search\document $doc) {
global $USER;
// The post is already in static cache, we fetch it in self::search_access.
$entry = $this->get_entry($doc->get('itemid'));
$contextmodule = \context::instance_by_id($doc->get('contextid'));
if ($entry->approved == false && $entry->userid != $USER->id) {
// The URL should change when the entry is not approved and it was not created by the user.
$docparams = array('id' => $contextmodule->instanceid, 'mode' => 'approval');
} else {
$docparams = array('id' => $contextmodule->instanceid, 'mode' => 'entry', 'hook' => $doc->get('itemid'));
}
return new \moodle_url('/mod/glossary/view.php', $docparams);
}
/**
* Link to the glossary.
*
* @param \core_search\document $doc
* @return \moodle_url
*/
public function get_context_url(\core_search\document $doc) {
$contextmodule = \context::instance_by_id($doc->get('contextid'));
return new \moodle_url('/mod/glossary/view.php', array('id' => $contextmodule->instanceid));
}
/**
* Returns the specified glossary entry checking the internal cache.
*
* Store minimal information as this might grow.
*
* @throws \dml_exception
* @param int $entryid
* @return stdClass
*/
protected function get_entry($entryid) {
global $DB;
if (empty($this->entriesdata[$entryid])) {
$this->entriesdata[$entryid] = $DB->get_record_sql("SELECT ge.*, g.course, g.defaultapproval FROM {glossary_entries} ge
JOIN {glossary} g ON g.id = ge.glossaryid
WHERE ge.id = ?", array('id' => $entryid), MUST_EXIST);
}
return $this->entriesdata[$entryid];
}
/**
* Returns true if this area uses file indexing.
*
* @return bool
*/
public function uses_file_indexing() {
return true;
}
/**
* Return the context info required to index files for
* this search area.
*
* @return array
*/
public function get_search_fileareas() {
$fileareas = array('attachment', 'entry'); // Fileareas.
return $fileareas;
}
}
+234
View File
@@ -0,0 +1,234 @@
<?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/>.
/**
* Plugin capabilities
*
* @package mod_glossary
* @copyright 2006 Martin Dougiamas
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$capabilities = array(
'mod/glossary:addinstance' => array(
'riskbitmask' => RISK_XSS,
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
'archetypes' => array(
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
),
'clonepermissionsfrom' => 'moodle/course:manageactivities'
),
'mod/glossary:view' => array(
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'frontpage' => CAP_ALLOW,
'guest' => CAP_ALLOW,
'student' => CAP_ALLOW,
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/glossary:write' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'student' => CAP_ALLOW,
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/glossary:manageentries' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/glossary:managecategories' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/glossary:comment' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'student' => CAP_ALLOW,
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/glossary:managecomments' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/glossary:import' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/glossary:export' => array(
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/glossary:approve' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/glossary:rate' => array(
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/glossary:viewrating' => array(
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/glossary:viewanyrating' => array(
'riskbitmask' => RISK_PERSONAL,
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
),
'clonepermissionsfrom' => 'mod/glossary:viewrating'
),
'mod/glossary:viewallratings' => array(
'riskbitmask' => RISK_PERSONAL,
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
),
'clonepermissionsfrom' => 'mod/glossary:viewrating'
),
'mod/glossary:exportentry' => array(
'riskbitmask' => RISK_PERSONAL,
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
'mod/glossary:exportownentry' => array(
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW,
'student' => CAP_ALLOW,
)
),
);
+35
View 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/>.
/**
* Glossary cache definitions.
*
* @package mod_glossary
* @category cache
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$definitions = array(
// This MUST NOT be a local cache, sorry cluster lovers.
'concepts' => array(
'mode' => cache_store::MODE_APPLICATION,
'simplekeys' => true, // The course id or 0 for global.
'simpledata' => false,
'staticacceleration' => true,
'staticaccelerationsize' => 30,
),
);
+32
View File
@@ -0,0 +1,32 @@
<?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/>.
/**
* Glossary event observer.
*
* @package mod_glossary
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$observers = array(
array (
'eventname' => '\core\event\course_module_updated',
'callback' => '\mod_glossary\local\concept_cache::cm_updated',
),
);
+126
View File
@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/glossary/db" VERSION="20150602" COMMENT="XMLDB file for Moodle mod/glossary"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
<TABLES>
<TABLE NAME="glossary" COMMENT="all glossaries">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="intro" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="introformat" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="allowduplicatedentries" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="displayformat" TYPE="char" LENGTH="50" NOTNULL="true" DEFAULT="dictionary" SEQUENCE="false"/>
<FIELD NAME="mainglossary" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="showspecial" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="showalphabet" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="showall" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="allowcomments" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="allowprintview" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="usedynalink" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="defaultapproval" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="approvaldisplayformat" TYPE="char" LENGTH="50" NOTNULL="true" DEFAULT="default" SEQUENCE="false" COMMENT="Display Format when approving entries"/>
<FIELD NAME="globalglossary" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="entbypage" TYPE="int" LENGTH="3" NOTNULL="true" DEFAULT="10" SEQUENCE="false"/>
<FIELD NAME="editalways" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="rsstype" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="rssarticles" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="assessed" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="assesstimestart" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="assesstimefinish" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="scale" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="completionentries" TYPE="int" LENGTH="9" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Non zero if a certain number of entries are required to mark this glossary complete for a user."/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="course" UNIQUE="false" FIELDS="course"/>
</INDEXES>
</TABLE>
<TABLE NAME="glossary_entries" COMMENT="all glossary entries">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="glossaryid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="concept" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="definition" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="definitionformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="definitiontrust" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="attachment" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="teacherentry" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="sourceglossaryid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="usedynalink" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="casesensitive" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="fullmatch" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="approved" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="glossaryid" TYPE="foreign" FIELDS="glossaryid" REFTABLE="glossary" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="userid" UNIQUE="false" FIELDS="userid"/>
<INDEX NAME="concept" UNIQUE="false" FIELDS="concept"/>
</INDEXES>
</TABLE>
<TABLE NAME="glossary_alias" COMMENT="entries alias">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="entryid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="alias" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="entryid" TYPE="foreign" FIELDS="entryid" REFTABLE="glossary_entries" REFFIELDS="id"/>
</KEYS>
</TABLE>
<TABLE NAME="glossary_categories" COMMENT="all categories for glossary entries">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="glossaryid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="usedynalink" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="glossaryid" TYPE="foreign" FIELDS="glossaryid" REFTABLE="glossary" REFFIELDS="id"/>
</KEYS>
</TABLE>
<TABLE NAME="glossary_entries_categories" COMMENT="categories of each glossary entry">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="categoryid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="entryid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="categoryid" TYPE="foreign" FIELDS="categoryid" REFTABLE="glossary_categories" REFFIELDS="id"/>
<KEY NAME="entryid" TYPE="foreign" FIELDS="entryid" REFTABLE="glossary_entries" REFFIELDS="id"/>
</KEYS>
</TABLE>
<TABLE NAME="glossary_formats" COMMENT="Setting of the display formats">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="name" TYPE="char" LENGTH="50" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="popupformatname" TYPE="char" LENGTH="50" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="visible" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="showgroup" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="showtabs" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="defaultmode" TYPE="char" LENGTH="50" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="defaulthook" TYPE="char" LENGTH="50" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="sortkey" TYPE="char" LENGTH="50" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="sortorder" TYPE="char" LENGTH="50" NOTNULL="true" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
</KEYS>
</TABLE>
</TABLES>
</XMLDB>
+42
View File
@@ -0,0 +1,42 @@
<?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/>.
/**
* Definition of log events
*
* @package mod_glossary
* @category log
* @copyright 2010 Petr Skoda (http://skodak.org)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$logs = array(
array('module'=>'glossary', 'action'=>'add', 'mtable'=>'glossary', 'field'=>'name'),
array('module'=>'glossary', 'action'=>'update', 'mtable'=>'glossary', 'field'=>'name'),
array('module'=>'glossary', 'action'=>'view', 'mtable'=>'glossary', 'field'=>'name'),
array('module'=>'glossary', 'action'=>'view all', 'mtable'=>'glossary', 'field'=>'name'),
array('module'=>'glossary', 'action'=>'add entry', 'mtable'=>'glossary', 'field'=>'name'),
array('module'=>'glossary', 'action'=>'update entry', 'mtable'=>'glossary', 'field'=>'name'),
array('module'=>'glossary', 'action'=>'add category', 'mtable'=>'glossary', 'field'=>'name'),
array('module'=>'glossary', 'action'=>'update category', 'mtable'=>'glossary', 'field'=>'name'),
array('module'=>'glossary', 'action'=>'delete category', 'mtable'=>'glossary', 'field'=>'name'),
array('module'=>'glossary', 'action'=>'approve entry', 'mtable'=>'glossary', 'field'=>'name'),
array('module'=>'glossary', 'action'=>'disapprove entry', 'mtable'=>'glossary', 'field'=>'name'),
array('module'=>'glossary', 'action'=>'view entry', 'mtable'=>'glossary_entries', 'field'=>'concept'),
);
+190
View File
@@ -0,0 +1,190 @@
<?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/>.
/**
* Glossary module external functions.
*
* @package mod_glossary
* @category external
* @copyright 2015 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$functions = array(
'mod_glossary_get_glossaries_by_courses' => array(
'classname' => 'mod_glossary_external',
'methodname' => 'get_glossaries_by_courses',
'description' => 'Retrieve a list of glossaries from several courses.',
'type' => 'read',
'capabilities' => 'mod/glossary:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_glossary_view_glossary' => array(
'classname' => 'mod_glossary_external',
'methodname' => 'view_glossary',
'description' => 'Notify the glossary as being viewed.',
'type' => 'write',
'capabilities' => 'mod/glossary:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_glossary_view_entry' => array(
'classname' => 'mod_glossary_external',
'methodname' => 'view_entry',
'description' => 'Notify a glossary entry as being viewed.',
'type' => 'write',
'ajax' => true,
'capabilities' => 'mod/glossary:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_glossary_get_entries_by_letter' => array(
'classname' => 'mod_glossary_external',
'methodname' => 'get_entries_by_letter',
'description' => 'Browse entries by letter.',
'type' => 'read',
'capabilities' => 'mod/glossary:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_glossary_get_entries_by_date' => array(
'classname' => 'mod_glossary_external',
'methodname' => 'get_entries_by_date',
'description' => 'Browse entries by date.',
'type' => 'read',
'capabilities' => 'mod/glossary:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_glossary_get_categories' => array(
'classname' => 'mod_glossary_external',
'methodname' => 'get_categories',
'description' => 'Get the categories.',
'type' => 'read',
'capabilities' => 'mod/glossary:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_glossary_get_entries_by_category' => array(
'classname' => 'mod_glossary_external',
'methodname' => 'get_entries_by_category',
'description' => 'Browse entries by category.',
'type' => 'read',
'capabilities' => 'mod/glossary:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_glossary_get_authors' => array(
'classname' => 'mod_glossary_external',
'methodname' => 'get_authors',
'description' => 'Get the authors.',
'type' => 'read',
'capabilities' => 'mod/glossary:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_glossary_get_entries_by_author' => array(
'classname' => 'mod_glossary_external',
'methodname' => 'get_entries_by_author',
'description' => 'Browse entries by author.',
'type' => 'read',
'capabilities' => 'mod/glossary:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_glossary_get_entries_by_author_id' => array(
'classname' => 'mod_glossary_external',
'methodname' => 'get_entries_by_author_id',
'description' => 'Browse entries by author ID.',
'type' => 'read',
'capabilities' => 'mod/glossary:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_glossary_get_entries_by_search' => array(
'classname' => 'mod_glossary_external',
'methodname' => 'get_entries_by_search',
'description' => 'Browse entries by search query.',
'type' => 'read',
'capabilities' => 'mod/glossary:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_glossary_get_entries_by_term' => array(
'classname' => 'mod_glossary_external',
'methodname' => 'get_entries_by_term',
'description' => 'Browse entries by term (concept or alias).',
'type' => 'read',
'capabilities' => 'mod/glossary:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_glossary_get_entries_to_approve' => array(
'classname' => 'mod_glossary_external',
'methodname' => 'get_entries_to_approve',
'description' => 'Browse entries to be approved.',
'type' => 'read',
'capabilities' => 'mod/glossary:approve',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_glossary_get_entry_by_id' => array(
'classname' => 'mod_glossary_external',
'methodname' => 'get_entry_by_id',
'description' => 'Get an entry by ID',
'type' => 'read',
'ajax' => true,
'capabilities' => 'mod/glossary:view',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_glossary_add_entry' => array(
'classname' => 'mod_glossary_external',
'methodname' => 'add_entry',
'description' => 'Add a new entry to a given glossary',
'type' => 'write',
'capabilities' => 'mod/glossary:write',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
),
'mod_glossary_delete_entry' => [
'classname' => 'mod_glossary\external\delete_entry',
'classpath' => '',
'description' => 'Delete the given entry from the glossary.',
'type' => 'write',
'services' => [MOODLE_OFFICIAL_MOBILE_SERVICE]
],
'mod_glossary_update_entry' => [
'classname' => 'mod_glossary\external\update_entry',
'classpath' => '',
'description' => 'Updates the given glossary entry.',
'type' => 'write',
'services' => [MOODLE_OFFICIAL_MOBILE_SERVICE]
],
'mod_glossary_prepare_entry_for_edition' => [
'classname' => 'mod_glossary\external\prepare_entry',
'classpath' => '',
'description' => 'Prepares the given entry for edition returning draft item areas and file areas information.',
'type' => 'read',
'services' => [MOODLE_OFFICIAL_MOBILE_SERVICE]
],
);
+35
View 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',
),
);
+56
View File
@@ -0,0 +1,56 @@
<?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/>.
/**
* This file keeps track of upgrades to the glossary module
*
* Sometimes, changes between versions involve
* alterations to database structures and other
* major things that may break installations.
*
* The upgrade function in this file will attempt
* to perform all the necessary actions to upgrade
* your older installation to the current version.
*
* If there's something it cannot do itself, it
* will tell you what you need to do.
*
* The commands in here will all be database-neutral,
* using the methods of database_manager class
*
* Please do not forget to use upgrade_set_timeout()
* before any action that may take longer time to finish.
*
* @package mod_glossary
* @copyright 2006 Eloy Lafuente (stronk7)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
function xmldb_glossary_upgrade($oldversion) {
// Automatically generated Moodle v4.1.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.2.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.3.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
+80
View File
@@ -0,0 +1,80 @@
<?php
require_once("../../config.php");
require_once("lib.php");
$id = required_param('id', PARAM_INT); // course module ID
$confirm = optional_param('confirm', 0, PARAM_INT); // commit the operation?
$entry = optional_param('entry', 0, PARAM_INT); // entry id
$prevmode = required_param('prevmode', PARAM_ALPHA);
$hook = optional_param('hook', '', PARAM_CLEAN);
$url = new moodle_url('/mod/glossary/deleteentry.php', array('id'=>$id,'prevmode'=>$prevmode));
if ($confirm !== 0) {
$url->param('confirm', $confirm);
}
if ($entry !== 0) {
$url->param('entry', $entry);
}
if ($hook !== '') {
$url->param('hook', $hook);
}
$PAGE->set_url($url);
$strglossary = get_string("modulename", "glossary");
$strglossaries = get_string("modulenameplural", "glossary");
$stredit = get_string("edit");
$entrydeleted = get_string("entrydeleted","glossary");
if (! $cm = get_coursemodule_from_id('glossary', $id)) {
throw new \moodle_exception("invalidcoursemodule");
}
if (! $course = $DB->get_record("course", array("id"=>$cm->course))) {
throw new \moodle_exception('coursemisconf');
}
if (! $entry = $DB->get_record("glossary_entries", array("id"=>$entry))) {
throw new \moodle_exception('invalidentry');
}
// Permission checks are based on the course module instance so make sure it is correct.
if ($cm->instance != $entry->glossaryid) {
throw new \moodle_exception('invalidentry');
}
require_login($course, false, $cm);
$context = context_module::instance($cm->id);
if (! $glossary = $DB->get_record("glossary", array("id"=>$cm->instance))) {
throw new \moodle_exception('invalidid', 'glossary');
}
// Throws an exception if the user cannot delete the entry.
mod_glossary_can_delete_entry($entry, $glossary, $context, false);
/// If data submitted, then process and store.
if ($confirm and confirm_sesskey()) { // the operation was confirmed.
mod_glossary_delete_entry($entry, $glossary, $cm, $context, $course, $hook, $prevmode);
redirect("view.php?id=$cm->id&amp;mode=$prevmode&amp;hook=$hook");
} else { // the operation has not been confirmed yet so ask the user to do so
$strareyousuredelete = get_string("areyousuredelete", "glossary");
$PAGE->navbar->add(get_string('delete'));
$PAGE->set_title($glossary->name);
$PAGE->set_heading($course->fullname);
$PAGE->activityheader->disable();
echo $OUTPUT->header();
$areyousure = "<b>".format_string($entry->concept)."</b><p>$strareyousuredelete</p>";
$linkyes = 'deleteentry.php';
$linkno = 'view.php';
$optionsyes = array('id'=>$cm->id, 'entry'=>$entry->id, 'confirm'=>1, 'sesskey'=>sesskey(), 'prevmode'=>$prevmode, 'hook'=>$hook);
$optionsno = array('id'=>$cm->id, 'mode'=>$prevmode, 'hook'=>$hook);
echo $OUTPUT->confirm($areyousure, new moodle_url($linkyes, $optionsyes), new moodle_url($linkno, $optionsno));
echo $OUTPUT->footer();
}
+31
View File
@@ -0,0 +1,31 @@
<?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/>.
/**
* List of deprecated mod_glossary functions.
*
* @package mod_glossary
* @copyright 2021 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* @deprecated since Moodle 3.11
*/
function glossary_get_completion_state() {
$completionclass = \mod_glossary\completion\custom_completion::class;
throw new coding_exception(__FUNCTION__ . "() has been removed, please use the '{$completionclass}' class instead");
}
+104
View File
@@ -0,0 +1,104 @@
<?php
require_once('../../config.php');
require_once('lib.php');
require_once('edit_form.php');
$cmid = required_param('cmid', PARAM_INT); // Course Module ID
$id = optional_param('id', 0, PARAM_INT); // EntryID
if (!$cm = get_coursemodule_from_id('glossary', $cmid)) {
throw new \moodle_exception('invalidcoursemodule');
}
if (!$course = $DB->get_record('course', array('id'=>$cm->course))) {
throw new \moodle_exception('coursemisconf');
}
require_login($course, false, $cm);
$context = context_module::instance($cm->id);
if (!$glossary = $DB->get_record('glossary', array('id'=>$cm->instance))) {
throw new \moodle_exception('invalidid', 'glossary');
}
$url = new moodle_url('/mod/glossary/edit.php', array('cmid'=>$cm->id));
if (!empty($id)) {
$url->param('id', $id);
}
$PAGE->set_url($url);
if ($id) { // if entry is specified
if (isguestuser()) {
throw new \moodle_exception('guestnoedit', 'glossary', "$CFG->wwwroot/mod/glossary/view.php?id=$cmid");
}
if (!$entry = $DB->get_record('glossary_entries', array('id'=>$id, 'glossaryid'=>$glossary->id))) {
throw new \moodle_exception('invalidentry');
}
// 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);
// note: guest user does not have any write capability
$entry = new stdClass();
$entry->id = null;
}
list($definitionoptions, $attachmentoptions) = glossary_get_editor_and_attachment_options($course, $context, $entry);
$entry = file_prepare_standard_editor($entry, 'definition', $definitionoptions, $context, 'mod_glossary', 'entry', $entry->id);
$entry = file_prepare_standard_filemanager($entry, 'attachment', $attachmentoptions, $context, 'mod_glossary', 'attachment', $entry->id);
$entry->cmid = $cm->id;
// create form and set initial data
$mform = new mod_glossary_entry_form(null, array('current'=>$entry, 'cm'=>$cm, 'glossary'=>$glossary,
'definitionoptions'=>$definitionoptions, 'attachmentoptions'=>$attachmentoptions));
if ($mform->is_cancelled()){
if ($id){
redirect("view.php?id=$cm->id&mode=entry&hook=$id");
} else {
redirect("view.php?id=$cm->id");
}
} 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");
}
if (!empty($id)) {
$PAGE->navbar->add(get_string('edit'));
}
$PAGE->set_title($glossary->name);
$PAGE->set_heading($course->fullname);
$PAGE->set_secondary_active_tab('modulepage');
$PAGE->activityheader->set_attrs([
'hidecompletion' => true,
'description' => ''
]);
echo $OUTPUT->header();
if (!$id) {
echo $OUTPUT->heading(get_string('addsingleentry', 'mod_glossary'));
} else {
echo $OUTPUT->heading(get_string('editentry', 'mod_glossary'));
}
$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();
+152
View File
@@ -0,0 +1,152 @@
<?php
if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
}
require_once ($CFG->dirroot.'/lib/formslib.php');
class mod_glossary_entry_form extends moodleform {
function definition() {
global $CFG, $DB;
$mform = $this->_form;
$currententry = $this->_customdata['current'];
$glossary = $this->_customdata['glossary'];
$cm = $this->_customdata['cm'];
$definitionoptions = $this->_customdata['definitionoptions'];
$attachmentoptions = $this->_customdata['attachmentoptions'];
$context = context_module::instance($cm->id);
// Prepare format_string/text options
$fmtoptions = array(
'context' => $context);
//-------------------------------------------------------------------------------
$mform->addElement('header', 'general', get_string('general', 'form'));
$mform->addElement('text', 'concept', get_string('concept', 'glossary'));
$mform->setType('concept', PARAM_TEXT);
$mform->addRule('concept', null, 'required', null, 'client');
$mform->addElement('editor', 'definition_editor', get_string('definition', 'glossary'), null, $definitionoptions);
$mform->setType('definition_editor', PARAM_RAW);
$mform->addRule('definition_editor', get_string('required'), 'required', null, 'client');
if ($categories = $DB->get_records_menu('glossary_categories', array('glossaryid'=>$glossary->id), 'name ASC', 'id, name')){
foreach ($categories as $id => $name) {
$categories[$id] = format_string($name, true, $fmtoptions);
}
$categories = array(0 => get_string('notcategorised', 'glossary')) + $categories;
$categoriesEl = $mform->addElement('select', 'categories', get_string('categories', 'glossary'), $categories);
$categoriesEl->setMultiple(true);
$categoriesEl->setSize(5);
}
$mform->addElement('textarea', 'aliases', get_string('aliases', 'glossary'), 'rows="2" cols="40"');
$mform->setType('aliases', PARAM_TEXT);
$mform->addHelpButton('aliases', 'aliases', 'glossary');
$mform->addElement('filemanager', 'attachment_filemanager', get_string('attachment', 'glossary'), null, $attachmentoptions);
$mform->addHelpButton('attachment_filemanager', 'attachment', 'glossary');
if (!$glossary->usedynalink) {
$mform->addElement('hidden', 'usedynalink', $CFG->glossary_linkentries);
$mform->setType('usedynalink', PARAM_INT);
$mform->addElement('hidden', 'casesensitive', $CFG->glossary_casesensitive);
$mform->setType('casesensitive', PARAM_INT);
$mform->addElement('hidden', 'fullmatch', $CFG->glossary_fullmatch);
$mform->setType('fullmatch', PARAM_INT);
} else {
//-------------------------------------------------------------------------------
$mform->addElement('header', 'linkinghdr', get_string('linking', 'glossary'));
$mform->addElement('checkbox', 'usedynalink', get_string('entryusedynalink', 'glossary'));
$mform->addHelpButton('usedynalink', 'entryusedynalink', 'glossary');
$mform->setDefault('usedynalink', $CFG->glossary_linkentries);
$mform->addElement('checkbox', 'casesensitive', get_string('casesensitive', 'glossary'));
$mform->addHelpButton('casesensitive', 'casesensitive', 'glossary');
$mform->hideIf('casesensitive', 'usedynalink');
$mform->setDefault('casesensitive', $CFG->glossary_casesensitive);
$mform->addElement('checkbox', 'fullmatch', get_string('fullmatch', 'glossary'));
$mform->addHelpButton('fullmatch', 'fullmatch', 'glossary');
$mform->hideIf('fullmatch', 'usedynalink');
$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');
$mform->setType('cmid', PARAM_INT);
//-------------------------------------------------------------------------------
$this->add_action_buttons();
//-------------------------------------------------------------------------------
$this->set_data($currententry);
}
function validation($data, $files) {
global $CFG, $USER, $DB;
$errors = parent::validation($data, $files);
$glossary = $this->_customdata['glossary'];
$cm = $this->_customdata['cm'];
$context = context_module::instance($cm->id);
$id = (int)$data['id'];
$data['concept'] = trim($data['concept']);
$aliases = explode("\r\n", trim($data['aliases']));
foreach ($aliases as $alias) {
// Check if the alias is just a single character and that it doesn't match reserved symbols.
if (strlen(trim($alias)) == 1 && preg_match('/[$-\/:-?{-~!"^_`\[\]]/', trim($alias))) {
$errors['aliases'] = get_string('errreservedkeywords', 'glossary');
}
}
if ($id) {
//We are updating an entry, so we compare current session user with
//existing entry user to avoid some potential problems if secureforms=off
//Perhaps too much security? Anyway thanks to skodak (Bug 1823)
$old = $DB->get_record('glossary_entries', array('id'=>$id));
$ineditperiod = ((time() - $old->timecreated < $CFG->maxeditingtime) || $glossary->editalways);
if ((!$ineditperiod || $USER->id != $old->userid) and !has_capability('mod/glossary:manageentries', $context)) {
if ($USER->id != $old->userid) {
$errors['concept'] = get_string('errcannoteditothers', 'glossary');
} elseif (!$ineditperiod) {
$errors['concept'] = get_string('erredittimeexpired', 'glossary');
}
}
if (!$glossary->allowduplicatedentries) {
if ($DB->record_exists_select('glossary_entries',
'glossaryid = :glossaryid AND LOWER(concept) = :concept AND id != :id', array(
'glossaryid' => $glossary->id,
'concept' => core_text::strtolower($data['concept']),
'id' => $id))) {
$errors['concept'] = get_string('errconceptalreadyexists', 'glossary');
}
}
} else {
if (!$glossary->allowduplicatedentries) {
if (glossary_concept_exists($glossary, $data['concept'])) {
$errors['concept'] = get_string('errconceptalreadyexists', 'glossary');
}
}
}
return $errors;
}
}
+77
View File
@@ -0,0 +1,77 @@
<?php
global $CFG;
require_once("../../config.php");
?>
<div class="boxaligncenter">
<form id="form" method="post" action="editcategories.php">
<div id="fitem_id_name" class="mb-3 row fitem">
<div class="col-md-3">
<label class="col-form-label d-inline " for="name">
<?php echo get_string("name") ?>
</label>
</div>
<div class="col-md-9 d-flex flex-wrap align-items-center felement" data-fieldtype="select">
<input type="text" name="name" id="name" class="form-control" size="30" value="<?php p($name) ?>" />
</div>
</div>
<div id="fitem_id_usedynalink" class="mb-3 row fitem">
<div class="col-md-3">
<span class="float-sm-right text-nowrap">
<?php echo $OUTPUT->help_icon('linkcategory', 'glossary') ?>
</span>
<label class="col-form-label d-inline " for="usedynalink">
<?php echo get_string("linkcategory","glossary") ?>
</label>
</div>
<div class="col-md-9 d-flex flex-wrap align-items-center felement" data-fieldtype="select">
<select size="1" id="usedynalink" name="usedynalink" class="custom-select">
<option value="1" <?php
if ( $usedynalink ) {
echo "selected=\"selected\"";
}
?>><?php echo get_string("yes") ?></option>
<option value="0" <?php
if ( !$usedynalink ) {
echo "selected=\"selected\"";
}
?>><?php echo get_string("no") ?>
</option>
</select>
</div>
</div>
<div id="fgroup_id_buttonar" class="mb-3 row fitem femptylabel" data-groupname="buttonar">
<div class="col-md-3">
<span class="float-sm-right text-nowrap">
</span>
<label class="col-form-label d-inline " for="fgroup_id_buttonar">
</label>
</div>
<div class="col-md-9 d-flex flex-wrap align-items-center felement" data-fieldtype="group">
<div class="mb-3 fitem form-submit mr-1">
<label class="col-form-label" for="id_save">
</label>
<span data-fieldtype="submit">
<input type="hidden" name="sesskey" value="<?php echo sesskey(); ?>" />
<input type="hidden" name="id" value="<?php p($cm->id) ?>" />
<input type="hidden" name="action" value="<?php p($action) ?>" />
<input type="hidden" name="confirm" value="1" />
<input type="hidden" name="mode" value='cat' />
<input type="hidden" name="hook" value="<?php p($hook) ?>" />
<input type="submit" class="btn btn-primary" name="save" id="id_save"
value="<?php echo get_string("savechanges") ?>" />
</span>
</div>
<div class="mb-3 fitem btn-cancel">
<label class="col-form-label" for="id_back">
</label>
<span data-fieldtype="submit">
<input type="reset" class="btn btn-secondary" name="back" id="id_back"
value="<?php print_string("back", "glossary") ?>" onclick="javascript:history.go(-1);" />
</span>
</div>
</div>
</div>
<div>
</div>
</form>
</div>
+308
View File
@@ -0,0 +1,308 @@
<?php
/// This page allows to edit entries categories for a particular instance of glossary
require_once("../../config.php");
require_once("lib.php");
$id = required_param('id', PARAM_INT); // Course Module ID, or
$usedynalink = optional_param('usedynalink', 0, PARAM_INT); // category ID
$confirm = optional_param('confirm', 0, PARAM_INT); // confirm the action
$name = optional_param('name', '', PARAM_CLEAN); // confirm the name
$action = optional_param('action', '', PARAM_ALPHA ); // what to do
$hook = optional_param('hook', '', PARAM_ALPHANUM); // category ID
$mode = optional_param('mode', '', PARAM_ALPHA); // cat
$action = strtolower($action);
$url = new moodle_url('/mod/glossary/editcategories.php', array('id'=>$id));
if ($usedynalink !== 0) {
$url->param('usedynalink', $usedynalink);
}
if ($confirm !== 0) {
$url->param('confirm', $confirm);
}
if ($name !== 'name') {
$url->param('name', $name);
}
if ($action !== 'action') {
$url->param('action', $action);
}
if ($hook !== 'hook') {
$url->param('hook', $hook);
}
if ($mode !== 'mode') {
$url->param('mode', $mode);
}
$PAGE->set_url($url);
if (! $cm = get_coursemodule_from_id('glossary', $id)) {
throw new \moodle_exception('invalidcoursemodule');
}
if (! $course = $DB->get_record("course", array("id"=>$cm->course))) {
throw new \moodle_exception('coursemisconf');
}
if (! $glossary = $DB->get_record("glossary", array("id"=>$cm->instance))) {
throw new \moodle_exception('invalidcoursemodule');
}
if ($hook > 0) {
if ($category = $DB->get_record("glossary_categories", array("id"=>$hook))) {
//Check it belongs to the same glossary
if ($category->glossaryid != $glossary->id) {
throw new \moodle_exception('invalidid', 'glossary');
}
} else {
throw new \moodle_exception('invalidcategoryid');
}
}
require_login($course, false, $cm);
$context = context_module::instance($cm->id);
require_capability('mod/glossary:managecategories', $context);
$strglossaries = get_string("modulenameplural", "glossary");
$strglossary = get_string("modulename", "glossary");
$PAGE->navbar->add(get_string("categories","glossary"),
new moodle_url('/mod/glossary/editcategories.php', array('id' => $cm->id,'mode' => 'cat')));
if (!empty($action)) {
$navaction = get_string(core_text::strtolower($action."category"), 'glossary');
$PAGE->navbar->add($navaction);
}
$PAGE->set_title($glossary->name);
$PAGE->set_heading($course->fullname);
// Prepare format_string/text options
$fmtoptions = array(
'context' => $context);
if (right_to_left()) { // RTL table alignment support
$rightalignment = 'left';
$leftalignment = 'right';
} else {
$rightalignment = 'right';
$leftalignment = 'left';
}
if ( $hook >0 ) {
if ( $action == "edit" ) {
if ( $confirm ) {
require_sesskey();
$action = "";
$cat = new stdClass();
$cat->id = $hook;
$cat->name = $name;
$cat->usedynalink = $usedynalink;
$DB->update_record("glossary_categories", $cat);
$event = \mod_glossary\event\category_updated::create(array(
'context' => $context,
'objectid' => $hook
));
$cat->glossaryid = $glossary->id;
$event->add_record_snapshot('glossary_categories', $cat);
$event->add_record_snapshot('glossary', $glossary);
$event->trigger();
// Reset caches.
\mod_glossary\local\concept_cache::reset_glossary($glossary);
} else {
echo $OUTPUT->header();
echo $OUTPUT->heading(format_string($glossary->name), 2);
echo $OUTPUT->heading(format_string(get_string("editcategory", "glossary")), 3);
$name = $category->name;
$usedynalink = $category->usedynalink;
require "editcategories.html";
echo $OUTPUT->footer();
die;
}
} elseif ( $action == "delete" ) {
if ( $confirm ) {
require_sesskey();
$DB->delete_records("glossary_entries_categories", array("categoryid"=>$hook));
$DB->delete_records("glossary_categories", array("id"=>$hook));
$event = \mod_glossary\event\category_deleted::create(array(
'context' => $context,
'objectid' => $hook
));
$event->add_record_snapshot('glossary_categories', $category);
$event->add_record_snapshot('glossary', $glossary);
$event->trigger();
// Reset caches.
\mod_glossary\local\concept_cache::reset_glossary($glossary);
redirect("editcategories.php?id=$cm->id", get_string("categorydeleted", "glossary"), 2);
} else {
echo $OUTPUT->header();
echo $OUTPUT->heading(format_string($glossary->name), 2);
echo $OUTPUT->heading(format_string(get_string("deletecategory", "glossary")), 3);
echo $OUTPUT->box_start('generalbox boxaligncenter errorboxcontent boxwidthnarrow');
echo "<div class=\"boxaligncenter deletecatconfirm\">".format_string($category->name, true, $fmtoptions)."<br/>";
$num_entries = $DB->count_records("glossary_entries_categories", array("categoryid"=>$category->id));
if ( $num_entries ) {
print_string("deletingnoneemptycategory","glossary");
}
echo "<p>";
print_string("areyousuredelete","glossary");
echo "</p>";
?>
<table border="0" width="100" class="confirmbuttons">
<tr>
<td align="$rightalignment" style="width:50%">
<form id="form" method="post" action="editcategories.php">
<div>
<input type="hidden" name="sesskey" value="<?php echo sesskey(); ?>" />
<input type="hidden" name="id" value="<?php p($cm->id) ?>" />
<input type="hidden" name="action" value="delete" />
<input type="hidden" name="confirm" value="1" />
<input type="hidden" name="mode" value="<?php echo $mode ?>" />
<input type="hidden" name="hook" value="<?php echo $hook ?>" />
<input type="submit" class="btn btn-primary" value=" <?php print_string("yes")?> " />
</div>
</form>
</td>
<td align="$leftalignment" style="width:50%">
<?php
unset($options);
$options = array ("id" => $id);
echo $OUTPUT->single_button(new moodle_url("editcategories.php", $options), get_string("no"));
echo "</td></tr></table>";
echo "</div>";
echo $OUTPUT->box_end();
}
}
} elseif ( $action == "add" ) {
if ( $confirm ) {
require_sesskey();
$dupcategory = $DB->get_records_sql("SELECT * FROM {glossary_categories} WHERE ".$DB->sql_like('name','?', false)." AND glossaryid=?", array($name, $glossary->id));
if ( $dupcategory ) {
redirect("editcategories.php?id=$cm->id&amp;action=add&amp;name=$name", get_string("duplicatecategory", "glossary"), 2);
} else {
$action = "";
$cat = new stdClass();
$cat->name = $name;
$cat->usedynalink = $usedynalink;
$cat->glossaryid = $glossary->id;
$cat->id = $DB->insert_record("glossary_categories", $cat);
$event = \mod_glossary\event\category_created::create(array(
'context' => $context,
'objectid' => $cat->id
));
$event->add_record_snapshot('glossary_categories', $cat);
$event->add_record_snapshot('glossary', $glossary);
$event->trigger();
// Reset caches.
\mod_glossary\local\concept_cache::reset_glossary($glossary);
}
} else {
echo $OUTPUT->header();
echo $OUTPUT->heading(format_string($glossary->name), 2);
echo "<h3 class=\"main\">" . get_string("addcategory", "glossary"). "</h3>";
$name="";
require "editcategories.html";
}
}
if ( $action ) {
echo $OUTPUT->footer();
die;
}
echo $OUTPUT->header();
echo $OUTPUT->heading(format_string($glossary->name), 2);
?>
<form method="post" action="editcategories.php">
<table width="40%" class="boxaligncenter generalbox" cellpadding="5">
<tr>
<th style="width:90%" align="center">
<?php p(get_string("categories","glossary")) ?></th>
<th style="width:10%" align="center">
<?php p(get_string("action")) ?></th>
</tr>
<tr><td style="width:100%" colspan="2">
<?php
$categories = $DB->get_records("glossary_categories", array("glossaryid"=>$glossary->id), "name ASC");
if ( $categories ) {
echo '<table width="100%">';
foreach ($categories as $category) {
$num_entries = $DB->count_records("glossary_entries_categories", array("categoryid"=>$category->id));
?>
<tr>
<td style="width:80%" align="$leftalignment">
<?php
echo "<span class=\"bold\">".format_string($category->name, true, $fmtoptions)."</span> <span>($num_entries " . get_string("entries","glossary") . ")</span>";
?>
</td>
<td style="width:19%" align="center" class="action">
<?php
echo "<a href=\"editcategories.php?id=$cm->id&amp;action=delete&amp;mode=cat&amp;hook=$category->id\">" .
$OUTPUT->pix_icon('t/delete', get_string('delete')). "</a> ";
echo "<a href=\"editcategories.php?id=$cm->id&amp;action=edit&amp;mode=cat&amp;hook=$category->id\">" .
$OUTPUT->pix_icon('t/edit', get_string('edit')). "</a> ";
?>
</td>
</tr>
<?php
}
echo '</table>';
}
?>
</td></tr>
<tr>
<td style="width:100%" colspan="2" align="center">
<?php
$options['id'] = $cm->id;
$options['action'] = "add";
echo "<table class=\"editbuttons\" border=\"0\"><tr><td align=\"$rightalignment\">";
echo $OUTPUT->single_button(new moodle_url("editcategories.php", $options), get_string("addcategory", "glossary"));
echo "</td><td align=\"$leftalignment\">";
unset($options['action']);
$options['mode'] = 'cat';
$options['hook'] = $hook;
echo $OUTPUT->single_button(new moodle_url("view.php", $options), get_string("back","glossary"));
echo "</td></tr>";
echo "</table>";
?>
</td>
</tr>
</table>
</form>
<?php
echo $OUTPUT->footer();
+78
View File
@@ -0,0 +1,78 @@
<?php
require_once("../../config.php");
require_once("lib.php");
$id = required_param('id', PARAM_INT); // Course Module ID
$mode= optional_param('mode', '', PARAM_ALPHA); // term entry cat date letter search author approval
$hook= optional_param('hook', '', PARAM_CLEAN); // the term, entry, cat, etc... to look for based on mode
$cat = optional_param('cat',0, PARAM_ALPHANUM);
$url = new moodle_url('/mod/glossary/export.php', array('id'=>$id));
if ($cat !== 0) {
$url->param('cat', $cat);
}
if ($mode !== '') {
$url->param('mode', $mode);
}
$PAGE->set_url($url);
if (! $cm = get_coursemodule_from_id('glossary', $id)) {
throw new \moodle_exception('invalidcoursemodule');
}
if (! $course = $DB->get_record("course", array("id"=>$cm->course))) {
throw new \moodle_exception('coursemisconf');
}
if (! $glossary = $DB->get_record("glossary", array("id"=>$cm->instance))) {
throw new \moodle_exception('invalidid', 'glossary');
}
require_login($course, false, $cm);
$context = context_module::instance($cm->id);
require_capability('mod/glossary:export', $context);
$strglossaries = get_string("modulenameplural", "glossary");
$strglossary = get_string("modulename", "glossary");
$strallcategories = get_string("allcategories", "glossary");
$straddentry = get_string("addentry", "glossary");
$strnoentries = get_string("noentries", "glossary");
$strsearchindefinition = get_string("searchindefinition", "glossary");
$strsearch = get_string("search");
$strexportfile = get_string("exportfile", "glossary");
$strexportentries = get_string('exportentriestoxml', 'glossary');
$PAGE->set_url('/mod/glossary/export.php', array('id'=>$cm->id));
$PAGE->navbar->add($strexportentries);
$PAGE->set_title($glossary->name);
$PAGE->set_heading($course->fullname);
$PAGE->set_secondary_active_tab('modulepage');
$PAGE->activityheader->disable();
echo $OUTPUT->header();
$backlink = html_writer::link(new moodle_url('view.php', ['id' => $cm->id]),
get_string('back'), ['class' => 'btn btn-secondary']);
echo html_writer::tag('div', $backlink, ['class' => 'tertiary-navigation']);
echo $OUTPUT->heading($strexportentries);
echo $OUTPUT->box_start('glossarydisplay generalbox');
$exporturl = moodle_url::make_pluginfile_url($context->id, 'mod_glossary', 'export', 0, "/$cat/", 'export.xml', true);
?>
<form action="<?php echo $exporturl->out(); ?>" method="post">
<input class="btn btn-primary" type="submit" value="<?php p($strexportfile)?>" />
</form>
<?php
// don't need cap check here, we share with the general export.
if (!empty($CFG->enableportfolios) && $DB->count_records('glossary_entries', array('glossaryid' => $glossary->id))) {
require_once($CFG->libdir . '/portfoliolib.php');
$button = new portfolio_add_button();
$button->set_callback_options('glossary_full_portfolio_caller', array('id' => $cm->id), 'mod_glossary');
$button->render();
}
echo $OUTPUT->box_end();
echo $OUTPUT->footer();
?>
+127
View File
@@ -0,0 +1,127 @@
<?php
require_once('../../config.php');
require_once('lib.php');
$id = required_param('id', PARAM_INT); // Entry ID
$confirm = optional_param('confirm', 0, PARAM_BOOL); // export confirmation
$prevmode = required_param('prevmode', PARAM_ALPHA);
$hook = optional_param('hook', '', PARAM_CLEAN);
$url = new moodle_url('/mod/glossary/exportentry.php', array('id'=>$id,'prevmode'=>$prevmode));
if ($confirm !== 0) {
$url->param('confirm', $confirm);
}
if ($hook !== 'ALL') {
$url->param('hook', $hook);
}
$PAGE->set_url($url);
if (!$entry = $DB->get_record('glossary_entries', array('id'=>$id))) {
throw new \moodle_exception('invalidentry');
}
if ($entry->sourceglossaryid) {
//already exported
if (!$cm = get_coursemodule_from_id('glossary', $entry->sourceglossaryid)) {
throw new \moodle_exception('invalidcoursemodule');
}
redirect('view.php?id='.$cm->id.'&amp;mode=entry&amp;hook='.$entry->id);
}
if (!$cm = get_coursemodule_from_instance('glossary', $entry->glossaryid)) {
throw new \moodle_exception('invalidcoursemodule');
}
if (!$glossary = $DB->get_record('glossary', array('id'=>$cm->instance))) {
throw new \moodle_exception('invalidid', 'glossary');
}
if (!$course = $DB->get_record('course', array('id'=>$cm->course))) {
throw new \moodle_exception('coursemisconf');
}
require_course_login($course->id, true, $cm);
$context = context_module::instance($cm->id);
require_capability('mod/glossary:export', $context);
$returnurl = "view.php?id=$cm->id&amp;mode=$prevmode&amp;hook=".urlencode($hook);
if (!$mainglossary = $DB->get_record('glossary', array('course'=>$cm->course, 'mainglossary'=>1))) {
//main glossary not present
redirect($returnurl);
}
if (!$maincm = get_coursemodule_from_instance('glossary', $mainglossary->id)) {
throw new \moodle_exception('invalidcoursemodule');
}
$context = context_module::instance($cm->id);
$maincontext = context_module::instance($maincm->id);
if (!$course = $DB->get_record('course', array('id'=>$cm->course))) {
throw new \moodle_exception('coursemisconf');
}
$strglossaries = get_string('modulenameplural', 'glossary');
$entryalreadyexist = get_string('entryalreadyexist','glossary');
$entryexported = get_string('entryexported','glossary');
if (!$mainglossary->allowduplicatedentries) {
if ($DB->record_exists_select('glossary_entries',
'glossaryid = :glossaryid AND LOWER(concept) = :concept', array(
'glossaryid' => $mainglossary->id,
'concept' => core_text::strtolower($entry->concept)))) {
$PAGE->set_title($glossary->name);
$PAGE->set_heading($course->fullname);
echo $OUTPUT->header();
echo $OUTPUT->notification(get_string('errconceptalreadyexists', 'glossary'));
echo $OUTPUT->continue_button($returnurl);
echo $OUTPUT->box_end();
echo $OUTPUT->footer();
die;
}
}
if (!data_submitted() or !$confirm or !confirm_sesskey()) {
$PAGE->set_title($glossary->name);
$PAGE->set_heading($course->fullname);
echo $OUTPUT->header();
echo '<div class="boxaligncenter">';
$areyousure = '<h2>'.format_string($entry->concept).'</h2><p align="center">'.get_string('areyousureexport','glossary').'<br /><b>'.format_string($mainglossary->name).'</b>?';
$linkyes = 'exportentry.php';
$linkno = 'view.php';
$optionsyes = array('id'=>$entry->id, 'confirm'=>1, 'sesskey'=>sesskey(), 'prevmode'=>$prevmode, 'hook'=>$hook);
$optionsno = array('id'=>$cm->id, 'mode'=>$prevmode, 'hook'=>$hook);
echo $OUTPUT->confirm($areyousure, new moodle_url($linkyes, $optionsyes), new moodle_url($linkno, $optionsno));
echo '</div>';
echo $OUTPUT->footer();
die;
} else {
$entry->glossaryid = $mainglossary->id;
$entry->sourceglossaryid = $glossary->id;
$DB->update_record('glossary_entries', $entry);
// move attachments too
$fs = get_file_storage();
if ($oldfiles = $fs->get_area_files($context->id, 'mod_glossary', 'attachment', $entry->id)) {
foreach ($oldfiles as $oldfile) {
$file_record = new stdClass();
$file_record->contextid = $maincontext->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);
redirect ($returnurl);
}
+300
View File
@@ -0,0 +1,300 @@
<?php
/// This file allows to manage the default behaviour of the display formats
require_once("../../config.php");
require_once($CFG->libdir.'/adminlib.php');
require_once("lib.php");
$id = required_param('id', PARAM_INT);
$mode = optional_param('mode', '', PARAM_ALPHANUMEXT);
$url = new moodle_url('/mod/glossary/formats.php', array('id'=>$id));
if ($mode !== '') {
$url->param('mode', $mode);
}
$PAGE->set_url($url);
admin_externalpage_setup('managemodules'); // this is hacky, tehre should be a special hidden page for it
if ( !$displayformat = $DB->get_record("glossary_formats", array("id"=>$id))) {
throw new \moodle_exception('invalidglossaryformat', 'glossary');
}
$form = data_submitted();
if ( $mode == 'visible' and confirm_sesskey()) {
if ( $displayformat ) {
if ( $displayformat->visible ) {
$displayformat->visible = 0;
} else {
$displayformat->visible = 1;
}
$DB->update_record("glossary_formats",$displayformat);
}
redirect("$CFG->wwwroot/$CFG->admin/settings.php?section=modsettingglossary#glossary_formats_header");
die;
} elseif ( $mode == 'edit' and $form and confirm_sesskey()) {
$displayformat->popupformatname = $form->popupformatname;
$displayformat->showgroup = $form->showgroup;
$displayformat->defaultmode = $form->defaultmode;
$displayformat->defaulthook = $form->defaulthook;
$displayformat->sortkey = $form->sortkey;
$displayformat->sortorder = $form->sortorder;
// Extract visible tabs from array into comma separated list.
$visibletabs = implode(',', $form->visibletabs);
// Include 'standard' tab by default along with other tabs.
// This way we don't run into the risk of users not selecting any tab for displayformat.
$displayformat->showtabs = GLOSSARY_STANDARD.','.$visibletabs;
$DB->update_record("glossary_formats",$displayformat);
redirect("$CFG->wwwroot/$CFG->admin/settings.php?section=modsettingglossary#glossary_formats_header");
die;
}
$strmodulename = get_string("modulename", "glossary");
$strdisplayformats = get_string("displayformats","glossary");
echo $OUTPUT->header();
echo $OUTPUT->heading($strmodulename . ': ' . get_string("displayformats","glossary"));
echo $OUTPUT->box(get_string("configwarning", 'admin'), "generalbox boxaligncenter boxwidthnormal");
echo "<br />";
$yes = get_string("yes");
$no = get_string("no");
echo '<form method="post" action="formats.php" id="form">';
echo '<table width="90%" align="center" class="generalbox">';
?>
<tr>
<td colspan="3" align="center"><strong>
<?php echo get_string('displayformat'.$displayformat->name,'glossary'); ?>
</strong></td>
</tr>
<tr valign="top">
<td align="right" width="20%"><?php echo html_writer::label(get_string('popupformat','glossary'), 'menupopupformatname'); ?></td>
<td>
<?php
// Get available formats.
$recformats = $DB->get_records("glossary_formats");
$formats = array();
//Take names
foreach ($recformats as $format) {
$formats[$format->name] = get_string("displayformat$format->name", "glossary");
}
//Sort it
asort($formats);
echo html_writer::select($formats, 'popupformatname', $displayformat->popupformatname, false);
?>
</td>
<td width="60%">
<?php print_string("cnfrelatedview", "glossary") ?><br /><br />
</td>
</tr>
<tr valign="top">
<td align="right" width="20%"><label for="defaultmode"><?php print_string('defaultmode','glossary'); ?></label></td>
<td>
<select size="1" id="defaultmode" name="defaultmode">
<?php
$sletter = '';
$scat = '';
$sauthor = '';
$sdate = '';
switch ( strtolower($displayformat->defaultmode) ) {
case 'letter':
$sletter = ' selected="selected" ';
break;
case 'cat':
$scat = ' selected="selected" ';
break;
case 'date':
$sdate = ' selected="selected" ';
break;
case 'author':
$sauthor = ' selected="selected" ';
break;
}
?>
<option value="letter" <?php p($sletter)?>><?php print_string("letter", "glossary"); ?></option>
<option value="cat" <?php p($scat)?>><?php print_string("cat", "glossary"); ?></option>
<option value="date" <?php p($sdate)?>><?php print_string("date", "glossary"); ?></option>
<option value="author" <?php p($sauthor)?>><?php print_string("author", "glossary"); ?></option>
</select>
</td>
<td width="60%">
<?php print_string("cnfdefaultmode", "glossary") ?><br /><br />
</td>
</tr>
<tr valign="top">
<td align="right" width="20%"><label for="defaulthook"><?php print_string('defaulthook','glossary'); ?></label></td>
<td>
<select size="1" id="defaulthook" name="defaulthook">
<?php
$sall = '';
$sspecial = '';
$sallcategories = '';
$snocategorised = '';
switch ( strtolower($displayformat->defaulthook) ) {
case 'all':
$sall = ' selected="selected" ';
break;
case 'special':
$sspecial = ' selected="selected" ';
break;
case '0':
$sallcategories = ' selected="selected" ';
break;
case '-1':
$snocategorised = ' selected="selected" ';
break;
}
?>
<option value="ALL" <?php p($sall)?>><?php p(get_string("allentries","glossary"))?></option>
<option value="SPECIAL" <?php p($sspecial)?>><?php p(get_string("special","glossary"))?></option>
<option value="0" <?php p($sallcategories)?>><?php p(get_string("allcategories","glossary"))?></option>
<option value="-1" <?php p($snocategorised)?>><?php p(get_string("notcategorised","glossary"))?></option>
</select>
</td>
<td width="60%">
<?php print_string("cnfdefaulthook", "glossary") ?><br /><br />
</td>
</tr>
<tr valign="top">
<td align="right" width="20%"><label for="sortkey"><?php print_string('defaultsortkey','glossary'); ?></label></td>
<td>
<select size="1" id="sortkey" name="sortkey">
<?php
$sfname = '';
$slname = '';
$supdate = '';
$screation = '';
switch ( strtolower($displayformat->sortkey) ) {
case 'firstname':
$sfname = ' selected="selected" ';
break;
case 'lastname':
$slname = ' selected="selected" ';
break;
case 'creation':
$screation = ' selected="selected" ';
break;
case 'update':
$supdate = ' selected="selected" ';
break;
}
?>
<option value="CREATION" <?php p($screation)?>><?php p(get_string("sortbycreation","glossary"))?></option>
<option value="UPDATE" <?php p($supdate)?>><?php p(get_string("sortbylastupdate","glossary"))?></option>
<option value="FIRSTNAME" <?php p($sfname)?>><?php p(get_string("firstname"))?></option>
<option value="LASTNAME" <?php p($slname)?>><?php p(get_string("lastname"))?></option>
</select>
</td>
<td width="60%">
<?php print_string("cnfsortkey", "glossary") ?><br /><br />
</td>
</tr>
<tr valign="top">
<td align="right" width="20%"><label for="sortorder"><?php print_string('defaultsortorder','glossary'); ?></label></td>
<td>
<select size="1" id="sortorder" name="sortorder">
<?php
$sasc = '';
$sdesc = '';
switch ( strtolower($displayformat->sortorder) ) {
case 'asc':
$sasc = ' selected="selected" ';
break;
case 'desc':
$sdesc = ' selected="selected" ';
break;
}
?>
<option value="asc" <?php p($sasc)?>><?php p(get_string("ascending","glossary"))?></option>
<option value="desc" <?php p($sdesc)?>><?php p(get_string("descending","glossary"))?></option>
</select>
</td>
<td width="60%">
<?php print_string("cnfsortorder", "glossary") ?><br /><br />
</td>
</tr>
<tr valign="top">
<td align="right" width="20%"><label for="showgroup"><?php print_string("includegroupbreaks", "glossary"); ?>:</label></td>
<td>
<select size="1" id="showgroup" name="showgroup">
<?php
$yselected = "";
$nselected = "";
if ($displayformat->showgroup) {
$yselected = " selected=\"selected\" ";
} else {
$nselected = " selected=\"selected\" ";
}
?>
<option value="1" <?php echo $yselected ?>><?php p($yes)?></option>
<option value="0" <?php echo $nselected ?>><?php p($no)?></option>
</select>
</td>
<td width="60%">
<?php print_string("cnfshowgroup", "glossary") ?><br /><br />
</td>
</tr>
<tr>
<td align="right" width="20%"><label for="visibletabs"><?php print_string("visibletabs", "glossary"); ?></label></td>
<td>
<?php
// Get all glossary tabs.
$glossarytabs = glossary_get_all_tabs();
// Extract showtabs value in an array.
$visibletabs = glossary_get_visible_tabs($displayformat);
$size = min(10, count($glossarytabs));
?>
<select id="visibletabs" name="visibletabs[]" size="<?php echo $size ?>" multiple="multiple">
<?php
$selected = "";
foreach ($glossarytabs as $tabkey => $tabvalue) {
if (in_array($tabkey, $visibletabs)) {
?>
<option value="<?php echo $tabkey ?>" selected="selected"><?php echo $tabvalue ?></option>
<?php
} else {
?>
<option value="<?php echo $tabkey ?>"><?php echo $tabvalue ?></option>
<?php
}
}
?>
</select>
</td>
<td width="60%">
<?php print_string("cnftabs", "glossary") ?><br/><br/>
</td>
</tr>
<tr>
<td colspan="3" align="center">
<input type="submit" value="<?php print_string("savechanges") ?>" /></td>
</tr>
<input type="hidden" name="id" value="<?php p($id) ?>" />
<input type="hidden" name="sesskey" value="<?php echo sesskey() ?>" />
<input type="hidden" name="mode" value="edit" />
<?php
echo '</table></form>';
echo $OUTPUT->footer();
?>
+40
View File
@@ -0,0 +1,40 @@
GLOSSARY FORMAT PLUGINS
-----------------------
Starting with Moodle 1.4, the glossary module supports a plugin
architecture to create your own formats. This plugin system allows
you to "invent" your own presentations for your glossary data. :-)
To facilitate the creation process a TEMPLATE format has been created.
You should use it as the base for your own modifications (this requires
some basic PHP skills). The template includes all the available data.
Please, follow these STEPS:
1.-Think of an English word (or short phrase) to define your format.
For further reference in this document, we call it "THENAME".
2.-Duplicate the TEMPLATE directory (under mod/glossary/formats/TEMPLATE).
3.-Rename it to THENAME
4.-Go into the THENAME directory and rename the TEMPLATE_format.php file
to THENAME_format.php
5.-Edit the THENAME_format.php file. Change every ocurrence of TEMPLATE to
THENAME.
6.-Login into Moodle. Go to any glossary in your site.
7.-Edit (configure) your glossary. In the Format popup you'll see a new
entry. It will be showed as "displayformatTHENAME". Select it and view
your glossary.
8.-Edit the THENAME_format.php. Make your format modifications and reload your
web page to see them in your glossary. This file has been commented to make
things easier to understand (further suggestions welcome!)
9.-If you want to translate your THENAME format name to some nice name to
be showed in the Format popup, simply, edit your lang/XX/glossary.php
file (where XX is your language) and create a new displayformatTHENAME
string.
10.-Enjoy!! (and don't forget to send your amazing glossary formats to
the Glossary forum on http://moodle.org. They will be welcome!! ;-)
To talk about Glossary formats, go to:
http://moodle.org/mod/forum/view.php?id=742
Eloy (stronk7)
08/02/2004 (MM/DD/YYYY) :-D
@@ -0,0 +1,109 @@
<?php
function glossary_show_entry_TEMPLATE($course, $cm, $glossary, $entry, $mode='', $hook='', $printicons=1, $aliases=true) {
global $CFG, $USER, $DB, $OUTPUT;
$user = $DB->get_record('user', array('id'=>$entry->userid));
$strby = get_string('writtenby', 'glossary');
if ($entry) {
echo '<table class="glossarypost TEMPLATE">';
echo '<tr>';
echo '<td class="entryheader">';
//Use this function to show author's image
//Comments: Configuration not supported
echo $OUTPUT->user_picture($user, array('courseid'=>$course->id));
//Line separator to show this template fine. :-)
echo '<br />';
//Use this code to show author's name
//Comments: Configuration not supported
$fullname = fullname($user);
$by = new stdClass();
$by->name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.$course->id.'">'.$fullname.'</a>';
$by->date = userdate($entry->timemodified);
echo '<span class="author">'.get_string('bynameondate', 'forum', $by).'</span>' . '<br />';
//Use this code to show modification date
//Comments: Configuration not supported
echo get_string('lastedited').': '. userdate($entry->timemodified) . '<br /></span>';
//Use this function to show the approval button. It'll be shown if necessary
//Comments: You can configure this parameters:
//----Define where to show the approval button
$approvalalign = 'right'; //Values: left, center and right (default right)
//----Define if the approval button must be showed into a 100% width table
$approvalinsidetable = true; //Values: true, false (default true)
//Call the function
glossary_print_entry_approval($cm, $entry, $mode, $approvalalign, $approvalinsidetable);
//Line separator to show this template fine. :-)
echo '<br />';
echo '</td>';
echo '<td class="entryattachment">';
//Line separator to show this template fine. :-)
echo "<br />\n";
echo '</td></tr>';
echo '<tr valign="top">';
echo '<td class="entry">';
//Use this function to print the concept in a heading <h3>
//Comments: Configuration not supported
glossary_print_entry_concept($entry);
//Line separator not normally needed now.
//echo "<br />\n";
//Use this function to show the definition
//Comments: Configuration not supported
glossary_print_entry_definition($entry, $glossary, $cm);
// Use this function to show the attachment. It'll be shown if necessary.
glossary_print_entry_attachment($entry, $cm, 'html');
//Line separator to show this template fine. :-)
echo "<br />\n";
//Use this function to show aliases, editing icons and ratings (all know as the 'lower section')
//Comments: You can configure this parameters:
//----Define when to show the aliases popup
// use it only if you are really sure!
//$aliases = true; //Values: true, false (Default: true)
//----Uncoment this line to avoid editing icons being showed
// use it only if you are really sure!
//$printicons = false;
glossary_print_entry_lower_section($course, $cm, $glossary, $entry, $mode, $hook, $printicons, $aliases);
echo '</td>';
echo '</tr>';
echo "</table>\n";
} else {
echo '<div style="text-align:center">';
print_string('noentry', 'glossary');
echo '</div>';
}
}
function glossary_print_entry_TEMPLATE($course, $cm, $glossary, $entry, $mode='', $hook='', $printicons=1) {
//The print view for this format is exactly the normal view, so we use it
//Anyway, you can modify this to use your own print format!!
//Take out autolinking in definitions in print view
$entry->definition = '<span class="nolink">'.$entry->definition.'</span>';
//Call to view function (without icons, ratings and aliases) and return its result
return glossary_show_entry_TEMPLATE($course, $cm, $glossary, $entry, $mode, $hook, false, false, false);
}
@@ -0,0 +1,43 @@
<?php
function glossary_show_entry_continuous($course, $cm, $glossary, $entry, $mode='', $hook='', $printicons=1, $aliases=false) {
global $USER, $OUTPUT;
echo '<table class="glossarypost continuous" cellspacing="0">';
echo '<tr valign="top">';
echo '<td class="entry">';
glossary_print_entry_approval($cm, $entry, $mode);
echo '<div class="concept">';
glossary_print_entry_concept($entry);
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>';
echo '<tr valign="top"><td class="entrylowersection">';
glossary_print_entry_lower_section($course, $cm, $glossary, $entry, $mode, $hook, $printicons, $aliases, false);
echo '</td>';
echo '</tr>';
echo "</table>\n";
}
function glossary_print_entry_continuous($course, $cm, $glossary, $entry, $mode='', $hook='', $printicons=1) {
//The print view for this format is exactly the normal view, so we use it
//Take out autolinking in definitions un print view
$entry->definition = '<span class="nolink">'.$entry->definition.'</span>';
//Call to view function (without icons, ratings and aliases) and return its result
glossary_show_entry_continuous($course, $cm, $glossary, $entry, $mode, $hook, false, false, false);
}
@@ -0,0 +1,38 @@
<?php
function glossary_show_entry_dictionary($course, $cm, $glossary, $entry, $mode='', $hook='', $printicons=1, $aliases=true) {
global $CFG, $USER, $OUTPUT;
echo '<table class="glossarypost dictionary" cellspacing="0">';
echo '<tr valign="top">';
echo '<td class="entry">';
glossary_print_entry_approval($cm, $entry, $mode);
echo '<div class="concept">';
glossary_print_entry_concept($entry);
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);
echo '</td>';
echo '</tr>';
echo "</table>\n";
}
function glossary_print_entry_dictionary($course, $cm, $glossary, $entry, $mode='', $hook='', $printicons=1) {
//The print view for this format is exactly the normal view, so we use it
//Take out autolinking in definitions in print view
$entry->definition = '<span class="nolink">'.$entry->definition.'</span>';
//Call to view function (without icons, ratings and aliases) and return its result
return glossary_show_entry_dictionary($course, $cm, $glossary, $entry, $mode, $hook, false, false, false);
}
@@ -0,0 +1,79 @@
<?php
function glossary_show_entry_encyclopedia($course, $cm, $glossary, $entry, $mode='',$hook='',$printicons=1, $aliases=true) {
global $CFG, $USER, $DB, $OUTPUT;
$user = $DB->get_record('user', array('id'=>$entry->userid));
$strby = get_string('writtenby', 'glossary');
if ($entry) {
echo '<table class="glossarypost encyclopedia" cellspacing="0">';
echo '<tr valign="top">';
echo '<td class="left picture">';
echo $OUTPUT->user_picture($user, array('courseid'=>$course->id));
echo '</td>';
echo '<th class="entryheader">';
echo '<div class="concept">';
glossary_print_entry_concept($entry);
echo '</div>';
$fullname = fullname($user);
$by = new stdClass();
$by->name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.$course->id.'">'.$fullname.'</a>';
$by->date = userdate($entry->timemodified);
echo '<span class="author">'.get_string('bynameondate', 'forum', $by).'</span>';
echo '</th>';
echo '<td class="entryapproval">';
glossary_print_entry_approval($cm, $entry, $mode);
echo '</td>';
echo '</tr>';
echo '<tr valign="top">';
echo '<td class="left side" rowspan="2">&nbsp;</td>';
echo '<td colspan="2" class="entry">';
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>';
echo '<tr>';
echo '<td colspan="2" class="entrylowersection">';
glossary_print_entry_lower_section($course, $cm, $glossary, $entry,$mode,$hook,$printicons,$aliases);
echo ' ';
}
echo '</td></tr>';
echo "</table>\n";
} else {
echo '<div style="text-align:center">';
print_string('noentry', 'glossary');
echo '</div>';
}
}
function glossary_print_entry_encyclopedia($course, $cm, $glossary, $entry, $mode='', $hook='', $printicons=1) {
//The print view for this format is exactly the normal view, so we use it
//Take out autolinking in definitions un print view
$entry->definition = '<span class="nolink">'.$entry->definition.'</span>';
//Call to view function (without icons, ratings and aliases) and return its result
return glossary_show_entry_encyclopedia($course, $cm, $glossary, $entry, $mode, $hook, false, false);
}
@@ -0,0 +1,67 @@
<?php
function glossary_show_entry_entrylist($course, $cm, $glossary, $entry, $mode='', $hook='', $printicons=1, $aliases=true) {
global $USER, $OUTPUT;
$return = false;
echo '<table class="glossarypost entrylist" cellspacing="0">';
echo '<tr valign="top">';
echo '<td class="entry">';
if ($entry) {
glossary_print_entry_approval($cm, $entry, $mode);
$anchortagcontents = glossary_print_entry_concept($entry, true);
$link = new moodle_url('/mod/glossary/showentry.php', array('courseid' => $course->id,
'eid' => $entry->id, 'displayformat' => 'dictionary'));
$anchor = html_writer::link($link, $anchortagcontents);
echo "<div class=\"concept\">$anchor</div> ";
echo '</td><td align="right" class="entrylowersection">';
if ($printicons) {
glossary_print_entry_icons($course, $cm, $glossary, $entry, $mode, $hook,'print');
}
if (!empty($entry->rating)) {
echo '<br />';
echo '<span class="ratings d-block pt-3">';
$return = glossary_print_entry_ratings($course, $entry);
echo '</span>';
}
echo '<br />';
} else {
echo '<div style="text-align:center">';
print_string('noentry', 'glossary');
echo '</div>';
}
echo '</td></tr>';
echo "</table>";
echo "<hr>\n";
return $return;
}
function glossary_print_entry_entrylist($course, $cm, $glossary, $entry, $mode='', $hook='', $printicons=1) {
//Take out autolinking in definitions un print view
// TODO use <nolink> tags MDL-15555.
$entry->definition = '<span class="nolink">'.$entry->definition.'</span>';
echo html_writer::start_tag('table', array('class' => 'glossarypost entrylist mod-glossary-entrylist'));
echo html_writer::start_tag('tr');
echo html_writer::start_tag('td', array('class' => 'entry mod-glossary-entry'));
echo html_writer::start_tag('div', array('class' => 'mod-glossary-concept'));
glossary_print_entry_concept($entry);
echo html_writer::end_tag('div');
echo html_writer::start_tag('div', array('class' => 'mod-glossary-definition'));
glossary_print_entry_definition($entry, $glossary, $cm);
echo html_writer::end_tag('div');
echo html_writer::start_tag('div', array('class' => 'mod-glossary-lower-section'));
glossary_print_entry_lower_section($course, $cm, $glossary, $entry, $mode, $hook, false, false);
echo html_writer::end_tag('div');
echo html_writer::end_tag('td');
echo html_writer::end_tag('tr');
echo html_writer::end_tag('table');
}
+63
View File
@@ -0,0 +1,63 @@
<?php
function glossary_show_entry_faq($course, $cm, $glossary, $entry, $mode="", $hook="", $printicons=1, $aliases=true) {
global $USER, $OUTPUT;
if ( $entry ) {
echo '<table class="glossarypost faq" cellspacing="0">';
echo '<tr valign="top">';
echo '<th class="entryheader">';
$entry->course = $course->id;
echo '<div class="concept">' . get_string('question','glossary') . ': ';
glossary_print_entry_concept($entry);
echo '</div>';
echo '<span class="time">('.get_string('lastedited').': '.
userdate($entry->timemodified).')</span>';
echo '</th>';
echo '<td class="entryattachment">';
glossary_print_entry_approval($cm, $entry, $mode);
echo '</td>';
echo '</tr>';
echo "\n<tr>";
echo '<td colspan="2" class="entry">';
echo '<b>'.get_string('answer','glossary').':</b> ';
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);
echo '</td></tr></table>';
} else {
echo '<div style="text-align:center">';
print_string('noentry', 'glossary');
echo '</div>';
}
}
function glossary_print_entry_faq($course, $cm, $glossary, $entry, $mode='', $hook='', $printicons=1) {
//The print view for this format is exactly the normal view, so we use it
//Take out autolinking in definitions un print view
$entry->definition = '<span class="nolink">'.$entry->definition.'</span>';
//Call to view function (without icons, ratings and aliases) and return its result
return glossary_show_entry_faq($course, $cm, $glossary, $entry, $mode, $hook, false, false, false);
}
@@ -0,0 +1,78 @@
<?php
function glossary_show_entry_fullwithauthor($course, $cm, $glossary, $entry, $mode="", $hook="", $printicons=1, $aliases=true) {
global $CFG, $USER, $DB, $OUTPUT;
$user = $DB->get_record('user', array('id'=>$entry->userid));
$strby = get_string('writtenby', 'glossary');
if ($entry) {
echo '<table class="glossarypost fullwithauthor" cellspacing="0">';
echo '<tr valign="top">';
echo '<td class="picture">';
echo $OUTPUT->user_picture($user, array('courseid'=>$course->id));
echo '</td>';
echo '<th class="entryheader">';
echo '<div class="concept">';
glossary_print_entry_concept($entry);
echo '</div>';
$fullname = fullname($user);
$by = new stdClass();
$by->name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.$course->id.'">'.$fullname.'</a>';
$by->date = userdate($entry->timemodified);
echo '<span class="author">'.get_string('bynameondate', 'forum', $by).'</span>';
echo '</th>';
echo '<td class="entryattachment">';
glossary_print_entry_approval($cm, $entry, $mode);
echo '</td>';
echo '</tr>';
echo '<tr valign="top">';
echo '<td class="left">&nbsp;</td>';
echo '<td colspan="2" class="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">';
echo '<td class="left">&nbsp;</td>';
echo '<td colspan="2" class="entrylowersection">';
glossary_print_entry_lower_section($course, $cm, $glossary, $entry, $mode, $hook, $printicons, $aliases);
echo ' ';
echo '</td></tr>';
echo "</table>\n";
} else {
echo '<div style="text-align:center">';
print_string('noentry', 'glossary');
echo '</div>';
}
}
function glossary_print_entry_fullwithauthor($course, $cm, $glossary, $entry, $mode="", $hook="", $printicons=1) {
//The print view for this format is exactly the normal view, so we use it
//Take out autolinking in definitions un print view
$entry->definition = '<span class="nolink">'.$entry->definition.'</span>';
//Call to view function (without icons, ratings and aliases) and return its result
return glossary_show_entry_fullwithauthor($course, $cm, $glossary, $entry, $mode, $hook, false, false, false);
}
@@ -0,0 +1,64 @@
<?php
function glossary_show_entry_fullwithoutauthor($course, $cm, $glossary, $entry, $mode="", $hook="", $printicons=1, $aliases=true) {
global $CFG, $USER, $OUTPUT;
if ($entry) {
echo '<table class="glossarypost fullwithoutauthor" cellspacing="0">';
echo '<tr valign="top">';
echo '<th class="entryheader">';
echo '<div class="concept">';
glossary_print_entry_concept($entry);
echo '</div>';
echo '<span class="time">('.get_string('lastedited').': '.
userdate($entry->timemodified).')</span>';
echo '</th>';
echo '<td class="entryattachment">';
glossary_print_entry_approval($cm, $entry, $mode);
echo '</td>';
echo '</tr>';
echo '<tr valign="top">';
echo '<td width="100%" colspan="2" class="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);
echo ' ';
echo '</td></tr>';
echo "</table>\n";
} else {
echo '<center>';
print_string('noentry', 'glossary');
echo '</center>';
}
}
function glossary_print_entry_fullwithoutauthor($course, $cm, $glossary, $entry, $mode="", $hook="", $printicons=1) {
//The print view for this format is exactly the normal view, so we use it
//Take out autolinking in definitions un print view
$entry->definition = '<span class="nolink">'.$entry->definition.'</span>';
//Call to view function (without icons, ratings and aliases) and return its result
return glossary_show_entry_fullwithoutauthor($course, $cm, $glossary, $entry, $mode, $hook, false, false, false);
}
+381
View File
@@ -0,0 +1,381 @@
<?php
require_once("../../config.php");
require_once("lib.php");
require_once("$CFG->dirroot/course/lib.php");
require_once("$CFG->dirroot/course/modlib.php");
require_once('import_form.php');
$id = required_param('id', PARAM_INT); // Course Module ID
$mode = optional_param('mode', 'letter', PARAM_ALPHA );
$hook = optional_param('hook', 'ALL', PARAM_ALPHANUM);
$url = new moodle_url('/mod/glossary/import.php', array('id'=>$id));
if ($mode !== 'letter') {
$url->param('mode', $mode);
}
if ($hook !== 'ALL') {
$url->param('hook', $hook);
}
$PAGE->set_url($url);
if (! $cm = get_coursemodule_from_id('glossary', $id)) {
throw new \moodle_exception('invalidcoursemodule');
}
if (! $course = $DB->get_record("course", array("id"=>$cm->course))) {
throw new \moodle_exception('coursemisconf');
}
if (! $glossary = $DB->get_record("glossary", array("id"=>$cm->instance))) {
throw new \moodle_exception('invalidid', 'glossary');
}
require_login($course, false, $cm);
$context = context_module::instance($cm->id);
require_capability('mod/glossary:import', $context);
$strglossaries = get_string("modulenameplural", "glossary");
$strglossary = get_string("modulename", "glossary");
$strallcategories = get_string("allcategories", "glossary");
$straddentry = get_string("addentry", "glossary");
$strnoentries = get_string("noentries", "glossary");
$strsearchindefinition = get_string("searchindefinition", "glossary");
$strsearch = get_string("search");
$strimportentries = get_string('importentriesfromxml', 'glossary');
$PAGE->navbar->add($strimportentries);
$PAGE->set_title($glossary->name);
$PAGE->set_heading($course->fullname);
$PAGE->set_secondary_active_tab('modulepage');
$PAGE->activityheader->disable();
$form = new mod_glossary_import_form('');
if ($form->is_cancelled()) {
redirect(new moodle_url('view.php', ['id' => $id]));
}
echo $OUTPUT->header();
echo $OUTPUT->heading($strimportentries);
if ( !$data = $form->get_data() ) {
echo $OUTPUT->box_start('glossarydisplay generalbox');
// display upload form
$data = new stdClass();
$data->id = $id;
$form->set_data($data);
$form->display();
echo $OUTPUT->box_end();
echo $OUTPUT->footer();
exit;
}
$result = $form->get_file_content('file');
if (empty($result)) {
echo $OUTPUT->box_start('glossarydisplay generalbox');
echo $OUTPUT->continue_button('import.php?id='.$id);
echo $OUTPUT->box_end();
echo $OUTPUT->footer();
die();
}
// Large exports are likely to take their time and memory.
core_php_time_limit::raise();
raise_memory_limit(MEMORY_EXTRA);
if ($xml = glossary_read_imported_file($result)) {
$importedentries = 0;
$importedcats = 0;
$entriesrejected = 0;
$rejections = '';
$glossarycontext = $context;
if ($data->dest == 'newglossary') {
// If the user chose to create a new glossary
$xmlglossary = $xml['GLOSSARY']['#']['INFO'][0]['#'];
if ( $xmlglossary['NAME'][0]['#'] ) {
$glossary = new stdClass();
$glossary->modulename = 'glossary';
$glossary->module = $cm->module;
$glossary->name = ($xmlglossary['NAME'][0]['#']);
$glossary->globalglossary = ($xmlglossary['GLOBALGLOSSARY'][0]['#']);
$glossary->intro = ($xmlglossary['INTRO'][0]['#']);
$glossary->introformat = isset($xmlglossary['INTROFORMAT'][0]['#']) ? $xmlglossary['INTROFORMAT'][0]['#'] : FORMAT_MOODLE;
$glossary->showspecial = ($xmlglossary['SHOWSPECIAL'][0]['#']);
$glossary->showalphabet = ($xmlglossary['SHOWALPHABET'][0]['#']);
$glossary->showall = ($xmlglossary['SHOWALL'][0]['#']);
$glossary->cmidnumber = null;
// Setting the default values if no values were passed
if ( isset($xmlglossary['ENTBYPAGE'][0]['#']) ) {
$glossary->entbypage = ($xmlglossary['ENTBYPAGE'][0]['#']);
} else {
$glossary->entbypage = $CFG->glossary_entbypage;
}
if ( isset($xmlglossary['ALLOWDUPLICATEDENTRIES'][0]['#']) ) {
$glossary->allowduplicatedentries = ($xmlglossary['ALLOWDUPLICATEDENTRIES'][0]['#']);
} else {
$glossary->allowduplicatedentries = $CFG->glossary_dupentries;
}
if ( isset($xmlglossary['DISPLAYFORMAT'][0]['#']) ) {
$glossary->displayformat = ($xmlglossary['DISPLAYFORMAT'][0]['#']);
} else {
$glossary->displayformat = 2;
}
if ( isset($xmlglossary['ALLOWCOMMENTS'][0]['#']) ) {
$glossary->allowcomments = ($xmlglossary['ALLOWCOMMENTS'][0]['#']);
} else {
$glossary->allowcomments = $CFG->glossary_allowcomments;
}
if ( isset($xmlglossary['USEDYNALINK'][0]['#']) ) {
$glossary->usedynalink = ($xmlglossary['USEDYNALINK'][0]['#']);
} else {
$glossary->usedynalink = $CFG->glossary_linkentries;
}
if ( isset($xmlglossary['DEFAULTAPPROVAL'][0]['#']) ) {
$glossary->defaultapproval = ($xmlglossary['DEFAULTAPPROVAL'][0]['#']);
} else {
$glossary->defaultapproval = $CFG->glossary_defaultapproval;
}
// These fields were not included in export, assume zero.
$glossary->assessed = 0;
$glossary->availability = null;
// Check if we're creating the new glossary on the front page or inside a course.
if ($cm->course == SITEID) {
// On the front page, activities are in section 1.
$glossary->section = 1;
} else {
// Inside a course, add to the general section (0).
$glossary->section = 0;
}
// New glossary is always visible.
$glossary->visible = 1;
$glossary->visibleoncoursepage = 1;
// Include new glossary and return the new ID
if ( !($glossary = add_moduleinfo($glossary, $course)) ) {
echo $OUTPUT->notification("Error while trying to create the new glossary.");
glossary_print_tabbed_table_end();
echo $OUTPUT->footer();
exit;
} else {
$glossarycontext = context_module::instance($glossary->coursemodule);
glossary_xml_import_files($xmlglossary, 'INTROFILES', $glossarycontext->id, 'intro', 0);
echo $OUTPUT->box(get_string("newglossarycreated","glossary"),'generalbox boxaligncenter boxwidthnormal');
}
} else {
echo $OUTPUT->notification("Error while trying to create the new glossary.");
echo $OUTPUT->footer();
exit;
}
}
$xmlentries = $xml['GLOSSARY']['#']['INFO'][0]['#']['ENTRIES'][0]['#']['ENTRY'];
$sizeofxmlentries = is_array($xmlentries) ? count($xmlentries) : 0;
for($i = 0; $i < $sizeofxmlentries; $i++) {
// Inserting the entries
$xmlentry = $xmlentries[$i];
$newentry = new stdClass();
$newentry->concept = trim($xmlentry['#']['CONCEPT'][0]['#']);
$definition = $xmlentry['#']['DEFINITION'][0]['#'];
if (!is_string($definition)) {
throw new \moodle_exception('errorparsingxml', 'glossary');
}
$newentry->definition = trusttext_strip($definition);
if ( isset($xmlentry['#']['CASESENSITIVE'][0]['#']) ) {
$newentry->casesensitive = $xmlentry['#']['CASESENSITIVE'][0]['#'];
} else {
$newentry->casesensitive = $CFG->glossary_casesensitive;
}
$permissiongranted = 1;
if ( $newentry->concept and $newentry->definition ) {
if ( !$glossary->allowduplicatedentries ) {
// checking if the entry is valid (checking if it is duplicated when should not be)
if ( $newentry->casesensitive ) {
$dupentry = $DB->record_exists_select('glossary_entries',
'glossaryid = :glossaryid AND concept = :concept', array(
'glossaryid' => $glossary->id,
'concept' => $newentry->concept));
} else {
$dupentry = $DB->record_exists_select('glossary_entries',
'glossaryid = :glossaryid AND LOWER(concept) = :concept', array(
'glossaryid' => $glossary->id,
'concept' => core_text::strtolower($newentry->concept)));
}
if ($dupentry) {
$permissiongranted = 0;
}
}
} else {
$permissiongranted = 0;
}
if ($permissiongranted) {
$newentry->glossaryid = $glossary->id;
$newentry->sourceglossaryid = 0;
$newentry->approved = 1;
$newentry->userid = $USER->id;
$newentry->teacherentry = 1;
$newentry->definitionformat = $xmlentry['#']['FORMAT'][0]['#'];
$newentry->timecreated = time();
$newentry->timemodified = time();
// Setting the default values if no values were passed
if ( isset($xmlentry['#']['USEDYNALINK'][0]['#']) ) {
$newentry->usedynalink = $xmlentry['#']['USEDYNALINK'][0]['#'];
} else {
$newentry->usedynalink = $CFG->glossary_linkentries;
}
if ( isset($xmlentry['#']['FULLMATCH'][0]['#']) ) {
$newentry->fullmatch = $xmlentry['#']['FULLMATCH'][0]['#'];
} else {
$newentry->fullmatch = $CFG->glossary_fullmatch;
}
$newentry->id = $DB->insert_record("glossary_entries",$newentry);
$importedentries++;
$xmlaliases = @$xmlentry['#']['ALIASES'][0]['#']['ALIAS']; // ignore missing ALIASES
$sizeofxmlaliases = is_array($xmlaliases) ? count($xmlaliases) : 0;
for($k = 0; $k < $sizeofxmlaliases; $k++) {
/// Importing aliases
$xmlalias = $xmlaliases[$k];
$aliasname = $xmlalias['#']['NAME'][0]['#'];
if (!empty($aliasname)) {
$newalias = new stdClass();
$newalias->entryid = $newentry->id;
$newalias->alias = trim($aliasname);
$newalias->id = $DB->insert_record("glossary_alias",$newalias);
}
}
if (!empty($data->catsincl)) {
// If the categories must be imported...
$xmlcats = @$xmlentry['#']['CATEGORIES'][0]['#']['CATEGORY']; // ignore missing CATEGORIES
$sizeofxmlcats = is_array($xmlcats) ? count($xmlcats) : 0;
for($k = 0; $k < $sizeofxmlcats; $k++) {
$xmlcat = $xmlcats[$k];
$newcat = new stdClass();
$newcat->name = $xmlcat['#']['NAME'][0]['#'];
$newcat->usedynalink = $xmlcat['#']['USEDYNALINK'][0]['#'];
if ( !$category = $DB->get_record("glossary_categories", array("glossaryid"=>$glossary->id,"name"=>$newcat->name))) {
// Create the category if it does not exist
$category = new stdClass();
$category->name = $newcat->name;
$category->glossaryid = $glossary->id;
$category->id = $DB->insert_record("glossary_categories",$category);
$importedcats++;
}
if ( $category ) {
// inserting the new relation
$entrycat = new stdClass();
$entrycat->entryid = $newentry->id;
$entrycat->categoryid = $category->id;
$DB->insert_record("glossary_entries_categories",$entrycat);
}
}
}
// Import files embedded in the entry text.
glossary_xml_import_files($xmlentry['#'], 'ENTRYFILES', $glossarycontext->id, 'entry', $newentry->id);
// Import files attached to the entry.
if (glossary_xml_import_files($xmlentry['#'], 'ATTACHMENTFILES', $glossarycontext->id, 'attachment', $newentry->id)) {
$DB->update_record("glossary_entries", array('id' => $newentry->id, 'attachment' => '1'));
}
// Import tags associated with the entry.
if (core_tag_tag::is_enabled('mod_glossary', 'glossary_entries')) {
$xmltags = @$xmlentry['#']['TAGS'][0]['#']['TAG']; // Ignore missing TAGS.
$sizeofxmltags = is_array($xmltags) ? count($xmltags) : 0;
for ($k = 0; $k < $sizeofxmltags; $k++) {
// Importing tags.
$tag = $xmltags[$k]['#'];
if (!empty($tag)) {
core_tag_tag::add_item_tag('mod_glossary', 'glossary_entries', $newentry->id, $glossarycontext, $tag);
}
}
}
} else {
$entriesrejected++;
if ( $newentry->concept and $newentry->definition ) {
// add to exception report (duplicated entry))
$rejections .= "<tr><td>$newentry->concept</td>" .
"<td>" . get_string("duplicateentry","glossary"). "</td></tr>";
} else {
// add to exception report (no concept or definition found))
$rejections .= "<tr><td>---</td>" .
"<td>" . get_string("noconceptfound","glossary"). "</td></tr>";
}
}
}
// Reset caches.
\mod_glossary\local\concept_cache::reset_glossary($glossary);
// processed entries
echo $OUTPUT->box_start('glossarydisplay generalbox');
echo '<table class="glossaryimportexport">';
echo '<tr>';
echo '<td width="50%" align="right">';
echo get_string("totalentries","glossary");
echo ':</td>';
echo '<td width="50%" align="left">';
echo $importedentries + $entriesrejected;
echo '</td>';
echo '</tr>';
echo '<tr>';
echo '<td width="50%" align="right">';
echo get_string("importedentries","glossary");
echo ':</td>';
echo '<td width="50%" align="left">';
echo $importedentries;
if ( $entriesrejected ) {
echo ' <small>(' . get_string("rejectedentries","glossary") . ": $entriesrejected)</small>";
}
echo '</td>';
echo '</tr>';
if (!empty($data->catsincl)) {
echo '<tr>';
echo '<td width="50%" align="right">';
echo get_string("importedcategories","glossary");
echo ':</td>';
echo '<td width="50%">';
echo $importedcats;
echo '</td>';
echo '</tr>';
}
echo '</table><hr />';
// rejected entries
if ($rejections) {
echo $OUTPUT->heading(get_string("rejectionrpt","glossary"), 4);
echo '<table class="glossaryimportexport">';
echo $rejections;
echo '</table><hr />';
}
/// Print continue button, based on results
if ($importedentries) {
echo $OUTPUT->continue_button('view.php?id='.$id);
} else {
echo $OUTPUT->continue_button('import.php?id='.$id);
}
echo $OUTPUT->box_end();
} else {
echo $OUTPUT->box_start('glossarydisplay generalbox');
echo get_string('errorparsingxml', 'glossary');
echo $OUTPUT->continue_button('import.php?id='.$id);
echo $OUTPUT->box_end();
}
/// Finish the page
echo $OUTPUT->footer();
+28
View File
@@ -0,0 +1,28 @@
<?php
if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
}
require_once($CFG->libdir.'/formslib.php');
class mod_glossary_import_form extends moodleform {
function definition() {
global $CFG;
$mform =& $this->_form;
$cmid = $this->_customdata['id'] ?? null;
$mform->addElement('filepicker', 'file', get_string('filetoimport', 'glossary'));
$mform->addHelpButton('file', 'filetoimport', 'glossary');
$options = array();
$options['current'] = get_string('currentglossary', 'glossary');
$options['newglossary'] = get_string('newglossary', 'glossary');
$mform->addElement('select', 'dest', get_string('destination', 'glossary'), $options);
$mform->addHelpButton('dest', 'destination', 'glossary');
$mform->addElement('checkbox', 'catsincl', get_string('importcategories', 'glossary'));
$submit_string = get_string('submit');
$mform->addElement('hidden', 'id');
$mform->setType('id', PARAM_INT);
$this->add_action_buttons(true, $submit_string);
}
}
+142
View File
@@ -0,0 +1,142 @@
<?php
/// This page lists all the instances of glossary in a particular course
/// Replace glossary with the name of your module
require_once("../../config.php");
require_once("lib.php");
require_once("$CFG->libdir/rsslib.php");
require_once("$CFG->dirroot/course/lib.php");
$id = required_param('id', PARAM_INT); // course
$PAGE->set_url('/mod/glossary/index.php', array('id'=>$id));
if (!$course = $DB->get_record('course', array('id'=>$id))) {
throw new \moodle_exception('invalidcourseid');
}
require_course_login($course);
$PAGE->set_pagelayout('incourse');
$context = context_course::instance($course->id);
$event = \mod_glossary\event\course_module_instance_list_viewed::create(array(
'context' => $context
));
$event->add_record_snapshot('course', $course);
$event->trigger();
/// Get all required strings
$strglossarys = get_string("modulenameplural", "glossary");
$strglossary = get_string("modulename", "glossary");
$strrss = get_string("rss");
/// Print the header
$PAGE->navbar->add($strglossarys, "index.php?id=$course->id");
$PAGE->set_title($strglossarys);
$PAGE->set_heading($course->fullname);
echo $OUTPUT->header();
echo $OUTPUT->heading(format_string($strglossarys), 2);
/// Get all the appropriate data
if (! $glossarys = get_all_instances_in_course("glossary", $course)) {
notice(get_string('thereareno', 'moodle', $strglossarys), "../../course/view.php?id=$course->id");
die;
}
$usesections = course_format_uses_sections($course->format);
/// Print the list of instances (your module will probably extend this)
$timenow = time();
$strname = get_string("name");
$strentries = get_string("entries", "glossary");
$table = new html_table();
if ($usesections) {
$strsectionname = get_string('sectionname', 'format_'.$course->format);
$table->head = array ($strsectionname, $strname, $strentries);
$table->align = array ('center', 'left', 'center');
} else {
$table->head = array ($strname, $strentries);
$table->align = array ('left', 'center');
}
if ($show_rss = (isset($CFG->enablerssfeeds) && isset($CFG->glossary_enablerssfeeds) &&
$CFG->enablerssfeeds && $CFG->glossary_enablerssfeeds)) {
$table->head[] = $strrss;
$table->align[] = 'center';
}
$currentsection = "";
foreach ($glossarys as $glossary) {
if (!$glossary->visible && has_capability('moodle/course:viewhiddenactivities',
context_module::instance($glossary->coursemodule))) {
// Show dimmed if the mod is hidden.
$link = "<a class=\"dimmed\" href=\"view.php?id=$glossary->coursemodule\">".format_string($glossary->name,true)."</a>";
} else if ($glossary->visible) {
// Show normal if the mod is visible.
$link = "<a href=\"view.php?id=$glossary->coursemodule\">".format_string($glossary->name,true)."</a>";
} else {
// Don't show the glossary.
continue;
}
$printsection = "";
if ($usesections) {
if ($glossary->section !== $currentsection) {
if ($glossary->section) {
$printsection = get_section_name($course, $glossary->section);
}
if ($currentsection !== "") {
$table->data[] = 'hr';
}
$currentsection = $glossary->section;
}
}
// TODO: count only approved if not allowed to see them
$count = $DB->count_records_sql("SELECT COUNT(*) FROM {glossary_entries} WHERE (glossaryid = ? OR sourceglossaryid = ?)", array($glossary->id, $glossary->id));
//If this glossary has RSS activated, calculate it
if ($show_rss) {
$rsslink = '';
if ($glossary->rsstype and $glossary->rssarticles) {
//Calculate the tolltip text
$tooltiptext = get_string("rsssubscriberss","glossary",format_string($glossary->name));
if (!isloggedin()) {
$userid = 0;
} else {
$userid = $USER->id;
}
//Get html code for RSS link
$rsslink = rss_get_link($context->id, $userid, 'mod_glossary', $glossary->id, $tooltiptext);
}
}
if ($usesections) {
$linedata = array ($printsection, $link, $count);
} else {
$linedata = array ($link, $count);
}
if ($show_rss) {
$linedata[] = $rsslink;
}
$table->data[] = $linedata;
}
echo "<br />";
echo html_writer::table($table);
/// Finish the page
echo $OUTPUT->footer();
+1
View File
@@ -0,0 +1 @@
completionentriesgroup,mod_glossary
+343
View File
@@ -0,0 +1,343 @@
<?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/>.
/**
* Strings for component 'glossary', language 'en', branch 'MOODLE_20_STABLE'
*
* @package mod_glossary
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['addcomment'] = 'Add comment';
$string['addcategory'] = 'Add category';
$string['addentry'] = 'Add a new entry';
$string['addsingleentry'] = 'Add entry';
$string['addingcomment'] = 'Add a comment';
$string['alias'] = 'Keyword';
$string['aliases'] = 'Keyword(s)';
$string['aliases_help'] = 'Each glossary entry can have an associated list of keywords (or aliases). If the entry is auto-linked, then any keywords will also be auto-linked.
Enter each keyword on a new line (not separated by commas).';
$string['allcategories'] = 'All categories';
$string['allentries'] = 'ALL';
$string['allowcomments'] = 'Allow comments on entries';
$string['allowcomments_help'] = 'If enabled, all participants with permission to create comments will be able to add comments to glossary entries.';
$string['allowduplicatedentries'] = 'Duplicate entries allowed';
$string['allowduplicatedentries_help'] = 'If enabled, multiple entries can have the same concept name.';
$string['allowprintview'] = 'Allow print view';
$string['allowprintview_help'] = 'If enabled, students are provided with a link to a printer-friendly version of the glossary. The link is always available to teachers.';
$string['andmorenewentries'] = 'and {$a} more new entries.';
$string['answer'] = 'Answer';
$string['approve'] = 'Approve';
$string['approvaldisplayformat'] = 'Approval display format';
$string['approvaldisplayformat_help'] = 'When approving glossary items you may wish to use a different display format';
$string['areaattachment'] = 'Attachments';
$string['areaentry'] = 'Definitions';
$string['areyousuredelete'] = 'Are you sure you want to delete this entry?';
$string['areyousuredeletecomment'] = 'Are you sure you want to delete this comment?';
$string['areyousureexport'] = 'Are you sure you want to export this entry to';
$string['ascending'] = 'ascending';
$string['attachment'] = 'Attachment';
$string['attachment_help'] = 'You can optionally attach one or more files to a glossary entry.';
$string['author'] = 'author';
$string['authorview'] = 'Browse by Author';
$string['back'] = 'Back';
$string['cachedef_concepts'] = 'Concept linking';
$string['cantinsertcat'] = 'Can\'t insert category';
$string['cantinsertrec'] = 'Can\'t insert record';
$string['cantinsertrel'] = 'Can\'t insert relation category-entry';
$string['casesensitive'] = 'This entry is case sensitive';
$string['casesensitive_help'] = 'This setting specifies whether matching exact upper and lower case is necessary when auto-linking to an entry.';
$string['cat'] = 'cat';
$string['categories'] = 'Categories';
$string['category'] = 'Category';
$string['categorydeleted'] = 'Category deleted';
$string['categoryview'] = 'Browse by category';
$string['cnfallowcomments'] = 'Define if a glossary will accept comments on entries by default';
$string['cnfallowdupentries'] = 'Define if a glossary will allows duplicated entries by default';
$string['cnfapprovalstatus'] = 'Define the approval status by default of an entry posted by a student';
$string['cnfcasesensitive'] = 'Define if an entry, when linked, is case sensitive by default';
$string['cnfdefaulthook'] = 'Select the default selection to show when the glossary is first viewed';
$string['cnfdefaultmode'] = 'Select the default frame to show when the glossary is first viewed.';
$string['cnffullmatch'] = 'Define if an entry, when linked, should match the case in the target text by default';
$string['cnflinkentry'] = 'Define if an entry should be automatically linked by default';
$string['cnflinkglossaries'] = 'Define if a glossary should be automatically linked by default';
$string['cnfrelatedview'] = 'Select the display format to be used for automatic linking and entry view.';
$string['cnfshowgroup'] = 'Specify if the group break should be shown or not.';
$string['cnfsortkey'] = 'Select the sorting key by default.';
$string['cnfsortorder'] = 'Select the sorting order by default.';
$string['cnfstudentcanpost'] = 'Define if the students can or cannot post entries by default';
$string['cnftabs'] = 'Select visible tabs for this glossary format';
$string['comment'] = 'Comment';
$string['commentdeleted'] = 'The comment has been deleted.';
$string['comments'] = 'Comments';
$string['commentson'] = 'Comments on';
$string['commentupdated'] = 'The comment has been updated.';
$string['completiondetail:entries'] = 'Make entries: {$a}';
$string['completionentries'] = 'Add entries';
$string['completionentriesdesc'] = 'Student must create at least {$a} entry/entries';
$string['concept'] = 'Concept';
$string['concepts'] = 'Concepts';
$string['configenablerssfeeds'] = 'This switch will enable the possibility of RSS feeds for all glossaries. You will still need to turn feeds on manually in the settings for each glossary.';
$string['current'] = 'Currently sorted {$a}';
$string['currentglossary'] = 'Current glossary';
$string['date'] = 'date';
$string['dateview'] = 'Browse by date';
$string['defaultapproval'] = 'Approved by default';
$string['defaultapproval_help'] = 'If set to no, entries require approving by a teacher before they are viewable by everyone.';
$string['defaulthook'] = 'Default hook';
$string['defaultmode'] = 'Default mode';
$string['defaultsortkey'] = 'Default sort key';
$string['defaultsortorder'] = 'Default sort order';
$string['definition'] = 'Definition';
$string['definitions'] = 'Definitions';
$string['deleteentry'] = 'Delete entry';
$string['deletecategory'] = 'Delete category';
$string['deleteentrya'] = 'Delete entry: {$a}';
$string['deletenotenrolled'] = 'Delete entries by users not enrolled';
$string['deletingcomment'] = 'Deleting comment';
$string['deletingnoneemptycategory'] = 'Deleting this category will not delete the entries it contains - they will be marked as uncategorised.';
$string['descending'] = 'descending';
$string['destination'] = 'Destination of imported entries';
$string['destination_help'] = 'Entries can either be imported and added to the current glossary or to a new glossary, in which case a new glossary will be created based on information in the XML file.';
$string['disapprove'] = 'Undo approval';
$string['displayformat'] = 'Display format';
$string['displayformat_help'] = 'There are 7 display formats:
* Simple, dictionary style - No authors are displayed and attachments are shown as links
* Continuous without author - Entries are displayed one after another without any separation apart from the editing icons
* Full with author - A forum-like display format showing the author\'s data and with attachments shown as links
* Full without author - A forum-like display format without authors and with attachments shown as links
* Encyclopedia - As for "Full with author" but attached images are shown inline
* Entry list - Concepts are listed as links
* FAQ - The words QUESTION and ANSWER are appended to the concept and definition respectively';
$string['displayformatcontinuous'] = 'Continuous without author';
$string['displayformatdefault'] = 'Default to same as display format';
$string['displayformatdictionary'] = 'Simple, dictionary style';
$string['displayformatencyclopedia'] = 'Encyclopedia';
$string['displayformatentrylist'] = 'Entry list';
$string['displayformatfaq'] = 'FAQ';
$string['displayformatfullwithauthor'] = 'Full with author';
$string['displayformatfullwithoutauthor'] = 'Full without author';
$string['displayformats'] = 'Display formats';
$string['displayformatssetup'] = 'Display formats setup';
$string['duplicatecategory'] = 'Duplicate category';
$string['duplicateentry'] = 'Duplicate entry';
$string['editalways'] = 'Always allow editing';
$string['editalways_help'] = 'This setting specifies whether entries are always editable or whether students can only edit their entries during a configured editing time (usually 30 minutes).';
$string['editcategories'] = 'Edit categories';
$string['editcategory'] = 'Edit category';
$string['editentry'] = 'Edit entry';
$string['editentrya'] = 'Edit entry: {$a}';
$string['editingcomment'] = 'Editing comment';
$string['entbypage'] = 'Entries shown per page';
$string['entries'] = 'Entries';
$string['entrieswithoutcategory'] = 'Entries without category';
$string['entry'] = 'Entry';
$string['entryalreadyexist'] = 'Entry already exists';
$string['entryapproved'] = 'This entry has been approved';
$string['entrydeleted'] = 'Entry deleted';
$string['entryexported'] = 'Entry successfully exported';
$string['entryishidden'] = '(this entry is currently hidden)';
$string['entryleveldefaultsettings'] = 'Entry level default settings';
$string['entrylink'] = 'Entry link: {$a}';
$string['entrysaved'] = 'This entry has been saved';
$string['entryupdated'] = 'This entry has been updated';
$string['entryusedynalink'] = 'This entry should be automatically linked';
$string['entryusedynalink_help'] = 'If site-wide glossary auto-linking has been enabled by an administrator and this checkbox is ticked, the entry will be automatically linked wherever the concept words and phrases appear throughout the rest of the course.';
$string['errcannoteditothers'] = 'You cannot edit other people\'s entries.';
$string['errconceptalreadyexists'] = 'This concept already exists. No duplicates allowed in this glossary.';
$string['errdeltimeexpired'] = 'You can\'t delete this. Time expired!';
$string['erredittimeexpired'] = 'The editing time for this entry has expired.';
$string['errorparsingxml'] = 'Errors occurred while parsing the file. Make sure it is valid XML syntax.';
$string['errreservedkeywords'] = 'One or more keywords contain a special character which cannot be used.';
$string['eventcategorycreated'] = 'Category has been created';
$string['eventcategorydeleted'] = 'Category has been deleted';
$string['eventcategoryupdated'] = 'Category has been updated';
$string['evententryapproved'] = 'Entry has been approved';
$string['evententrycreated'] = 'Entry has been created';
$string['evententrydeleted'] = 'Entry has been deleted';
$string['evententrydisapproved'] = 'Entry has been disapproved';
$string['evententryviewed'] = 'Entry has been viewed';
$string['evententryupdated'] = 'Entry has been updated';
$string['explainaddentry'] = 'Add a new entry to the current glossary.<br />Concept and definition are mandatory fields.';
$string['explainall'] = 'Shows ALL entries on one page';
$string['explainalphabet'] = 'Browse the glossary using this index';
$string['explainexport'] = 'Click on the button below to export glossary entries.<br />You can import it anytime you wish in this or other course.<p>Please note that attachments (e.g. images) and authors are not exported.</p>';
$string['explainimport'] = 'You must specify the file to import and define the criteria of the process.<p>Submit your request and review the results.</p>';
$string['explainspecial'] = 'Shows entries that do not begin with a letter';
$string['export'] = 'Export';
$string['exportedentry'] = 'Exported entry';
$string['exportentries'] = 'Export entries';
$string['exportentriestoxml'] = 'Export entries to XML file';
$string['exportfile'] = 'Export entries to file';
$string['exportglossary'] = 'Export glossary';
$string['exporttomainglossary'] = 'Export to main glossary';
$string['filetoimport'] = 'File to import';
$string['filetoimport_help'] = 'Browse for and select the XML file on your computer which contains the entries to import.';
$string['fillfields'] = 'Concept and definition are mandatory fields.';
$string['filtername'] = 'Glossary auto-linking';
$string['fullmatch'] = 'Match whole words only';
$string['fullmatch_help'] = 'This setting specifies whether only whole words will be linked, for example, a glossary entry named "construct" will not create a link inside the word "constructivism".';
$string['glossary:addinstance'] = 'Add a new glossary';
$string['glossary:approve'] = 'Approve and undo approved entries';
$string['glossary:comment'] = 'Create comments';
$string['glossary:export'] = 'Export entries';
$string['glossary:exportentry'] = 'Export single entry';
$string['glossary:exportownentry'] = 'Export single entry of yours';
$string['glossary:import'] = 'Import entries';
$string['glossaryleveldefaultsettings'] = 'Glossary level default settings';
$string['glossary:managecategories'] = 'Manage categories';
$string['glossary:managecomments'] = 'Manage comments';
$string['glossary:manageentries'] = 'Manage entries';
$string['glossary:rate'] = 'Rate entries';
$string['glossary:view'] = 'View entries';
$string['glossarytype'] = 'Glossary type';
$string['glossarytype_help'] = 'A main glossary is a glossary in which entries from secondary glossaries can be imported. There can only be one main glossary in a course. If glossary entry import is not required, all glossaries in the course can be secondary glossaries.';
$string['glossary:view'] = 'View glossary';
$string['glossary:viewallratings'] = 'View all raw ratings given by individuals';
$string['glossary:viewanyrating'] = 'View total ratings that anyone received';
$string['glossary:viewrating'] = 'View the total rating you received';
$string['glossary:write'] = 'Create new entries';
$string['guestnoedit'] = 'Guests are not allowed to edit glossaries';
$string['changeto'] = 'change to {$a}';
$string['importcategories'] = 'Import categories';
$string['importedcategories'] = 'Imported categories';
$string['importedentries'] = 'Imported entries';
$string['importentries'] = 'Import entries';
$string['importentriesfromxml'] = 'Import entries from XML file';
$string['includegroupbreaks'] = 'Include group breaks';
$string['indicator:cognitivedepth'] = 'Glossary cognitive';
$string['indicator:cognitivedepth_help'] = 'This indicator is based on the cognitive depth reached by the student in a Glossary activity.';
$string['indicator:cognitivedepthdef'] = 'Glossary cognitive';
$string['indicator:cognitivedepthdef_help'] = 'The participant has reached this percentage of the cognitive engagement offered by the Glossary activities during this analysis interval (Levels = No view, View, Submit)';
$string['indicator:cognitivedepthdef_link'] = 'Learning_analytics_indicators#Cognitive_depth';
$string['indicator:socialbreadth'] = 'Glossary social';
$string['indicator:socialbreadth_help'] = 'This indicator is based on the social breadth reached by the student in a Glossary activity.';
$string['indicator:socialbreadthdef'] = 'Glossary social';
$string['indicator:socialbreadthdef_help'] = 'The participant has reached this percentage of the social engagement offered by the Glossary activities during this analysis interval (Levels = No participation, Participant alone)';
$string['indicator:socialbreadthdef_link'] = 'Learning_analytics_indicators#Social_breadth';
$string['isglobal'] = 'Is this glossary global?';
$string['isglobal_help'] = 'A global glossary has entries which are linked to from throughout the site, rather than only in the course that the glossary is in. Only administrators can set a glossary as global.';
$string['letter'] = 'letter';
$string['linkcategory'] = 'Automatically link this category';
$string['linkcategory_help'] = 'If glossary auto-linking has been enabled and this setting is enabled, the category name will be automatically linked wherever it appears throughout the rest of the course. When a participant follows a category name link, they will be taken to the "Browse by category" page of the glossary.';
$string['linking'] = 'Auto-linking';
$string['mainglossary'] = 'Main glossary';
$string['maxtimehaspassed'] = 'Sorry, but the maximum time for editing this comment ({$a}) has passed!';
$string['modulename'] = 'Glossary';
$string['modulename_help'] = 'The glossary activity module enables participants to create and maintain a list of definitions, like a dictionary, or to collect and organise resources or information.
A teacher can allow files to be attached to glossary entries. Attached images are displayed in the entry. Entries can be searched or browsed alphabetically or by category, date or author. Entries can be approved by default or require approval by a teacher before they are viewable by everyone.
If the glossary auto-linking filter is enabled, entries will be automatically linked where the concept words and/or phrases appear within the course.
A teacher can allow comments on entries. Entries can also be rated by teachers or students (peer evaluation). Ratings can be aggregated to form a final grade which is recorded in the gradebook.
Glossaries have many uses, such as
* A collaborative bank of key terms
* A getting to know you space where new students add their name and personal details
* A handy tips resource of best practice in a practical subject
* A sharing area of useful videos, images or sound files
* A revision resource of facts to remember';
$string['modulename_link'] = 'mod/glossary/view';
$string['modulenameplural'] = 'Glossaries';
$string['newentries'] = 'New glossary entries';
$string['newglossary'] = 'New glossary';
$string['newglossarycreated'] = 'New glossary created.';
$string['newglossaryentries'] = 'New glossary entries:';
$string['nocomment'] = 'No comment found';
$string['nocomments'] = '(No comments found on this entry)';
$string['noconceptfound'] = 'No concept or definition found.';
$string['noentries'] = 'No entries found in this section';
$string['noentry'] = 'No entry found.';
$string['nopermissiontodelcomment'] = 'You can\'t delete other people\'s comments!';
$string['nopermissiontodelinglossary'] = 'You can\'t comments in this glossary!';
$string['nopermissiontoviewresult'] = 'You can only look at results for your own entries';
$string['notcategorised'] = 'Not categorised';
$string['notapproved'] = 'glossary entry is not approved yet.';
$string['entrynotapproved'] = 'Entry not approved';
$string['numberofentries'] = 'Number of entries';
$string['onebyline'] = '(one per line)';
$string['page-mod-glossary-x'] = 'Any glossary module page';
$string['page-mod-glossary-edit'] = 'Glossary add/edit entry page';
$string['page-mod-glossary-view'] = 'View glossary edit page';
$string['pendingapproval'] = 'Pending approval';
$string['pendingapprovalcount'] = 'Pending approval ({$a})';
$string['pluginadministration'] = 'Glossary administration';
$string['pluginname'] = 'Glossary';
$string['popupformat'] = 'Popup format';
$string['print'] = 'Print';
$string['printerfriendly'] = 'Printer-friendly version';
$string['printviewnotallowed'] = 'Print view isn\'t allowed';
$string['privacy'] = 'Privacy of results';
$string['privacy:metadata:core_comments'] = 'Comments made on glossary definitions are stored using core_comment system';
$string['privacy:metadata:core_files'] = 'Files linked to glossary definitions are stored using the core_files system';
$string['privacy:metadata:core_rating'] = 'Ratings added to glossary entries are stored using core_rating system';
$string['privacy:metadata:core_tag'] = 'Tags added to glossary definitions are stored using core_tag system ';
$string['privacy:metadata:glossary_entries'] = 'Information about the user\'s entries for a given glossary activity';
$string['privacy:metadata:glossary_entries:attachment'] = 'The attachment of the entry the user added';
$string['privacy:metadata:glossary_entries:concept'] = 'The concept of the entry the user added';
$string['privacy:metadata:glossary_entries:definition'] = 'The definition of the entry the user added';
$string['privacy:metadata:glossary_entries:glossaryid'] = 'The ID of the glossary activity';
$string['privacy:metadata:glossary_entries:userid'] = 'The ID of the user that is adding this glossary entry';
$string['privacy:metadata:glossary_entries:timemodified'] = 'The timestamp indicating when the glossary entry was modified by the user';
$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';
$string['rssarticles_help'] = 'This setting specifies the number of glossary entry concepts to include in the RSS feed. Between 5 and 20 generally acceptable.';
$string['rsssubscriberss'] = 'Display the RSS feed for \'{$a}\' concepts';
$string['rssfeed'] = 'RSS feed';
$string['rsstype'] = 'RSS feed for this activity';
$string['rsstype_help'] = 'To enable the RSS feed for this activity, select either concepts with author or concepts without author to be included in the feed.';
$string['search:activity'] = 'Glossary - activity information';
$string['search:entry'] = 'Glossary - entries';
$string['searchindefinition'] = 'Search full text';
$string['secondaryglossary'] = 'Secondary glossary';
$string['showall'] = 'Show \'ALL\' link';
$string['showall_help'] = 'If enabled, participants can browse all entries at once.';
$string['showalphabet'] = 'Show alphabet links';
$string['showalphabet_help'] = 'If enabled, participants can browse the glossary by letters of the alphabet.';
$string['showspecial'] = 'Show \'Special\' link';
$string['showspecial_help'] = 'If enabled, participants can browse the glossary by special characters, such as @ and #.';
$string['sortby'] = 'Sort by';
$string['sortbycreation'] = 'By creation date';
$string['sortbylastupdate'] = 'By last update';
$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['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.';
$string['visibletabs'] = 'Visible tabs';
$string['warningstudentcapost'] = '(Applies only if the glossary is not the main one)';
$string['withauthor'] = 'Concepts with author';
$string['withoutauthor'] = 'Concepts without author';
$string['writtenby'] = 'by';
$string['youarenottheauthor'] = 'You are not the author of this comment, so you are not allowed to edit it.';
// Deprecated since 4.3.
$string['completionentriesgroup'] = 'Require entries';
+4509
View File
File diff suppressed because it is too large Load Diff
+766
View File
@@ -0,0 +1,766 @@
<?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/>.
/**
* Library of functions and constants for module glossary
* outside of what is required for the core moodle api
*
* @package mod_glossary
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once($CFG->libdir . '/portfolio/caller.php');
require_once($CFG->libdir . '/filelib.php');
/**
* class to handle exporting an entire glossary database
*/
class glossary_full_portfolio_caller extends portfolio_module_caller_base {
private $glossary;
private $exportdata;
private $keyedfiles = array(); // keyed on entry
/**
* return array of expected call back arguments
* and whether they are required or not
*
* @return array
*/
public static function expected_callbackargs() {
return array(
'id' => true,
);
}
/**
* load up all data required for this export.
*
* @return void
*/
public function load_data() {
global $DB;
if (!$this->cm = get_coursemodule_from_id('glossary', $this->id)) {
throw new portfolio_caller_exception('invalidid', 'glossary');
}
if (!$this->glossary = $DB->get_record('glossary', array('id' => $this->cm->instance))) {
throw new portfolio_caller_exception('invalidid', 'glossary');
}
$entries = $DB->get_records('glossary_entries', array('glossaryid' => $this->glossary->id));
list($where, $params) = $DB->get_in_or_equal(array_keys($entries));
$aliases = $DB->get_records_select('glossary_alias', 'entryid ' . $where, $params);
$categoryentries = $DB->get_records_sql('SELECT ec.entryid, c.name FROM {glossary_entries_categories} ec
JOIN {glossary_categories} c
ON c.id = ec.categoryid
WHERE ec.entryid ' . $where, $params);
$this->exportdata = array('entries' => $entries, 'aliases' => $aliases, 'categoryentries' => $categoryentries);
$fs = get_file_storage();
$context = context_module::instance($this->cm->id);
$this->multifiles = array();
foreach (array_keys($entries) as $entry) {
$this->keyedfiles[$entry] = array_merge(
$fs->get_area_files($context->id, 'mod_glossary', 'attachment', $entry, "timemodified", false),
$fs->get_area_files($context->id, 'mod_glossary', 'entry', $entry, "timemodified", false)
);
$this->multifiles = array_merge($this->multifiles, $this->keyedfiles[$entry]);
}
}
/**
* how long might we expect this export to take
*
* @return constant one of PORTFOLIO_TIME_XX
*/
public function expected_time() {
$filetime = portfolio_expected_time_file($this->multifiles);
$dbtime = portfolio_expected_time_db(count($this->exportdata['entries']));
return ($filetime > $dbtime) ? $filetime : $dbtime;
}
/**
* return the sha1 of this content
*
* @return string
*/
public function get_sha1() {
$file = '';
if ($this->multifiles) {
$file = $this->get_sha1_file();
}
return sha1(serialize($this->exportdata) . $file);
}
/**
* prepare the package ready to be passed off to the portfolio plugin
*
* @return void
*/
public function prepare_package() {
$entries = $this->exportdata['entries'];
$aliases = array();
$categories = array();
if (is_array($this->exportdata['aliases'])) {
foreach ($this->exportdata['aliases'] as $alias) {
if (!array_key_exists($alias->entryid, $aliases)) {
$aliases[$alias->entryid] = array();
}
$aliases[$alias->entryid][] = $alias->alias;
}
}
if (is_array($this->exportdata['categoryentries'])) {
foreach ($this->exportdata['categoryentries'] as $cat) {
if (!array_key_exists($cat->entryid, $categories)) {
$categories[$cat->entryid] = array();
}
$categories[$cat->entryid][] = $cat->name;
}
}
if ($this->get('exporter')->get('formatclass') == PORTFOLIO_FORMAT_SPREADSHEET) {
$csv = glossary_generate_export_csv($entries, $aliases, $categories);
$this->exporter->write_new_file($csv, clean_filename($this->cm->name) . '.csv', false);
return;
} else if ($this->get('exporter')->get('formatclass') == PORTFOLIO_FORMAT_LEAP2A) {
$ids = array(); // keep track of these to make into a selection later
global $USER, $DB;
$writer = $this->get('exporter')->get('format')->leap2a_writer($USER);
$format = $this->exporter->get('format');
$filename = $this->get('exporter')->get('format')->manifest_name();
foreach ($entries as $e) {
$content = glossary_entry_portfolio_caller::entry_content(
$this->course,
$this->cm,
$this->glossary,
$e,
(array_key_exists($e->id, $aliases) ? $aliases[$e->id] : array()),
$format
);
$entry = new portfolio_format_leap2a_entry('glossaryentry' . $e->id, $e->concept, 'entry', $content);
$entry->author = $DB->get_record('user', array('id' => $e->userid), 'id,firstname,lastname,email');
$entry->published = $e->timecreated;
$entry->updated = $e->timemodified;
if (!empty($this->keyedfiles[$e->id])) {
$writer->link_files($entry, $this->keyedfiles[$e->id], 'glossaryentry' . $e->id . 'file');
foreach ($this->keyedfiles[$e->id] as $file) {
$this->exporter->copy_existing_file($file);
}
}
if (!empty($categories[$e->id])) {
foreach ($categories[$e->id] as $cat) {
// this essentially treats them as plain tags
// leap has the idea of category schemes
// but I think this is overkill here
$entry->add_category($cat);
}
}
$writer->add_entry($entry);
$ids[] = $entry->id;
}
$selection = new portfolio_format_leap2a_entry('wholeglossary' . $this->glossary->id, get_string('modulename', 'glossary'), 'selection');
$writer->add_entry($selection);
$writer->make_selection($selection, $ids, 'Grouping');
$content = $writer->to_xml();
}
$this->exporter->write_new_file($content, $filename, true);
}
/**
* make sure that the current user is allowed to do this
*
* @return boolean
*/
public function check_permissions() {
return has_capability('mod/glossary:export', context_module::instance($this->cm->id));
}
/**
* return a nice name to be displayed about this export location
*
* @return string
*/
public static function display_name() {
return get_string('modulename', 'glossary');
}
/**
* what formats this function *generally* supports
*
* @return array
*/
public static function base_supported_formats() {
return array(PORTFOLIO_FORMAT_SPREADSHEET, PORTFOLIO_FORMAT_LEAP2A);
}
}
/**
* class to export a single glossary entry
*
* @package mod_glossary
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class glossary_entry_portfolio_caller extends portfolio_module_caller_base {
private $glossary;
private $entry;
protected $entryid;
/** @var array Array that contains all aliases for the given glossary entry. */
private array $aliases = [];
/** @var array categories. */
private array $categories = [];
/*
* @return array
*/
public static function expected_callbackargs() {
return array(
'entryid' => true,
'id' => true,
);
}
/**
* load up all data required for this export.
*
* @return void
*/
public function load_data() {
global $DB;
if (!$this->cm = get_coursemodule_from_id('glossary', $this->id)) {
throw new portfolio_caller_exception('invalidid', 'glossary');
}
if (!$this->glossary = $DB->get_record('glossary', array('id' => $this->cm->instance))) {
throw new portfolio_caller_exception('invalidid', 'glossary');
}
if ($this->entryid) {
if (!$this->entry = $DB->get_record('glossary_entries', array('id' => $this->entryid))) {
throw new portfolio_caller_exception('noentry', 'glossary');
}
// in case we don't have USER this will make the entry be printed
$this->entry->approved = true;
}
$this->categories = $DB->get_records_sql('SELECT ec.entryid, c.name FROM {glossary_entries_categories} ec
JOIN {glossary_categories} c
ON c.id = ec.categoryid
WHERE ec.entryid = ?', array($this->entryid));
$context = context_module::instance($this->cm->id);
if ($this->entry->sourceglossaryid == $this->cm->instance) {
if ($maincm = get_coursemodule_from_instance('glossary', $this->entry->glossaryid)) {
$context = context_module::instance($maincm->id);
}
}
$this->aliases = $DB->get_records('glossary_alias', ['entryid' => $this->entryid]);
$fs = get_file_storage();
$this->multifiles = array_merge(
$fs->get_area_files($context->id, 'mod_glossary', 'attachment', $this->entry->id, "timemodified", false),
$fs->get_area_files($context->id, 'mod_glossary', 'entry', $this->entry->id, "timemodified", false)
);
if (!empty($this->multifiles)) {
$this->add_format(PORTFOLIO_FORMAT_RICHHTML);
} else {
$this->add_format(PORTFOLIO_FORMAT_PLAINHTML);
}
}
/**
* how long might we expect this export to take
*
* @return constant one of PORTFOLIO_TIME_XX
*/
public function expected_time() {
return PORTFOLIO_TIME_LOW;
}
/**
* make sure that the current user is allowed to do this
*
* @return boolean
*/
public function check_permissions() {
$context = context_module::instance($this->cm->id);
return has_capability('mod/glossary:exportentry', $context)
|| ($this->entry->userid == $this->user->id && has_capability('mod/glossary:exportownentry', $context));
}
/**
* return a nice name to be displayed about this export location
*
* @return string
*/
public static function display_name() {
return get_string('modulename', 'glossary');
}
/**
* prepare the package ready to be passed off to the portfolio plugin
*
* @return void
*/
public function prepare_package() {
global $DB;
$format = $this->exporter->get('format');
$content = self::entry_content($this->course, $this->cm, $this->glossary, $this->entry, $this->aliases, $format);
if ($this->exporter->get('formatclass') === PORTFOLIO_FORMAT_PLAINHTML) {
$filename = clean_filename($this->entry->concept) . '.html';
$this->exporter->write_new_file($content, $filename);
} else if ($this->exporter->get('formatclass') === PORTFOLIO_FORMAT_RICHHTML) {
if ($this->multifiles) {
foreach ($this->multifiles as $file) {
$this->exporter->copy_existing_file($file);
}
}
$filename = clean_filename($this->entry->concept) . '.html';
$this->exporter->write_new_file($content, $filename);
} else if ($this->exporter->get('formatclass') === PORTFOLIO_FORMAT_LEAP2A) {
$writer = $this->get('exporter')->get('format')->leap2a_writer();
$entry = new portfolio_format_leap2a_entry('glossaryentry' . $this->entry->id, $this->entry->concept, 'entry', $content);
$entry->author = $DB->get_record('user', array('id' => $this->entry->userid), 'id,firstname,lastname,email');
$entry->published = $this->entry->timecreated;
$entry->updated = $this->entry->timemodified;
if ($this->multifiles) {
$writer->link_files($entry, $this->multifiles);
foreach ($this->multifiles as $file) {
$this->exporter->copy_existing_file($file);
}
}
if ($this->categories) {
foreach ($this->categories as $cat) {
// this essentially treats them as plain tags
// leap has the idea of category schemes
// but I think this is overkill here
$entry->add_category($cat->name);
}
}
$writer->add_entry($entry);
$content = $writer->to_xml();
$filename = $this->get('exporter')->get('format')->manifest_name();
$this->exporter->write_new_file($content, $filename);
} else {
throw new portfolio_caller_exception('unexpected_format_class', 'glossary');
}
}
/**
* return the sha1 of this content
*
* @return string
*/
public function get_sha1() {
if ($this->multifiles) {
return sha1(serialize($this->entry) . $this->get_sha1_file());
}
return sha1(serialize($this->entry));
}
/**
* what formats this function *generally* supports
*
* @return array
*/
public static function base_supported_formats() {
return array(PORTFOLIO_FORMAT_RICHHTML, PORTFOLIO_FORMAT_PLAINHTML, PORTFOLIO_FORMAT_LEAP2A);
}
/**
* helper function to get the html content of an entry
* for both this class and the full glossary exporter
* this is a very simplified version of the dictionary format output,
* but with its 500 levels of indirection removed
* and file rewriting handled by the portfolio export format.
*
* @param stdclass $course
* @param stdclass $cm
* @param stdclass $glossary
* @param stdclass $entry
*
* @return string
*/
public static function entry_content($course, $cm, $glossary, $entry, $aliases, $format) {
global $OUTPUT, $DB;
$entry = clone $entry;
$context = context_module::instance($cm->id);
$options = portfolio_format_text_options();
$options->trusted = $entry->definitiontrust;
$options->context = $context;
$output = '<table class="glossarypost dictionary" cellspacing="0">' . "\n";
$output .= '<tr valign="top">' . "\n";
$output .= '<td class="entry">' . "\n";
$output .= '<div class="concept">';
$output .= format_text($OUTPUT->heading($entry->concept, 3), FORMAT_MOODLE, $options);
$output .= '</div> ' . "\n";
$entry->definition = format_text($entry->definition, $entry->definitionformat, $options);
$output .= portfolio_rewrite_pluginfile_urls($entry->definition, $context->id, 'mod_glossary', 'entry', $entry->id, $format);
if (isset($entry->footer)) {
$output .= $entry->footer;
}
$output .= '</td></tr>' . "\n";
if (!empty($aliases)) {
$output .= '<tr valign="top"><td class="entrylowersection">';
$key = (count($aliases) == 1) ? 'alias' : 'aliases';
$output .= get_string($key, 'glossary') . ': ';
foreach ($aliases as $alias) {
$output .= s($alias->alias) . ',';
}
$output = substr($output, 0, -1);
$output .= '</td></tr>' . "\n";
}
if ($entry->sourceglossaryid == $cm->instance) {
if (!$maincm = get_coursemodule_from_instance('glossary', $entry->glossaryid)) {
return '';
}
$filecontext = context_module::instance($maincm->id);
} else {
$filecontext = $context;
}
$fs = get_file_storage();
if ($files = $fs->get_area_files($filecontext->id, 'mod_glossary', 'attachment', $entry->id, "timemodified", false)) {
$output .= '<table border="0" width="100%"><tr><td>' . "\n";
foreach ($files as $file) {
$output .= $format->file_output($file);
}
$output .= '</td></tr></table>' . "\n";
}
$output .= '</table>' . "\n";
return $output;
}
}
/**
* Class representing the virtual node with all itemids in the file browser
*
* @category files
* @copyright 2012 David Mudrak <david@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class glossary_file_info_container extends file_info {
/** @var file_browser */
protected $browser;
/** @var stdClass */
protected $course;
/** @var stdClass */
protected $cm;
/** @var string */
protected $component;
/** @var stdClass */
protected $context;
/** @var array */
protected $areas;
/** @var string */
protected $filearea;
/**
* Constructor (in case you did not realize it ;-)
*
* @param file_browser $browser
* @param stdClass $course
* @param stdClass $cm
* @param stdClass $context
* @param array $areas
* @param string $filearea
*/
public function __construct($browser, $course, $cm, $context, $areas, $filearea) {
parent::__construct($browser, $context);
$this->browser = $browser;
$this->course = $course;
$this->cm = $cm;
$this->component = 'mod_glossary';
$this->context = $context;
$this->areas = $areas;
$this->filearea = $filearea;
}
/**
* @return array with keys contextid, filearea, itemid, filepath and filename
*/
public function get_params() {
return array(
'contextid' => $this->context->id,
'component' => $this->component,
'filearea' => $this->filearea,
'itemid' => null,
'filepath' => null,
'filename' => null,
);
}
/**
* Can new files or directories be added via the file browser
*
* @return bool
*/
public function is_writable() {
return false;
}
/**
* Should this node be considered as a folder in the file browser
*
* @return bool
*/
public function is_directory() {
return true;
}
/**
* Returns localised visible name of this node
*
* @return string
*/
public function get_visible_name() {
return $this->areas[$this->filearea];
}
/**
* Returns list of children nodes
*
* @return array of file_info instances
*/
public function get_children() {
return $this->get_filtered_children('*', false, true);
}
/**
* Help function to return files matching extensions or their count
*
* @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
* @param bool|int $countonly if false returns the children, if an int returns just the
* count of children but stops counting when $countonly number of children is reached
* @param bool $returnemptyfolders if true returns items that don't have matching files inside
* @return array|int array of file_info instances or the count
*/
private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
global $DB;
$sql = 'SELECT DISTINCT f.itemid, ge.concept
FROM {files} f
JOIN {modules} m ON (m.name = :modulename AND m.visible = 1)
JOIN {course_modules} cm ON (cm.module = m.id AND cm.id = :instanceid)
JOIN {glossary} g ON g.id = cm.instance
JOIN {glossary_entries} ge ON (ge.glossaryid = g.id AND ge.id = f.itemid)
WHERE f.contextid = :contextid
AND f.component = :component
AND f.filearea = :filearea';
$params = array(
'modulename' => 'glossary',
'instanceid' => $this->context->instanceid,
'contextid' => $this->context->id,
'component' => $this->component,
'filearea' => $this->filearea);
if (!$returnemptyfolders) {
$sql .= ' AND f.filename <> :emptyfilename';
$params['emptyfilename'] = '.';
}
list($sql2, $params2) = $this->build_search_files_sql($extensions, 'f');
$sql .= ' '.$sql2;
$params = array_merge($params, $params2);
if ($countonly !== false) {
$sql .= ' ORDER BY ge.concept, f.itemid';
}
$rs = $DB->get_recordset_sql($sql, $params);
$children = array();
foreach ($rs as $record) {
if ($child = $this->browser->get_file_info($this->context, 'mod_glossary', $this->filearea, $record->itemid)) {
$children[] = $child;
}
if ($countonly !== false && count($children) >= $countonly) {
break;
}
}
$rs->close();
if ($countonly !== false) {
return count($children);
}
return $children;
}
/**
* Returns list of children which are either files matching the specified extensions
* or folders that contain at least one such file.
*
* @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
* @return array of file_info instances
*/
public function get_non_empty_children($extensions = '*') {
return $this->get_filtered_children($extensions, false);
}
/**
* Returns the number of children which are either files matching the specified extensions
* or folders containing at least one such file.
*
* @param string|array $extensions, for example '*' or array('.gif','.jpg')
* @param int $limit stop counting after at least $limit non-empty children are found
* @return int
*/
public function count_non_empty_children($extensions = '*', $limit = 1) {
return $this->get_filtered_children($extensions, $limit);
}
/**
* Returns parent file_info instance
*
* @return file_info or null for root
*/
public function get_parent() {
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, ge.userid,
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) {
global $USER;
if ($taggeditem->courseid == $courseid) {
$accessible = false;
if (($cm = $modinfo->get_cm($taggeditem->cmid)) && $cm->uservisible) {
if ($taggeditem->approved) {
$accessible = true;
} else if ($taggeditem->userid == $USER->id) {
$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())));
$approved = "";
if (!$item->approved) {
$approved = '<br>'. html_writer::span(get_string('entrynotapproved', 'mod_glossary'), 'badge bg-warning text-dark');
}
$tagfeed->add($icon, $pagename, $cmname.'<br>'.$coursename.$approved);
}
$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);
}
}
+250
View File
@@ -0,0 +1,250 @@
<?php
if (!defined('MOODLE_INTERNAL')) {
die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
}
require_once ($CFG->dirroot.'/course/moodleform_mod.php');
class mod_glossary_mod_form extends moodleform_mod {
function definition() {
global $CFG, $COURSE, $DB;
$mform =& $this->_form;
//-------------------------------------------------------------------------------
$mform->addElement('header', 'general', get_string('general', 'form'));
$mform->addElement('text', 'name', get_string('name'), array('size'=>'64'));
if (!empty($CFG->formatstringstriptags)) {
$mform->setType('name', PARAM_TEXT);
} else {
$mform->setType('name', PARAM_CLEANHTML);
}
$mform->addRule('name', null, 'required', null, 'client');
$mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
$this->standard_intro_elements();
if (has_capability('mod/glossary:manageentries', context_system::instance())) {
$mform->addElement('checkbox', 'globalglossary', get_string('isglobal', 'glossary'));
$mform->addHelpButton('globalglossary', 'isglobal', 'glossary');
}else{
$mform->addElement('hidden', 'globalglossary');
$mform->setType('globalglossary', PARAM_INT);
}
$options = array(1=>get_string('mainglossary', 'glossary'), 0=>get_string('secondaryglossary', 'glossary'));
$mform->addElement('select', 'mainglossary', get_string('glossarytype', 'glossary'), $options);
$mform->addHelpButton('mainglossary', 'glossarytype', 'glossary');
$mform->setDefault('mainglossary', 0);
// ----------------------------------------------------------------------
$mform->addElement('header', 'entrieshdr', get_string('entries', 'glossary'));
$mform->addElement('selectyesno', 'defaultapproval', get_string('defaultapproval', 'glossary'));
$mform->setDefault('defaultapproval', $CFG->glossary_defaultapproval);
$mform->addHelpButton('defaultapproval', 'defaultapproval', 'glossary');
$mform->addElement('selectyesno', 'editalways', get_string('editalways', 'glossary'));
$mform->setDefault('editalways', 0);
$mform->addHelpButton('editalways', 'editalways', 'glossary');
$mform->addElement('selectyesno', 'allowduplicatedentries', get_string('allowduplicatedentries', 'glossary'));
$mform->setDefault('allowduplicatedentries', $CFG->glossary_dupentries);
$mform->addHelpButton('allowduplicatedentries', 'allowduplicatedentries', 'glossary');
$mform->addElement('selectyesno', 'allowcomments', get_string('allowcomments', 'glossary'));
$mform->setDefault('allowcomments', $CFG->glossary_allowcomments);
$mform->addHelpButton('allowcomments', 'allowcomments', 'glossary');
$mform->addElement('selectyesno', 'usedynalink', get_string('usedynalink', 'glossary'));
$mform->setDefault('usedynalink', $CFG->glossary_linkbydefault);
$mform->addHelpButton('usedynalink', 'usedynalink', 'glossary');
// ----------------------------------------------------------------------
$mform->addElement('header', 'appearancehdr', get_string('appearance'));
// Get and update available formats.
$recformats = glossary_get_available_formats();
$formats = array();
foreach ($recformats as $format) {
$formats[$format->name] = get_string('displayformat'.$format->name, 'glossary');
}
asort($formats);
$mform->addElement('select', 'displayformat', get_string('displayformat', 'glossary'), $formats);
$mform->setDefault('displayformat', 'dictionary');
$mform->addHelpButton('displayformat', 'displayformat', 'glossary');
$displayformats['default'] = get_string('displayformatdefault', 'glossary');
$displayformats = array_merge($displayformats, $formats);
$mform->addElement('select', 'approvaldisplayformat', get_string('approvaldisplayformat', 'glossary'), $displayformats);
$mform->setDefault('approvaldisplayformat', 'default');
$mform->addHelpButton('approvaldisplayformat', 'approvaldisplayformat', 'glossary');
$mform->addElement('text', 'entbypage', get_string('entbypage', 'glossary'));
$mform->setDefault('entbypage', $this->get_default_entbypage());
$mform->addRule('entbypage', null, 'numeric', null, 'client');
$mform->setType('entbypage', PARAM_INT);
$mform->addElement('selectyesno', 'showalphabet', get_string('showalphabet', 'glossary'));
$mform->setDefault('showalphabet', 1);
$mform->addHelpButton('showalphabet', 'showalphabet', 'glossary');
$mform->addElement('selectyesno', 'showall', get_string('showall', 'glossary'));
$mform->setDefault('showall', 1);
$mform->addHelpButton('showall', 'showall', 'glossary');
$mform->addElement('selectyesno', 'showspecial', get_string('showspecial', 'glossary'));
$mform->setDefault('showspecial', 1);
$mform->addHelpButton('showspecial', 'showspecial', 'glossary');
$mform->addElement('selectyesno', 'allowprintview', get_string('allowprintview', 'glossary'));
$mform->setDefault('allowprintview', 1);
$mform->addHelpButton('allowprintview', 'allowprintview', 'glossary');
if ($CFG->enablerssfeeds && isset($CFG->glossary_enablerssfeeds) && $CFG->glossary_enablerssfeeds) {
//-------------------------------------------------------------------------------
$mform->addElement('header', 'rssheader', get_string('rss'));
$choices = array();
$choices[0] = get_string('none');
$choices[1] = get_string('withauthor', 'glossary');
$choices[2] = get_string('withoutauthor', 'glossary');
$mform->addElement('select', 'rsstype', get_string('rsstype', 'glossary'), $choices);
$mform->addHelpButton('rsstype', 'rsstype', 'glossary');
$choices = array();
$choices[0] = '0';
$choices[1] = '1';
$choices[2] = '2';
$choices[3] = '3';
$choices[4] = '4';
$choices[5] = '5';
$choices[10] = '10';
$choices[15] = '15';
$choices[20] = '20';
$choices[25] = '25';
$choices[30] = '30';
$choices[40] = '40';
$choices[50] = '50';
$mform->addElement('select', 'rssarticles', get_string('rssarticles'), $choices);
$mform->addHelpButton('rssarticles', 'rssarticles', 'glossary');
$mform->hideIf('rssarticles', 'rsstype', 'eq', 0);
}
//-------------------------------------------------------------------------------
$this->standard_grading_coursemodule_elements();
$this->standard_coursemodule_elements();
//-------------------------------------------------------------------------------
// buttons
$this->add_action_buttons();
}
function definition_after_data() {
global $COURSE, $DB;
parent::definition_after_data();
$mform =& $this->_form;
$mainglossaryel =& $mform->getElement('mainglossary');
$mainglossary = $DB->get_record('glossary', array('mainglossary'=>1, 'course'=>$COURSE->id));
if ($mainglossary && ($mainglossary->id != $mform->getElementValue('instance'))){
//secondary glossary, a main one already exists in this course.
$mainglossaryel->setValue(0);
$mainglossaryel->freeze();
$mainglossaryel->setPersistantFreeze(true);
} else {
$mainglossaryel->unfreeze();
$mainglossaryel->setPersistantFreeze(false);
}
}
public function data_preprocessing(&$defaultvalues) {
parent::data_preprocessing($defaultvalues);
// Fallsback on the default setting if 'Entries shown per page' has been left blank.
// This prevents the field from being required and expand its section which should not
// be the case if there is a default value defined.
if (empty($defaultvalues['entbypage']) || $defaultvalues['entbypage'] < 0) {
$defaultvalues['entbypage'] = $this->get_default_entbypage();
}
$suffix = $this->get_suffix();
$completionentriesel = 'completionentries' . $suffix;
$completionentriesenabledel = 'completionentriesenabled' . $suffix;
// Set up the completion checkboxes which aren't part of standard data.
// Tick by default if Add mode or if completion entries settings is set to 1 or more.
if (empty($this->_instance) || !empty($defaultvalues[$completionentriesel])) {
$defaultvalues[$completionentriesenabledel] = 1;
} else {
$defaultvalues[$completionentriesenabledel] = 0;
}
if (empty($defaultvalues[$completionentriesel])) {
$defaultvalues[$completionentriesel] = 1;
}
}
public function add_completion_rules() {
$mform = $this->_form;
$suffix = $this->get_suffix();
$group = [];
$completionentriesenabledel = 'completionentriesenabled' . $suffix;
$group[] =& $mform->createElement(
'checkbox',
$completionentriesenabledel,
'',
get_string('completionentries', 'glossary')
);
$completionentriesel = 'completionentries' . $suffix;
$group[] =& $mform->createElement('text', $completionentriesel, '', ['size' => 3]);
$mform->setType($completionentriesel, PARAM_INT);
$completionentriesgroupel = 'completionentriesgroup' . $suffix;
$mform->addGroup($group, $completionentriesgroupel, '', ' ', false);
$mform->hideIf($completionentriesel, $completionentriesenabledel, 'notchecked');
return [$completionentriesgroupel];
}
public function completion_rule_enabled($data) {
$suffix = $this->get_suffix();
return (!empty($data['completionentriesenabled' . $suffix]) && $data['completionentries' . $suffix] != 0);
}
/**
* Allows module to modify the data returned by form get_data().
* This method is also called in the bulk activity completion form.
*
* Only available on moodleform_mod.
*
* @param stdClass $data the form data to be modified.
*/
public function data_postprocessing($data) {
parent::data_postprocessing($data);
if (!empty($data->completionunlocked)) {
// Turn off completion settings if the checkboxes aren't ticked.
$suffix = $this->get_suffix();
$completion = $data->{'completion' . $suffix};
$autocompletion = !empty($completion) && $completion == COMPLETION_TRACKING_AUTOMATIC;
if (empty($data->{'completionentriesenabled' . $suffix}) || !$autocompletion) {
$data->{'completionentries' . $suffix} = 0;
}
}
}
/**
* Returns the default value for 'Entries shown per page'.
*
* @return int default for number of entries per page.
*/
protected function get_default_entbypage() {
global $CFG;
return !empty($CFG->glossary_entbypage) ? $CFG->glossary_entbypage : 10;
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 63 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

+3
View File
@@ -0,0 +1,3 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" preserveAspectRatio="xMinYMid meet" overflow="visible"><path d="M11 4.5H7.5V1c0-.5-.5-1-1-1h-1c-.5 0-1 .5-1 1v3.5H1c-.5 0-1 .5-1 1v1c0 .5.5 1 1 1h3.5V11c0 .5.5 1 1 1h1c.5 0 1-.5 1-1V7.5H11c.6 0 1-.5 1-1v-1c0-.5-.4-1-1-1z" fill="#888"/></svg>

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 448 512" preserveAspectRatio="xMinYMid meet"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M432 256c0 17.7-14.3 32-32 32L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l352 0c17.7 0 32 14.3 32 32z"/></svg>

After

Width:  |  Height:  |  Size: 399 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMid meet">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.00391 5.50049C5.00391 4.11978 6.12319 3.00049 7.50391 3.00049H7.50879H18.5039C18.78 3.00049 19.0039 3.22435 19.0039 3.50049V20.4995C19.0039 20.7757 18.78 20.9995 18.5039 20.9995L18.5025 20.9995L6.9928 20.9995C5.89005 20.9995 4.99609 20.1056 4.99609 19.0028C4.99609 18.9429 4.99873 18.8836 5.00391 18.825V5.50049ZM7.00879 4.08412C6.42364 4.28866 6.00391 4.84556 6.00391 5.50049V17.2678C6.29545 17.1013 6.63301 17.0061 6.9928 17.0061H7.00879L7.00879 4.08412ZM8.00879 17.0061L8.00879 4.00049H18.0039V17.0061H8.00879ZM6.9928 18.0061H18.0039V19.9995L6.9928 19.9995C6.45046 19.9995 6.0093 19.5664 5.99638 19.0271C6.00133 18.9989 6.00391 18.9699 6.00391 18.9402V18.8774C6.06558 18.3861 6.48481 18.0061 6.9928 18.0061ZM10.0068 13.502C10.0068 13.2258 10.2307 13.002 10.5068 13.002L15.5073 13.002C15.7835 13.002 16.0073 13.2258 16.0073 13.502C16.0073 13.7781 15.7835 14.002 15.5073 14.002L10.5068 14.002C10.2307 14.002 10.0068 13.7781 10.0068 13.502ZM11.7273 7.32404C11.6519 7.1332 11.4676 7.00781 11.2623 7.00781C11.0571 7.00781 10.8728 7.1332 10.7973 7.32404L9.54197 10.5005C9.44047 10.7573 9.56638 11.0478 9.8232 11.1493C10.08 11.2508 10.3705 11.1249 10.472 10.8681L10.6143 10.5078H11.9103L12.0527 10.8681C12.1542 11.1249 12.4447 11.2508 12.7015 11.1493C12.9583 11.0478 13.0842 10.7573 12.9827 10.5005L11.7273 7.32404ZM11.2623 8.86818L11.5151 9.50781H11.0096L11.2623 8.86818ZM14.0068 7.00781C13.7307 7.00781 13.5068 7.23167 13.5068 7.50781C13.5068 7.78396 13.7307 8.00781 14.0068 8.00781H15.0726L13.5908 10.2305C13.4885 10.3839 13.479 10.5812 13.566 10.7437C13.653 10.9063 13.8224 11.0078 14.0068 11.0078H16.0068C16.283 11.0078 16.5068 10.784 16.5068 10.5078C16.5068 10.2317 16.283 10.0078 16.0068 10.0078H14.9411L16.4229 7.78516C16.5251 7.63173 16.5347 7.43446 16.4477 7.27188C16.3607 7.1093 16.1912 7.00781 16.0068 7.00781H14.0068Z" fill="#212529"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

+225
View File
@@ -0,0 +1,225 @@
<?php
global $CFG;
require_once("../../config.php");
require_once("lib.php");
$id = required_param('id', PARAM_INT); // Course Module ID
$sortorder = optional_param('sortorder', 'asc', PARAM_ALPHA); // Sorting order
$offset = optional_param('offset', 0, PARAM_INT); // number of entries to bypass
$pagelimit = optional_param('pagelimit', 0, PARAM_INT); // Number of entries per page, 0 if unlimited.
$displayformat = optional_param('displayformat',-1, PARAM_INT);
$mode = required_param('mode', PARAM_ALPHA); // mode to show the entries
$hook = optional_param('hook','ALL', PARAM_CLEAN); // what to show
$sortkey = optional_param('sortkey','UPDATE', PARAM_ALPHA); // Sorting key
$url = new moodle_url('/mod/glossary/print.php', array('id'=>$id));
if ($sortorder !== 'asc') {
$url->param('sortorder', $sortorder);
}
if ($offset !== 0) {
$url->param('offset', $offset);
}
if ($displayformat !== -1) {
$url->param('displayformat', $displayformat);
}
if ($sortkey !== 'UPDATE') {
$url->param('sortkey', $sortkey);
}
if ($mode !== 'letter') {
$url->param('mode', $mode);
}
if ($hook !== 'ALL') {
$url->param('hook', $hook);
}
$PAGE->set_url($url);
if (! $cm = get_coursemodule_from_id('glossary', $id)) {
throw new \moodle_exception('invalidcoursemodule');
}
if (! $course = $DB->get_record("course", array("id"=>$cm->course))) {
throw new \moodle_exception('coursemisconf');
}
if (! $glossary = $DB->get_record("glossary", array("id"=>$cm->instance))) {
throw new \moodle_exception('invalidid', 'glossary');
}
if ($pagelimit < 0) {
$pagelimit = 0;
}
require_course_login($course, true, $cm);
$context = context_module::instance($cm->id);
// Prepare format_string/text options
$fmtoptions = array(
'context' => $context);
$PAGE->set_pagelayout('print');
$PAGE->set_title(get_string("modulenameplural", "glossary"));
$PAGE->set_heading($course->fullname);
echo $OUTPUT->header();
if (!has_capability('mod/glossary:manageentries', $context) and !$glossary->allowprintview) {
notice(get_string('printviewnotallowed', 'glossary'));
}
/// setting the default values for the display mode of the current glossary
/// only if the glossary is viewed by the first time
if ( $dp = $DB->get_record('glossary_formats', array('name'=>$glossary->displayformat)) ) {
$printpivot = $dp->showgroup;
if ( $mode == '' and $hook == '' and $show == '') {
$mode = $dp->defaultmode;
$hook = $dp->defaulthook;
$sortkey = $dp->sortkey;
$sortorder = $dp->sortorder;
}
} else {
$printpivot = 1;
if ( $mode == '' and $hook == '' and $show == '') {
$mode = 'letter';
$hook = 'ALL';
}
}
if ( $displayformat == -1 ) {
$displayformat = $glossary->displayformat;
}
/// stablishing flag variables
if ( $sortorder = strtolower($sortorder) ) {
if ($sortorder != 'asc' and $sortorder != 'desc') {
$sortorder = '';
}
}
if ( $sortkey = strtoupper($sortkey) ) {
if ($sortkey != 'CREATION' and
$sortkey != 'UPDATE' and
$sortkey != 'FIRSTNAME' and
$sortkey != 'LASTNAME'
) {
$sortkey = '';
}
}
switch ( $mode = strtolower($mode) ) {
case 'entry': /// Looking for a certain entry id
$tab = GLOSSARY_STANDARD_VIEW;
break;
case 'cat': /// Looking for a certain cat
$tab = GLOSSARY_CATEGORY_VIEW;
if ( $hook > 0 ) {
$category = $DB->get_record("glossary_categories", array("id"=>$hook));
}
break;
case 'approval': /// Looking for entries waiting for approval
$tab = GLOSSARY_APPROVAL_VIEW;
if ( !$hook and !$sortkey and !$sortorder) {
$hook = 'ALL';
}
break;
case 'term': /// Looking for entries that include certain term in its concept, definition or aliases
$tab = GLOSSARY_STANDARD_VIEW;
break;
case 'date':
$tab = GLOSSARY_DATE_VIEW;
if ( !$sortkey ) {
$sortkey = 'UPDATE';
}
if ( !$sortorder ) {
$sortorder = 'desc';
}
break;
case 'author': /// Looking for entries, browsed by author
$tab = GLOSSARY_AUTHOR_VIEW;
if ( !$hook ) {
$hook = 'ALL';
}
if ( !$sortkey ) {
$sortkey = 'FIRSTNAME';
}
if ( !$sortorder ) {
$sortorder = 'asc';
}
break;
case 'letter': /// Looking for entries that begin with a certain letter, ALL or SPECIAL characters
default:
$tab = GLOSSARY_STANDARD_VIEW;
if ( !$hook ) {
$hook = 'ALL';
}
break;
}
include_once("sql.php");
$entriesshown = 0;
$currentpivot = '';
$site = $DB->get_record("course", array("id"=>1));
// Print dialog link.
$printtext = get_string('print', 'glossary');
$printlinkatt = array('onclick' => 'window.print();return false;', 'class' => 'glossary_no_print printicon');
$printiconlink = html_writer::link('#', $printtext, $printlinkatt);
echo html_writer::tag('div', $printiconlink, array('class' => 'displayprinticon'));
echo html_writer::tag('div', userdate(time()), array('class' => 'displaydate'));
$sitename = get_string("site") . ': <span class="strong">' . format_string($site->fullname) . '</span>';
echo html_writer::tag('div', $sitename, array('class' => 'sitename'));
$coursename = get_string("course") . ': <span class="strong">' . format_string($course->fullname) . ' ('. format_string($course->shortname) . ')</span>';
echo html_writer::tag('div', $coursename, array('class' => 'coursename'));
$modname = get_string("modulename","glossary") . ': <span class="strong">' . format_string($glossary->name, true) . '</span>';
echo html_writer::tag('div', $modname, array('class' => 'modname'));
if ( $allentries ) {
foreach ($allentries as $entry) {
// Setting the pivot for the current entry.
if ($printpivot) {
$pivot = $entry->{$pivotkey};
$upperpivot = core_text::strtoupper($pivot);
$pivottoshow = core_text::strtoupper(format_string($pivot, true, $fmtoptions));
// Reduce pivot to 1cc if necessary.
if (!$fullpivot) {
$upperpivot = core_text::substr($upperpivot, 0, 1);
$pivottoshow = core_text::substr($pivottoshow, 0, 1);
}
// If there's a group break.
if ($currentpivot != $upperpivot) {
$currentpivot = $upperpivot;
if ($userispivot) {
// Printing the user icon if defined (only when browsing authors).
$user = mod_glossary_entry_query_builder::get_user_from_record($entry);
$pivottoshow = fullname($user);
}
echo html_writer::tag('div', clean_text($pivottoshow), array('class' => 'mdl-align strong'));
}
}
glossary_print_entry($course, $cm, $glossary, $entry, $mode, $hook, 1, $displayformat, true);
}
// The all entries value may be a recordset or an array.
if ($allentries instanceof moodle_recordset) {
$allentries->close();
}
}
echo $OUTPUT->footer();
+210
View File
@@ -0,0 +1,210 @@
<?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/>.
/**
* This file adds support to rss feeds generation
*
* @package mod_glossary
* @category rss
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Returns the path to the cached rss feed contents. Creates/updates the cache if necessary.
*
* @param stdClass $context the context
* @param array $args the arguments received in the url
* @return string the full path to the cached RSS feed directory. Null if there is a problem.
*/
function glossary_rss_get_feed($context, $args) {
global $CFG, $DB, $COURSE, $USER;
$status = true;
if (empty($CFG->glossary_enablerssfeeds)) {
debugging("DISABLED (module configuration)");
return null;
}
$glossaryid = clean_param($args[3], PARAM_INT);
$cm = get_coursemodule_from_instance('glossary', $glossaryid, 0, false, MUST_EXIST);
$modcontext = context_module::instance($cm->id);
if ($COURSE->id == $cm->course) {
$course = $COURSE;
} else {
$course = $DB->get_record('course', array('id'=>$cm->course), '*', MUST_EXIST);
}
//context id from db should match the submitted one
if ($context->id != $modcontext->id || !has_capability('mod/glossary:view', $modcontext)) {
return null;
}
$glossary = $DB->get_record('glossary', array('id' => $glossaryid), '*', MUST_EXIST);
if (!rss_enabled_for_mod('glossary', $glossary)) {
return null;
}
$sql = glossary_rss_get_sql($glossary);
//get the cache file info
$filename = rss_get_file_name($glossary, $sql);
$cachedfilepath = rss_get_file_full_name('mod_glossary', $filename);
//Is the cache out of date?
$cachedfilelastmodified = 0;
if (file_exists($cachedfilepath)) {
$cachedfilelastmodified = filemtime($cachedfilepath);
}
//if the cache is more than 60 seconds old and there's new stuff
$dontrecheckcutoff = time()-60;
if ( $dontrecheckcutoff > $cachedfilelastmodified && glossary_rss_newstuff($glossary, $cachedfilelastmodified)) {
if (!$recs = $DB->get_records_sql($sql, array(), 0, $glossary->rssarticles)) {
return null;
}
$items = array();
foreach ($recs as $rec) {
$item = new stdClass();
$item->title = $rec->entryconcept;
if ($glossary->rsstype == 1) {//With author
$item->author = fullname($rec);
}
$item->pubdate = $rec->entrytimecreated;
$item->link = $CFG->wwwroot."/mod/glossary/showentry.php?courseid=".$glossary->course."&eid=".$rec->entryid;
$definition = file_rewrite_pluginfile_urls($rec->entrydefinition, 'pluginfile.php',
$modcontext->id, 'mod_glossary', 'entry', $rec->entryid);
$item->description = format_text($definition, $rec->entryformat, [
'context' => $modcontext,
'trusted' => true,
]);
$items[] = $item;
}
//First all rss feeds common headers
$header = rss_standard_header(format_string($glossary->name,true),
$CFG->wwwroot."/mod/glossary/view.php?g=".$glossary->id,
format_string($glossary->intro,true));
//Now all the rss items
if (!empty($header)) {
$articles = rss_add_items($items);
}
//Now all rss feeds common footers
if (!empty($header) && !empty($articles)) {
$footer = rss_standard_footer();
}
//Now, if everything is ok, concatenate it
if (!empty($header) && !empty($articles) && !empty($footer)) {
$rss = $header.$articles.$footer;
//Save the XML contents to file.
$status = rss_save_file('mod_glossary', $filename, $rss);
}
}
if (!$status) {
$cachedfilepath = null;
}
return $cachedfilepath;
}
/**
* The appropriate SQL query for the glossary items to go into the RSS feed
*
* @param stdClass $glossary the glossary object
* @param int $time check for items since this epoch timestamp
* @return string the SQL query to be used to get the entried from the glossary table of the database
*/
function glossary_rss_get_sql($glossary, $time=0) {
//do we only want new items?
if ($time) {
$time = "AND e.timecreated > $time";
} else {
$time = "";
}
if ($glossary->rsstype == 1) {//With author
$userfieldsapi = \core_user\fields::for_name();
$allnamefields = $userfieldsapi->get_sql('u', false, '', '', false)->selects;
$sql = "SELECT e.id AS entryid,
e.concept AS entryconcept,
e.definition AS entrydefinition,
e.definitionformat AS entryformat,
e.definitiontrust AS entrytrust,
e.timecreated AS entrytimecreated,
u.id AS userid,
$allnamefields
FROM {glossary_entries} e,
{user} u
WHERE e.glossaryid = {$glossary->id} AND
u.id = e.userid AND
e.approved = 1 $time
ORDER BY e.timecreated desc";
} else {//Without author
$sql = "SELECT e.id AS entryid,
e.concept AS entryconcept,
e.definition AS entrydefinition,
e.definitionformat AS entryformat,
e.definitiontrust AS entrytrust,
e.timecreated AS entrytimecreated,
u.id AS userid
FROM {glossary_entries} e,
{user} u
WHERE e.glossaryid = {$glossary->id} AND
u.id = e.userid AND
e.approved = 1 $time
ORDER BY e.timecreated desc";
}
return $sql;
}
/**
* If there is new stuff in since $time this returns true
* Otherwise it returns false.
*
* @param stdClass $glossary the glossary activity object
* @param int $time epoch timestamp to compare new items against, 0 for everyting
* @return bool true if there are new items
*/
function glossary_rss_newstuff($glossary, $time) {
global $DB;
$sql = glossary_rss_get_sql($glossary, $time);
$recs = $DB->get_records_sql($sql, null, 0, 1);//limit of 1. If we get even 1 back we have new stuff
return ($recs && !empty($recs));
}
/**
* Given a glossary object, deletes all cached RSS files associated with it.
*
* @param stdClass $glossary
*/
function glossary_rss_delete_file($glossary) {
global $CFG;
require_once("$CFG->libdir/rsslib.php");
rss_delete_file('mod_glossary', $glossary);
}
+55
View File
@@ -0,0 +1,55 @@
<?php
defined('MOODLE_INTERNAL') || die;
if ($ADMIN->fulltree) {
require_once($CFG->dirroot.'/mod/glossary/lib.php');
$settings->add(new admin_setting_heading('glossary_normal_header', get_string('glossaryleveldefaultsettings', 'glossary'), ''));
$settings->add(new admin_setting_configtext('glossary_entbypage', get_string('entbypage', 'glossary'),
get_string('entbypage', 'glossary'), 10, PARAM_INT));
$settings->add(new admin_setting_configcheckbox('glossary_dupentries', get_string('allowduplicatedentries', 'glossary'),
get_string('cnfallowdupentries', 'glossary'), 0));
$settings->add(new admin_setting_configcheckbox('glossary_allowcomments', get_string('allowcomments', 'glossary'),
get_string('cnfallowcomments', 'glossary'), 0));
$settings->add(new admin_setting_configcheckbox('glossary_linkbydefault', get_string('usedynalink', 'glossary'),
get_string('cnflinkglossaries', 'glossary'), 1));
$settings->add(new admin_setting_configcheckbox('glossary_defaultapproval', get_string('defaultapproval', 'glossary'),
get_string('cnfapprovalstatus', 'glossary'), 1));
if (empty($CFG->enablerssfeeds)) {
$options = array(0 => get_string('rssglobaldisabled', 'admin'));
$str = get_string('configenablerssfeeds', 'glossary').'<br />'.get_string('configenablerssfeedsdisabled2', 'admin');
} else {
$options = array(0=>get_string('no'), 1=>get_string('yes'));
$str = get_string('configenablerssfeeds', 'glossary');
}
$settings->add(new admin_setting_configselect('glossary_enablerssfeeds', get_string('enablerssfeeds', 'admin'),
$str, 0, $options));
$settings->add(new admin_setting_heading('glossary_levdev_header', get_string('entryleveldefaultsettings', 'glossary'), ''));
$settings->add(new admin_setting_configcheckbox('glossary_linkentries', get_string('usedynalink', 'glossary'),
get_string('cnflinkentry', 'glossary'), 0));
$settings->add(new admin_setting_configcheckbox('glossary_casesensitive', get_string('casesensitive', 'glossary'),
get_string('cnfcasesensitive', 'glossary'), 0));
$settings->add(new admin_setting_configcheckbox('glossary_fullmatch', get_string('fullmatch', 'glossary'),
get_string('cnffullmatch', 'glossary'), 0));
// This is unfortunately necessary to ensure that the glossary_formats table is populated and up to date.
// Ensure the table is in sync with what display formats are available in code.
glossary_get_available_formats();
$settings->add(new mod_glossary_admin_setting_display_formats());
}
+93
View File
@@ -0,0 +1,93 @@
<?php
require_once('../../config.php');
require_once('lib.php');
$concept = optional_param('concept', '', PARAM_CLEAN);
$courseid = optional_param('courseid', 0, PARAM_INT);
$eid = optional_param('eid', 0, PARAM_INT); // glossary entry id
$displayformat = optional_param('displayformat',-1, PARAM_SAFEDIR);
$url = new moodle_url('/mod/glossary/showentry.php');
$url->param('concept', $concept);
$url->param('courseid', $courseid);
$url->param('eid', $eid);
$url->param('displayformat', $displayformat);
$PAGE->set_url($url);
if ($CFG->forcelogin) {
require_login();
}
if ($eid) {
$entry = $DB->get_record('glossary_entries', array('id'=>$eid), '*', MUST_EXIST);
$glossary = $DB->get_record('glossary', array('id'=>$entry->glossaryid), '*', MUST_EXIST);
$cm = get_coursemodule_from_instance('glossary', $glossary->id, 0, false, MUST_EXIST);
$course = $DB->get_record('course', array('id'=>$cm->course), '*', MUST_EXIST);
require_course_login($course, true, $cm);
$entry->glossaryname = $glossary->name;
$entry->cmid = $cm->id;
$entry->courseid = $cm->course;
$entries = array($entry);
} else if ($concept) {
$course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
require_course_login($course);
$entries = glossary_get_entries_search($concept, $courseid);
} else {
throw new \moodle_exception('invalidelementid');
}
$PAGE->set_pagelayout('incourse');
$PAGE->activityheader->disable();
if ($entries) {
foreach ($entries as $key => $entry) {
// Need to get the course where the entry is,
// in order to check for visibility/approve permissions there
$entrycourse = $DB->get_record('course', array('id' => $entry->courseid), '*', MUST_EXIST);
$modinfo = get_fast_modinfo($entrycourse);
// make sure the entry is visible
if (empty($modinfo->cms[$entry->cmid]->uservisible)) {
unset($entries[$key]);
continue;
}
// make sure the entry is approved (or approvable by current user)
if (!$entry->approved and ($USER->id != $entry->userid)) {
$context = context_module::instance($entry->cmid);
if (!has_capability('mod/glossary:approve', $context)) {
unset($entries[$key]);
continue;
}
}
$entries[$key]->footer = "<p style=\"text-align:right\">&raquo;&nbsp;<a href=\"$CFG->wwwroot/mod/glossary/view.php?g=$entry->glossaryid\">".format_string($entry->glossaryname,true)."</a></p>";
glossary_entry_view($entry, $modinfo->cms[$entry->cmid]->context);
}
}
if (!empty($courseid)) {
$strglossaries = get_string('modulenameplural', 'glossary');
$strsearch = get_string('search');
$PAGE->navbar->add($strglossaries);
$PAGE->navbar->add($strsearch);
$PAGE->set_title(strip_tags("$course->shortname: $strglossaries $strsearch"));
$PAGE->set_heading($course->fullname);
echo $OUTPUT->header();
} else {
echo $OUTPUT->header(); // Needs to be something here to allow linking back to the whole glossary
}
if ($glossary) {
$url = new moodle_url('view.php', ['id' => $cm->id]);
$backlink = html_writer::link($url, get_string('back'), ['class' => 'btn btn-secondary']);
echo html_writer::tag('div', $backlink, ['class' => 'tertiary-navigation']);
}
if ($entries) {
glossary_print_dynaentry($courseid, $entries, $displayformat);
}
/// Show one reduced footer
echo $OUTPUT->footer();
+109
View File
@@ -0,0 +1,109 @@
<?php
/**
* SQL.PHP
* This file is include from view.php and print.php
* @copyright 2003
**/
/**
* This file defines, or redefines, the following variables:
*
* bool $userispivot Whether the user is the pivot.
* bool $fullpivot Whether the pivot should be displayed in full.
* bool $printpivot Whether the pivot should be displayed.
* string $pivotkey The property of the record at which the pivot is.
* int $count The number of records matching the request.
* array $allentries The entries matching the request.
* mixed $field Unset in this file.
* mixed $entry Unset in this file.
* mixed $canapprove Unset in this file.
*
* It relies on the following variables:
*
* object $glossary The glossary object.
* context $context The glossary context.
* mixed $hook The hook for the selected tab.
* string $sortkey The key to sort the records.
* string $sortorder The order of the sorting.
* int $offset The number of records to skip.
* int $pagelimit The number of entries on this page, or 0 if unlimited.
* string $mode The mode of browsing.
* string $tab The tab selected.
*/
$userispivot = false;
$fullpivot = true;
$pivotkey = 'concept';
switch ($tab) {
case GLOSSARY_AUTHOR_VIEW:
$userispivot = true;
$pivotkey = 'userid';
$field = ($sortkey == 'LASTNAME' ? 'LASTNAME' : 'FIRSTNAME');
list($allentries, $count) = glossary_get_entries_by_author($glossary, $context, $hook,
$field, $sortorder, $offset, $pagelimit);
unset($field);
break;
case GLOSSARY_CATEGORY_VIEW:
$hook = (int) $hook; // Make sure it's properly casted to int.
list($allentries, $count) = glossary_get_entries_by_category($glossary, $context, $hook, $offset, $pagelimit);
$pivotkey = 'categoryname';
if ($hook != GLOSSARY_SHOW_ALL_CATEGORIES) {
$printpivot = false;
}
break;
case GLOSSARY_DATE_VIEW:
$printpivot = false;
$field = ($sortkey == 'CREATION' ? 'CREATION' : 'UPDATE');
list($allentries, $count) = glossary_get_entries_by_date($glossary, $context, $field, $sortorder,
$offset, $pagelimit);
unset($field);
break;
case GLOSSARY_APPROVAL_VIEW:
$fullpivot = false;
$printpivot = false;
list($allentries, $count) = glossary_get_entries_to_approve($glossary, $context, $hook, $sortkey, $sortorder,
$offset, $pagelimit);
break;
case GLOSSARY_STANDARD_VIEW:
default:
$fullpivot = false;
switch ($mode) {
case 'search':
list($allentries, $count) = glossary_get_entries_by_search($glossary, $context, $hook, $fullsearch,
$sortkey, $sortorder, $offset, $pagelimit);
break;
case 'term':
$printpivot = false;
list($allentries, $count) = glossary_get_entries_by_term($glossary, $context, $hook, $offset, $pagelimit);
break;
case 'entry':
$printpivot = false;
$entry = glossary_get_entry_by_id($hook);
$canapprove = has_capability('mod/glossary:approve', $context);
if ($entry && ($entry->glossaryid == $glossary->id || $entry->sourceglossaryid != $glossary->id)
&& (!empty($entry->approved) || $entry->userid == $USER->id || $canapprove)) {
$count = 1;
$allentries = array($entry);
} else {
$count = 0;
$allentries = array();
}
unset($entry, $canapprove);
break;
case 'letter':
default:
list($allentries, $count) = glossary_get_entries_by_letter($glossary, $context, $hook, $offset, $pagelimit);
break;
}
break;
}
+128
View File
@@ -0,0 +1,128 @@
/** General Styles **/
.path-mod-glossary .glossarypost {
width: 95%;
border-collapse: separate;
margin: 0 auto;
text-align: left;
}
.path-mod-glossary .glossarypost.entrylist {
border-width: 0;
}
.path-mod-glossary .glossarypost.continuous .concept {
display: inline;
}
.path-mod-glossary .glossarypost .commands {
width: 200px;
white-space: nowrap;
}
.path-mod-glossary .glossarypost td.picture {
width: 35px;
}
.path-mod-glossary .glossarypost .entrylowersection .icons {
text-align: right;
padding-right: 5px;
}
.path-mod-glossary .glossarypost .entrylowersection .ratings {
text-align: right;
padding-right: 5px;
padding-bottom: 2px;
}
.path-mod-glossary .glossarypost .glossary-hidden-note {
margin: 0 .45em;
}
.path-mod-glossary .glossarydisplay {
margin-left: auto;
margin-right: auto;
}
.path-mod-glossary .glossarydisplay .tabs {
width: 100%;
margin-bottom: 0;
}
.path-mod-glossary .glossarydisplay .tabs .side {
border-style: none;
border-width: 0;
width: auto;
}
.path-mod-glossary .glossarydisplay .separator {
width: 4px;
}
.path-mod-glossary table.glossarypopup {
width: 95%;
}
.path-mod-glossary .entrybox,
.path-mod-glossary table.glossaryapproval,
.path-mod-glossary .glossarypost .entrylowersection table {
width: 100%;
margin-bottom: 0;
}
.glossary-activity-picture {
float: left;
}
.glossary-activity-content {
margin-left: 40px;
}
/** Page specific styles **/
#page-mod-glossary-view .glossarycontrol {
float: right;
text-align: right;
white-space: nowrap;
margin: 5px 0;
}
#page-mod-glossary-view table.glossarycategoryheader,
#page-mod-glossary-import table.glossaryimportexport {
margin-left: auto;
margin-right: auto;
}
#page-mod-glossary-view table.glossarycategoryheader {
margin-bottom: 0;
}
#page-mod-glossary-view table.glossarycategoryheader th {
padding: 0;
}
#page-mod-glossary-view td.glossarysearchbox label {
display: inline-block;
}
#page-mod-glossary-showentry #page-content {
min-width: 600px;
}
#page-mod-glossary-print .mod-glossary-entrylist .mod-glossary-entry {
vertical-align: top;
}
#page-mod-glossary-print .displayprinticon,
#page-mod-glossary-print .displaydate {
text-align: right;
font-size: 0.75em;
}
#page-mod-glossary-print .strong {
font-weight: bold;
}
.path-mod-glossary .printicon {
background: url([[pix:t/print]]) no-repeat scroll 2px center transparent;
/*rtl:ignore*/
padding-left: 20px;
}
+70
View File
@@ -0,0 +1,70 @@
<?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/>.
/**
* prints the tabbed bar
*
* @author Peter Dias
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mod_glossary
* @copyright 2021 Peter Dias
*/
defined('MOODLE_INTERNAL') || die;
echo html_writer::start_div('entrybox');
if (!isset($category)) {
$category = "";
}
switch ($tab) {
case GLOSSARY_CATEGORY_VIEW:
glossary_print_categories_menu($cm, $glossary, $hook, $category);
break;
case GLOSSARY_APPROVAL_VIEW:
glossary_print_approval_menu($cm, $glossary, $mode, $hook, $sortkey, $sortorder);
break;
case GLOSSARY_AUTHOR_VIEW:
$search = "";
glossary_print_author_menu($cm, $glossary, "author", $hook, $sortkey, $sortorder, 'print');
break;
case GLOSSARY_IMPORT_VIEW:
$search = "";
$l = "";
glossary_print_import_menu($cm, $glossary, 'import', $hook, $sortkey, $sortorder);
break;
case GLOSSARY_EXPORT_VIEW:
$search = "";
$l = "";
glossary_print_export_menu($cm, $glossary, 'export', $hook, $sortkey, $sortorder);
break;
case GLOSSARY_DATE_VIEW:
if (!$sortkey) {
$sortkey = 'UPDATE';
}
if (!$sortorder) {
$sortorder = 'desc';
}
glossary_print_alphabet_menu($cm, $glossary, "date", $hook, $sortkey, $sortorder);
break;
case GLOSSARY_STANDARD_VIEW:
default:
glossary_print_alphabet_menu($cm, $glossary, "letter", $hook, $sortkey, $sortorder);
if ($mode == 'search' and $hook) {
echo html_writer::tag('div', "$strsearch: $hook");
}
break;
}
echo html_writer::empty_tag('hr');
@@ -0,0 +1,165 @@
{{!
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/>.
}}
{{!
@template mod_glossary/standard_action_menu
Actions panel at the bottom of the assignment grading UI.
Classes required for JS:
* none
Data attributes required for JS:
* none
Context variables required for this template:
* see mod/glossary/classes/output/standard_action_bar.php
Example context (json):
{
"addnewbutton": {
"method" : "get",
"url" : "#",
"primary" : true,
"tooltip" : "This is a tooltip",
"label" : "This is a the button text",
"attributes": [
{
"name": "data-attribute",
"value": "yeah"
}
]
},
"tools": {
"button": {
"method" : "get",
"url" : "#",
"primary" : true,
"tooltip" : "This is a tooltip",
"label" : "This is a the button text",
"attributes": [
{
"name": "data-attribute",
"value": "yeah"
}
]
},
"select": {
"options": [
{
"url": "www.google.com",
"string": "Google"
},
{
"url": "www.yahoo.com",
"string": "Yahoo"
}
]
}
},
"tabjumps":
{
"id": "url_select_test",
"action": "https://example.com/post",
"formid": "url_select_form",
"sesskey": "sesskey",
"label": "core/url_select",
"helpicon": {
"title": "Help with something",
"text": "Help with something",
"url": "http://example.org/help",
"linktext": "",
"icon":{
"extraclasses": "iconhelp",
"attributes": [
{"name": "src", "value": "../../../pix/help.svg"},
{"name": "alt", "value": "Help icon"}
]
}
},
"showbutton": "Go",
"options": [{
"name": "Group 1", "isgroup": true, "options":
[
{"name": "Item 1", "isgroup": false, "value": "1"},
{"name": "Item 2", "isgroup": false, "value": "2"}
]},
{"name": "Group 2", "isgroup": true, "options":
[
{"name": "Item 3", "isgroup": false, "value": "3"},
{"name": "Item 4", "isgroup": false, "value": "4"}
]}],
"disabled": false,
"title": "Some cool title"
},
"searchbox": {
"action": "http://localhost/stable/mod/glossary/view.php",
"hiddenfields": [
{
"name": "id",
"value": 23
},
{
"name": "mode",
"value": "search"
}
],
"otherfields": "<input type='checkbox'>Rendered checkbox",
"inputname": "hook",
"query": "hook",
"searchstring": "Search"
}
}
}}
<div class="container-fluid tertiary-navigation">
<div class="row">
{{#addnewbutton}}
<div class="navitem">
{{> core/single_button }}
</div>
{{/addnewbutton}}
<div class="d-flex ml-sm-auto">
{{#tools}}
{{#button}}
<div class="navitem">
{{> core/single_button}}
</div>
{{/button}}
{{#select}}
<div class="navitem">
<div class="dropdown">
<button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
...
<span class="sr-only">{{#str}} exportentries, mod_glossary {{/str}}</span>
</button>
<div class="dropdown-menu dropdown-menu-right">
{{#options}}
<a class="dropdown-item" href="{{url}}"
{{#openinnewwindow}}target="_blank"{{/openinnewwindow}}>{{string}}</a>
{{/options}}
</div>
</div>
</div>
{{/select}}
{{/tools}}
</div>
</div>
<div class="row">
{{#tabjumps}}
<div class="navitem">
{{> core/url_select }}
</div>
{{/tabjumps}}
{{#searchbox}}
<div class="navitem">
{{> core/search_input }}
</div>
{{/searchbox}}
</div>
</div>
@@ -0,0 +1,85 @@
<?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/>.
namespace mod_glossary\backup;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir . "/phpunit/classes/restore_date_testcase.php");
require_once($CFG->dirroot . '/rating/lib.php');
/**
* Restore date tests.
*
* @package mod_glossary
* @copyright 2017 onwards Ankit Agarwal <ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class restore_date_test extends \restore_date_testcase {
/**
* Test restore dates.
*/
public function test_restore_dates(): void {
global $DB, $USER;
$gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
$record = ['assesstimefinish' => 100, 'assesstimestart' => 100, 'ratingtime' => 1, 'assessed' => 2, 'scale' => 1];
list($course, $glossary) = $this->create_course_and_module('glossary', $record);
// Glossary entries.
$entry1 = $gg->create_content($glossary, array('approved' => 1));
$gg->create_content($glossary, array('approved' => 0, 'userid' => $USER->id));
$gg->create_content($glossary, array('approved' => 0, 'userid' => -1));
$gg->create_content($glossary, array('approved' => 1));
$timestamp = 10000;
$DB->set_field('glossary_entries', 'timecreated', $timestamp);
$DB->set_field('glossary_entries', 'timemodified', $timestamp);
$ratingoptions = new \stdClass;
$ratingoptions->context = \context_module::instance($glossary->cmid);
$ratingoptions->ratingarea = 'entry';
$ratingoptions->component = 'mod_glossary';
$ratingoptions->itemid = $entry1->id;
$ratingoptions->scaleid = 2;
$ratingoptions->userid = $USER->id;
$rating = new \rating($ratingoptions);
$rating->update_rating(2);
$rating = $DB->get_record('rating', ['itemid' => $entry1->id]);
// Do backup and restore.
$newcourseid = $this->backup_and_restore($course);
$newglossary = $DB->get_record('glossary', ['course' => $newcourseid]);
$this->assertFieldsNotRolledForward($glossary, $newglossary, ['timecreated', 'timemodified']);
$props = ['assesstimefinish', 'assesstimestart'];
$this->assertFieldsRolledForward($glossary, $newglossary, $props);
$newentries = $DB->get_records('glossary_entries', ['glossaryid' => $newglossary->id]);
$newcm = $DB->get_record('course_modules', ['course' => $newcourseid, 'instance' => $newglossary->id]);
// Entries test.
foreach ($newentries as $entry) {
$this->assertEquals($timestamp, $entry->timecreated);
$this->assertEquals($timestamp, $entry->timemodified);
}
// Rating test.
$newrating = $DB->get_record('rating', ['contextid' => \context_module::instance($newcm->id)->id]);
$this->assertEquals($rating->timecreated, $newrating->timecreated);
$this->assertEquals($rating->timemodified, $newrating->timemodified);
}
}
@@ -0,0 +1,77 @@
<?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/>.
/**
* Steps definitions related with the glossary activity.
*
* @package mod_glossary
* @category test
* @copyright 2013 David Monllaó
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
require_once(__DIR__ . '/../../../../lib/behat/behat_base.php');
use Behat\Gherkin\Node\TableNode as TableNode;
/**
* Glossary-related steps definitions.
*
* @package mod_glossary
* @category test
* @copyright 2013 David Monllaó
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class behat_mod_glossary extends behat_base {
/**
* Adds an entry to the current glossary with the provided data. You should be in the glossary page.
*
* @Given /^I add a glossary entry with the following data:$/
* @param TableNode $data
*/
public function i_add_a_glossary_entry_with_the_following_data(TableNode $data) {
$this->execute("behat_forms::press_button", get_string('addsingleentry', 'mod_glossary'));
$this->execute("behat_forms::i_set_the_following_fields_to_these_values", $data);
$this->execute("behat_forms::press_button", get_string('savechanges'));
}
/**
* Adds a category with the specified name to the current glossary. You need to be in the glossary page.
*
* @Given /^I add a glossary entries category named "(?P<category_name_string>(?:[^"]|\\")*)"$/
* @param string $categoryname Category name
*/
public function i_add_a_glossary_entries_category_named($categoryname) {
$params = [
get_string('categoryview', 'mod_glossary'),
get_string('explainalphabet', 'glossary')
];
$this->execute("behat_forms::i_select_from_the_singleselect", $params);
$this->execute("behat_forms::press_button", get_string('editcategories', 'mod_glossary'));
$this->execute("behat_forms::press_button", get_string('addcategory', 'glossary'));
$this->execute('behat_forms::i_set_the_field_to', array('name', $this->escape($categoryname)));
$this->execute("behat_forms::press_button", get_string('savechanges'));
$this->execute("behat_forms::press_button", get_string('back', 'mod_glossary'));
}
}
+116
View File
@@ -0,0 +1,116 @@
@mod @mod_glossary
Feature: Glossary entries can be organised in categories
In order to organise glossary entries
As a teacher
I need to be able to create, edit and delete categories
@javascript
Scenario: Glossary entries can be organised in categories and categories can be autolinked
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 | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activities" exist:
| activity | name | intro | displayformat | course | idnumber |
| glossary | MyGlossary | Test glossary description | encyclopedia | C1 | glossary1 |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| label | name | check autolinking of CategoryAutoLinks and CategoryNoLinks text | C1 | label1 |
And the "glossary" filter is "on"
# Log in as a teacher and make sure nothing is yet autolinked
When I am on the "Course 1" course page logged in as teacher1
Then I should see "CategoryAutoLinks"
And I should see "CategoryNoLinks"
And "a.glossary.autolink" "css_element" should not exist
# Create, edit and delete categories
And I am on the MyGlossary "glossary activity" page
And I select "Browse by category" from the "Browse the glossary using this index" singleselect
And I press "Edit categories"
And I press "Add category"
And I set the field "name" to "CategoryNoLinks"
And I press "Save changes"
And I should see "0 Entries" in the "CategoryNoLinks" "table_row"
And I press "Add category"
And I set the field "name" to "CategoryAutoLinks"
And I set the field "usedynalink" to "Yes"
And I press "Save changes"
And I should see "0 Entries" in the "CategoryAutoLinks" "table_row"
And I press "Add category"
And I set the field "name" to "Category2"
And I press "Save changes"
And I click on "Edit" "link" in the "Category2" "table_row"
And I set the field "name" to "Category3"
And I press "Save changes"
And I should see "Category3"
And I should not see "Category2"
And I click on "Delete" "link" in the "Category3" "table_row"
And I press "No"
And I should see "Category3"
And I click on "Delete" "link" in the "Category3" "table_row"
And I press "Yes"
And I should not see "Category3"
And I press "Back"
# Add glossary entries in categories and outside
And I add a glossary entry with the following data:
| Concept | EntryNoCategory |
| Definition | Definition |
And I add a glossary entry with the following data:
| Concept | EntryCategoryNL |
| Definition | Definition |
| Categories | CategoryNoLinks |
And I add a glossary entry with the following data:
| Concept | EntryCategoryAL |
| Definition | Definition |
| Categories | CategoryAutoLinks |
And I press "Add entry"
And I set the following fields to these values:
| Concept | EntryCategoryBoth |
| Definition | Definition |
| Categories | CategoryAutoLinks,CategoryNoLinks |
And I press "Save changes"
# Make sure entries appear in their categories
And I select "Browse by category" from the "Browse the glossary using this index" singleselect
And "//h3[contains(.,'CATEGORYAUTOLINKS')]" "xpath_element" should appear before "//h3[contains(.,'CATEGORYNOLINKS')]" "xpath_element"
And "//h4[contains(.,'EntryCategoryAL')]" "xpath_element" should appear before "//h3[contains(.,'CATEGORYNOLINKS')]" "xpath_element"
And "(//h4[contains(.,'EntryCategoryBoth')])[1]" "xpath_element" should appear before "//h3[contains(.,'CATEGORYNOLINKS')]" "xpath_element"
And "//h3[contains(.,'CATEGORYNOLINKS')]" "xpath_element" should appear before "(//h4[contains(.,'EntryCategoryBoth')])[2]" "xpath_element"
And "//h4[contains(.,'EntryCategoryNL')]" "xpath_element" should appear after "//h3[contains(.,'CATEGORYNOLINKS')]" "xpath_element"
And I should not see "EntryNoCategory"
And I set the field "hook" to "Not categorised"
And I set the field "Categories" to "Not categorised"
And I should see "EntryNoCategory"
And I should not see "EntryCategoryNL"
And I should not see "EntryCategoryAL"
And I should not see "EntryCategoryBoth"
# Check that category is autolinked from the text in the course
And I am on "Course 1" course homepage
And I should see "CategoryAutoLinks"
And I should see "CategoryAutoLinks" in the "a.glossary.autolink" "css_element"
And I should see "CategoryNoLinks"
And "//a[contains(.,'CategoryNoLinks')]" "xpath_element" should not exist
# Delete a category with entries
And I am on the MyGlossary "glossary activity" page
And I select "Browse by category" from the "Browse the glossary using this index" singleselect
And I press "Edit categories"
And I should see "2 Entries" in the "CategoryNoLinks" "table_row"
And I should see "2 Entries" in the "CategoryAutoLinks" "table_row"
And I click on "Delete" "link" in the "CategoryAutoLinks" "table_row"
And I press "Yes"
And I wait to be redirected
And I am on the MyGlossary "glossary activity" page
And I select "Browse by category" from the "Browse the glossary using this index" singleselect
And I should see "EntryCategoryNL"
And I should not see "EntryNoCategory"
And I should not see "EntryCategoryAL"
And I should see "EntryCategoryBoth"
And I set the field "Categories" to "Not categorised"
And I should see "EntryNoCategory"
And I should see "EntryCategoryAL"
And I should not see "EntryCategoryBoth"
@@ -0,0 +1,49 @@
@mod @mod_glossary
Feature: Create a glossary entry.
In order to create glossary entries
As a user
I should be able to enter an entry without using reserved keywords
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 the following "activity" exists:
| activity | glossary |
| course | C1 |
| name | Test glossary |
Scenario: Glossary entry edition of custom tags works as expected
Given I am on the "Test glossary" "glossary activity" page logged in as "teacher1"
When I press "Add entry"
And I set the following fields to these values:
| Concept | Dummy first entry |
| Definition | Dream is the start of a journey |
| Keyword(s) | " |
And I press "Save changes"
Then I should see "One or more keywords contain a special character which cannot be used."
@javascript @_file_upload
Scenario: Create glossary entry with attached file
Given I am on the "Test glossary" "glossary activity" page logged in as student1
# As a student, add a glossary entry with attachment
And I press "Add entry"
And I set the following fields to these values:
| Concept | Entry 1 |
| Definition | Definition of Entry 1 |
| Attachment | mod/glossary/tests/fixtures/musicians.xml |
And I press "Save changes"
# Confirm you can download attachment from student's entry as teacher
When I am on the "Test glossary" "glossary activity" page logged in as teacher1
Then I should see "Entry 1"
And following "musicians.xml" should download a file that:
| Has mimetype | text/xml |
| Contains text in xml element | Paul McCartney |
@@ -0,0 +1,67 @@
@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 the following "activity" exists:
| course | C1 |
| activity | glossary |
| name | Test glossary |
| intro | A glossary about dreams! |
Scenario: Glossary entry edition of custom tags works as expected
Given I am on the "Test glossary" "glossary activity" page logged in as teacher1
And I press "Add 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"
Scenario: Glossary entry edition of standard tags works as expected
Given the following "tags" exist:
| name | isstandard |
| OT1 | 1 |
| OT2 | 1 |
| OT3 | 1 |
And I am on the "Test glossary" "glossary activity" page logged in as teacher1
And I press "Add entry"
And I expand all fieldsets
And I open the autocomplete suggestions list
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"
@@ -0,0 +1,35 @@
@mod @mod_glossary
Feature: A teacher can set whether glossary entries are always editable or not
In order to ensure students think before adding new entries
As a teacher
I need to prevent entries to be always editable
Scenario: Glossary entries are not always editable
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 | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber | editalways |
| glossary | Test glossary name | Test glossary description | C1 | glossary1 | 0 |
And the following config values are set as admin:
| maxeditingtime | 5 |
And I log in as "student1"
And I am on "Course 1" course homepage
And I follow "Test glossary name"
When I add a glossary entry with the following data:
| Concept | Test concept name |
| Definition | Test concept description |
Then "Delete entry: Test concept name" "link" should exist
And "Edit entry: Test concept name" "link" should exist
And I wait "6" seconds
And I reload the page
And "Delete entry: Test concept name" "link" should not exist
And "Edit entry: Test concept name" "link" should not exist
@@ -0,0 +1,80 @@
@mod @mod_glossary
Feature: A teacher can choose whether glossary entries require approval
In order to check entries before they are displayed
As a user
I need to enable entries requiring approval
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
| student2 | Student | 2 | student2@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
And the following "activity" exists:
| activity | glossary |
| course | C1 |
| idnumber | 0001 |
| name | Test glossary name |
| intro | Test glossary entries require approval |
| section | 1 |
| defaultapproval | 0 |
Scenario: Approve and undo approve glossary entries
Given I am on the "Test glossary name" "glossary activity" page logged in as student1
When I add a glossary entry with the following data:
| Concept | Just a test concept |
| Definition | Concept definition |
| Keyword(s) | Black |
And I log out
# Test that students can not see the unapproved entry.
And I am on the "Test glossary name" "glossary activity" page logged in as student2
Then I should see "No entries found in this section"
And I log out
# Approve the entry.
And I am on the "Test glossary name" "glossary activity" page logged in as teacher1
And I follow "Pending approval (1)"
Then I should see "(this entry is currently hidden)"
And I follow "Approve"
And I am on the "Test glossary name" "glossary activity" page
Then I should see "Concept definition"
And I log out
# Check that the entry can now be viewed by students.
And I am on the "Test glossary name" "glossary activity" page logged in as student2
Then I should see "Concept definition"
And I log out
# Undo the approval of the previous entry.
And I am on the "Test glossary name" "glossary activity" page logged in as teacher1
And I follow "Undo approval"
And I log out
# Check that the entry is no longer visible by students.
And I am on the "Test glossary name" "glossary activity" page logged in as student2
Then I should see "No entries found in this section"
@javascript
Scenario: View pending approval glossary items
Given I am on the "Test glossary name" "glossary activity" page logged in as student1
When I add a glossary entry with the following data:
| Concept | Just a test concept |
| Definition | Concept definition |
| Keyword(s) | Black |
| Tags | Test |
And I log out
And I log in as "teacher1"
And I turn editing mode on
And the following config values are set as admin:
| unaddableblocks | | theme_boost|
And I add the "Navigation" block if not present
And I expand "Site pages" node
And I click on "Tags" "link" in the "Navigation" "block"
And I follow "Test"
Then I should see "Glossary entries"
And I should see "Just a test concept"
And I should see "Entry not approved"
@@ -0,0 +1,82 @@
@mod @mod_glossary @core_completion
Feature: View activity completion in the glossary activity
In order to have visibility of glossary completion requirements
As a student
I need to be able to view my glossary completion progress
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Vinnie | Student1 | student1@example.com |
| teacher1 | Darrell | Teacher1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | enablecompletion | showcompletionconditions |
| Course 1 | C1 | 1 | 1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| teacher1 | C1 | editingteacher |
And the following "activity" exists:
| activity | glossary |
| course | C1 |
| name | Music history |
| section | 1 |
And I am on the "Music history" "glossary activity editing" page logged in as teacher1
And I expand all fieldsets
And I set the following fields to these values:
| Aggregate type | Average of ratings |
| scale[modgrade_type] | Point |
| scale[modgrade_point] | 100 |
| Add requirements | 1 |
| View the activity | 1 |
| Receive a grade | 1 |
| Any grade | 1 |
| completionentriesenabled | 1 |
| completionentries | 1 |
And I press "Save and display"
And I log out
Scenario: View automatic completion items as a teacher
Given I am on the "Music history" "glossary activity" page logged in as teacher1
Then "Music history" should have the "View" completion condition
And "Music history" should have the "Make entries: 1" completion condition
And "Music history" should have the "Receive a grade" completion condition
Scenario: View automatic completion items as a student
Given I am on the "Music history" "glossary activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "done"
And the "Make entries: 1" completion condition of "Music history" is displayed as "todo"
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
And I am on the "Music history" "glossary activity" page
And I press "Add entry"
And I set the following fields to these values:
| Concept | Blast beats |
| Definition | Repeated fast tempo hits combining bass, snare and cymbal |
And I press "Save changes"
And the "View" completion condition of "Music history" is displayed as "done"
And the "Make entries: 1" completion condition of "Music history" is displayed as "done"
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
And I log out
And I am on the "Music history" "glossary activity" page logged in as teacher1
And I set the field "rating" to "3"
And I press "Rate"
And I log out
When I am on the "Music history" "glossary activity" page logged in as student1
Then the "View" completion condition of "Music history" is displayed as "done"
And the "Make entries: 1" completion condition of "Music history" is displayed as "done"
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
@javascript
Scenario: Use manual completion
Given I am on the "Music history" "glossary activity editing" page logged in as teacher1
And I expand all fieldsets
And I set the field "Students must manually mark the activity as done" to "1"
And I press "Save and display"
# Teacher view.
And the manual completion button for "Music history" should be disabled
And I log out
# Student view.
When I am on the "Music history" "glossary activity" page logged in as student1
Then the manual completion button of "Music history" is displayed as "Mark as done"
And I toggle the manual completion state of "Music history"
And the manual completion button of "Music history" is displayed as "Done"
@@ -0,0 +1,108 @@
@mod @mod_glossary @core_completion
Feature: Pass grade completion in the glossary activity
In order to have visibility of glossary completion requirements
As a student
I need to be able to view my glossary completion progress
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Vinnie | Student1 | student1@example.com |
| teacher1 | Darrell | Teacher1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | category | enablecompletion |
| Course 1 | C1 | 0 | 1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| teacher1 | C1 | editingteacher |
And the following "activity" exists:
| activity | glossary |
| course | C1 |
| idnumber | mh1 |
| name | Music history |
| section | 1 |
When I am on the "Music history" "glossary activity editing" page logged in as teacher1
And I expand all fieldsets
And I set the following fields to these values:
| Aggregate type | Average of ratings |
| scale[modgrade_type] | Point |
| scale[modgrade_point] | 100 |
| Ratings > Grade to pass | 50 |
| Add requirements | 1 |
| View the activity | 1 |
| Receive a grade | 1 |
| Passing grade | 1 |
| completionentriesenabled | 1 |
| completionentries | 1 |
And I press "Save and display"
And I log out
Scenario: View automatic completion items as a teacher
Given I log in as "teacher1"
And I am on "Course 1" course homepage
When I follow "Music history"
Then "Music history" should have the "View" completion condition
And "Music history" should have the "Make entries: 1" completion condition
And "Music history" should have the "Receive a grade" completion condition
And "Music history" should have the "Receive a passing grade" completion condition
Scenario: View automatic completion items as a failing student
Given I am on the "Music history" "glossary activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "done"
And the "Make entries: 1" completion condition of "Music history" is displayed as "todo"
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
When I am on "Course 1" course homepage
And I follow "Music history"
And I press "Add entry"
And I set the following fields to these values:
| Concept | Blast beats |
| Definition | Repeated fast tempo hits combining bass, snare and cymbal |
And I press "Save changes"
And the "View" completion condition of "Music history" is displayed as "done"
And the "Make entries: 1" completion condition of "Music history" is displayed as "done"
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
And I log out
And I am on the "Music history" "glossary activity" page logged in as teacher1
And I set the field "rating" to "3"
And I press "Rate"
And I log out
When I am on the "Music history" "glossary activity" page logged in as student1
Then the "View" completion condition of "Music history" is displayed as "done"
And the "Make entries: 1" completion condition of "Music history" is displayed as "done"
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
And the "Receive a passing grade" completion condition of "Music history" is displayed as "failed"
Scenario: View automatic completion items as a passing student
Given I am on the "Music history" "glossary activity" page logged in as student1
And the "View" completion condition of "Music history" is displayed as "done"
And the "Make entries: 1" completion condition of "Music history" is displayed as "todo"
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
When I am on "Course 1" course homepage
And I follow "Music history"
And I press "Add entry"
And I set the following fields to these values:
| Concept | Blast beats |
| Definition | Repeated fast tempo hits combining bass, snare and cymbal |
And I press "Save changes"
And the "View" completion condition of "Music history" is displayed as "done"
And the "Make entries: 1" completion condition of "Music history" is displayed as "done"
And the "Receive a grade" completion condition of "Music history" is displayed as "todo"
And the "Receive a passing grade" completion condition of "Music history" is displayed as "todo"
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I follow "Music history"
And I set the field "rating" to "60"
And I press "Rate"
And I log out
When I log in as "student1"
And I am on "Course 1" course homepage
And I follow "Music history"
Then the "View" completion condition of "Music history" is displayed as "done"
And the "Make entries: 1" completion condition of "Music history" is displayed as "done"
And the "Receive a grade" completion condition of "Music history" is displayed as "done"
And the "Receive a passing grade" completion condition of "Music history" is displayed as "done"
@@ -0,0 +1,99 @@
@mod @mod_glossary
Feature: Glossary can be set to various display formats
In order to display different glossary formats
As a teacher
I can set the glossary activity display format
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | One | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
Given the following "activities" exist:
| activity | course | name |
| glossary | C1 | Glossary 1 |
And the following "mod_glossary > entries" exist:
| glossary | concept | definition |
| Glossary 1 | Entry 1 | Entry 1 definition |
| Glossary 1 | Entry 2 | Entry 2 definition |
Scenario: Glossary display format is entry list style
Given I am on the "Glossary 1" "glossary activity editing" page logged in as teacher1
And I set the following fields to these values:
| displayformat | entrylist |
When I press "Save and display"
# Confirm that glossary display format is entry list.
# In this format, the concept definitions are not displayed.
Then I should not see "by Admin User"
And I should not see "Entry 1 definition"
And I should not see "Entry 2 definition"
And ".entrylist" "css_element" should exist
Scenario: Glossary display format is FAQ-style
Given I am on the "Glossary 1" "glossary activity editing" page logged in as teacher1
And I set the following fields to these values:
| displayformat | faq |
When I press "Save and display"
# Confirm that glossary format is FAQ.
# In this format, the words Question and Answer are displayed.
Then I should see "Question:"
And I should see "Answer:"
And ".faq" "css_element" should exist
@_file_upload @javascript
Scenario: Glossary display format is full without author style
Given I am on the "Glossary 1" "glossary activity editing" page logged in as teacher1
And I set the following fields to these values:
| displayformat | fullwithoutauthor |
And I press "Save and display"
And I press "Add entry"
# Add an entry with an attachment.
And I set the following fields to these values:
| Concept | Entry 3 |
| Definition | Entry 3 definition |
| Attachment | lib/tests/fixtures/gd-logo.png |
When I press "Save changes"
# Confirm that glossary format is full without author style.
# In this format, the image link should exist and author's name should not be visible.
Then "gd-logo.png" "link" should exist
And I should not see "by Admin User"
And ".fullwithoutauthor" "css_element" should exist
@_file_upload @javascript
Scenario: Glossary display format is encyclopedia style
Given I am on the "Glossary 1" "glossary activity editing" page logged in as teacher1
And I set the following fields to these values:
| displayformat | encyclopedia |
And I press "Save and display"
And I press "Add entry"
# Add an entry with an attachment.
And I set the following fields to these values:
| Concept | Entry 3 |
| Definition | Entry 3 definition |
| Attachment | lib/tests/fixtures/gd-logo.png |
When I press "Save changes"
# Confirm that glossary format is encyclopedia.
# In this format, the image element should be displayed.
Then "//img[contains(@src, 'gd-logo.png')]" "xpath_element" should exist
And ".encyclopedia" "css_element" should exist
Scenario Outline: Glossary display format can be set to dictionary, continuous and full with author
Given I am on the "Glossary 1" "glossary activity editing" page logged in as teacher1
# Assign the corresponding display format to glossary activity.
And I set the following fields to these values:
| displayformat | <display_format> |
When I press "Save and display"
# Confirm that glossary format is the display format set in the previous step.
Then I should <visibility> "by Admin User"
And ".<display_format>" "css_element" should exist
Examples:
| display_format | visibility |
| dictionary | not see |
| continuous | not see |
| fullwithauthor | see |

Some files were not shown because too many files have changed in this diff Show More