Also content_to_text moved to weblib.
$searchareas = \core_search\manager::get_search_areas_list();
foreach ($searchareas as $areaid => $searcharea) {
list($componentname, $varname) = $searcharea->get_config_var_name();
- $temp->add(new admin_setting_configcheckbox($componentname . '/enable' . $varname, $searcharea->get_visible_name(true),
+ $temp->add(new admin_setting_configcheckbox($componentname . '/' . $varname . '_enabled', $searcharea->get_visible_name(true),
'', 1, 1, 0));
}
$ADMIN->add('searchplugins', $temp);
$string['roletoassign'] = 'Role to assign';
$string['roletooverride'] = 'Role to override';
$string['safeoverridenotice'] = 'Note: Capabilities with higher risks are locked because you are only allowed to override safe capabilities.';
+$string['search:query'] = 'Perform site-wide searches';
$string['selectanotheruser'] = 'Select another user';
$string['selectauser'] = 'Select a user';
$string['selectrole'] = 'Select a role';
return false;
}
- $this->settings->{$setting->name} = $setting;
+ $name = $setting->name;
+ if ($setting->plugin) {
+ $name = $setting->plugin . $name;
+ }
+ $this->settings->{$name} = $setting;
return true;
}
foreach ($searchareas as $areaid => $searcharea) {
list($componentname, $varname) = $searcharea->get_config_var_name();
if (!$anyenabled) {
- $anyenabled = get_config($componentname, 'enable' . $varname);
+ $anyenabled = get_config($componentname, $varname . '_enabled');
}
if (!$anyindexed) {
$anyindexed = get_config($componentname, $varname . '_indexingstart');
// Available areas.
$row = array();
- $url = new moodle_url('/admin/settings.php?section=manageglobalsearch#id_s_mod_assign_enablesearch_activity');
+ $url = new moodle_url('/admin/settings.php?section=manageglobalsearch#admin-searchengine');
$row[0] = '3. ' . html_writer::tag('a', get_string('enablesearchareas', 'admin'),
array('href' => $url));
var windowWidth = $(document).width();
+ // We are only interested in enter and space keys (accessibility).
+ if (ev.type === 'keydown' && ev.keyCode !== 13 && ev.keyCode !== 32) {
+ return;
+ }
+
if (windowWidth <= 767 && (ev.type === 'click' || ev.type === 'keydown')) {
// Move to the search page when using small window sizes as the input requires too much space.
submitForm();
'contextlevel' => CONTEXT_SYSTEM,
'archetypes' => array(
)
+ ),
+
+ // Perform site-wide search queries through the search API.
+ 'moodle/search:query' => array(
+ 'captype' => 'read',
+ 'contextlevel' => CONTEXT_SYSTEM,
+ 'archetypes' => array(
+ 'guest' => CAP_ALLOW,
+ 'user' => CAP_ALLOW,
+ 'student' => CAP_ALLOW,
+ 'teacher' => CAP_ALLOW,
+ 'editingteacher' => CAP_ALLOW,
+ 'manager' => CAP_ALLOW
+ )
)
+
);
}
}
-/**
- * Converts editor text input in different formats to plain text.
- *
- * @param string $content The text as entered by the user
- * @param int $contentformat FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN or FORMAT_MARKDOWN
- * @return string Plain text.
- */
-function editor_input_to_text($content, $contentformat) {
-
- switch ($contentformat) {
- case FORMAT_PLAIN:
- return $content;
- case FORMAT_MARKDOWN:
- $html = markdown_to_html($content);
- return html_to_text($html, 75, false);
- default:
- // FORMAT_HTML and FORMAT_MOODLE.
- return html_to_text($content, 75, false);
- }
-}
-
/**
* Base abstract text editor class.
*
}
// Search.
- if (!empty($CFG->enableglobalsearch)) {
+ if (!empty($CFG->enableglobalsearch) && has_capability('moodle/search:query', $sitecontext)) {
$node = $coursenode->add(get_string('search', 'search'), new moodle_url('/search/index.php'),
self::TYPE_SETTING, null, 'search');
}
// Accessing $CFG directly as using \core_search::is_global_search_enabled would
// result in an extra included file for each site, even the ones where global search
// is disabled.
- if (empty($CFG->enableglobalsearch)) {
+ if (empty($CFG->enableglobalsearch) || !has_capability('moodle/search:query', context_system::instance())) {
return '';
}
$inputattrs = array('type' => 'text', 'name' => 'q', 'placeholder' => get_string('search', 'search'),
'size' => 13, 'tabindex' => -1, 'id' => 'id_q_' . $id);
- $contents = html_writer::tag('label', get_string('search', 'search'),
+ $contents = html_writer::tag('label', get_string('enteryoursearchquery', 'search'),
array('for' => 'id_q_' . $id, 'class' => 'accesshide')) . html_writer::tag('input', '', $inputattrs);
$searchinput = html_writer::tag('form', $contents, $formattrs);
return $result;
}
+/**
+ * Converts content introduced in an editor to plain text.
+ *
+ * @param string $content The text as entered by the user
+ * @param int $contentformat The text format: FORMAT_MOODLE, FORMAT_HTML, FORMAT_PLAIN or FORMAT_MARKDOWN
+ * @return string Plain text.
+ */
+function content_to_text($content, $contentformat) {
+
+ switch ($contentformat) {
+ case FORMAT_PLAIN:
+ return $content;
+ case FORMAT_MARKDOWN:
+ $html = markdown_to_html($content);
+ return html_to_text($html, 75, false);
+ default:
+ // FORMAT_HTML and FORMAT_MOODLE.
+ return html_to_text($content, 75, false);
+ }
+}
+
/**
* This function will highlight search words in a given string
*
// Prepare associative array with data from DB.
$doc = \core_search\document_factory::instance($record->id, $this->componentname, $this->areaname);
$doc->set('title', $record->subject);
- $doc->set('content', editor_input_to_text($record->message, $record->messageformat));
+ $doc->set('content', content_to_text($record->message, $record->messageformat));
$doc->set('contextid', $context->id);
$doc->set('type', \core_search\manager::TYPE_TEXT);
$doc->set('courseid', $record->courseid);
// Enabled by default once global search is enabled.
$this->assertTrue($searcharea->is_enabled());
- set_config('enable' . $varname, false, $componentname);
+ set_config($varname . '_enabled', false, $componentname);
$this->assertFalse($searcharea->is_enabled());
- set_config('enable' . $varname, true, $componentname);
+ set_config($varname . '_enabled', true, $componentname);
$this->assertTrue($searcharea->is_enabled());
}
// Prepare associative array with data from DB.
$doc = \core_search\document_factory::instance($entry->id, $this->componentname, $this->areaname);
$doc->set('title', $entry->concept);
- $doc->set('content', editor_input_to_text($entry->definition, $entry->definitionformat));
+ $doc->set('content', content_to_text($entry->definition, $entry->definitionformat));
$doc->set('contextid', $context->id);
$doc->set('type', \core_search\manager::TYPE_TEXT);
$doc->set('courseid', $entry->course);
// Enabled by default once global search is enabled.
$this->assertTrue($searcharea->is_enabled());
- set_config('enable' . $varname, false, $componentname);
+ set_config($varname . '_enabled', false, $componentname);
$this->assertFalse($searcharea->is_enabled());
- set_config('enable' . $varname, true, $componentname);
+ set_config($varname . '_enabled', true, $componentname);
$this->assertTrue($searcharea->is_enabled());
}
// Prepare associative array with data from DB.
$doc = \core_search\document_factory::instance($record->id, $this->componentname, $this->areaname);
$doc->set('title', $record->name);
- $doc->set('content', editor_input_to_text($record->content, $record->contentformat));
+ $doc->set('content', content_to_text($record->content, $record->contentformat));
$doc->set('contextid', $context->id);
$doc->set('type', \core_search\manager::TYPE_TEXT);
$doc->set('courseid', $record->course);
$doc->set('modified', $record->timemodified);
- $doc->set('description1', editor_input_to_text($record->intro, $record->introformat));
+ $doc->set('description1', content_to_text($record->intro, $record->introformat));
return $doc;
}
*
* It depends on whether it is a moodle subsystem or a plugin as plugin-related config should remain in their own scope.
*
+ * @access private
* @return string Config var path including the plugin (or component) and the varname
*/
public function get_config_var_name() {
return array($this->componentname, 'search_' . $this->areaname);
}
+ /**
+ * Returns all the search area configuration.
+ *
+ * @return array
+ */
+ public function get_config() {
+ list($componentname, $varname) = $this->get_config_var_name();
+
+ $config = [];
+ $settingnames = array('_enabled', '_indexingstart', '_indexingend', '_lastindexrun', '_docsignored', '_docsprocessed', '_recordsprocessed');
+ foreach ($settingnames as $name) {
+ $config[$varname . $name] = get_config($componentname, $varname . $name);
+ }
+
+ return $config;
+ }
+
/**
* Is the search component enabled by the system administrator?
*
*/
public function is_enabled() {
list($componentname, $varname) = $this->get_config_var_name();
- return (bool)get_config($componentname, 'enable' . $varname);
+ return (bool)get_config($componentname, $varname . '_enabled');
}
/**
* Internally it should use \core_search\document to standarise the documents before sending them to the search engine.
*
* Search areas should send plain text to the search engine, use the following function to convert any user
- * input data to plain text: {@link editor_input_to_text}
+ * input data to plain text: {@link content_to_text}
*
* @param \stdClass $record A record containing, at least, the indexed document id and a modified timestamp
* @return \core_search\document
// Prepare associative array with data from DB.
$doc = \core_search\document_factory::instance($record->id, $this->componentname, $this->areaname);
$doc->set('title', $record->name);
- $doc->set('content', editor_input_to_text($record->intro, $record->introformat));
+ $doc->set('content', content_to_text($record->intro, $record->introformat));
$doc->set('contextid', $context->id);
$doc->set('type', \core_search\manager::TYPE_TEXT);
$doc->set('courseid', $record->course);
if ($fielddata['type'] === 'int' || $fielddata['type'] === 'tdate') {
$this->data[$fieldname] = intval($value);
} else {
- $this->data[$fieldname] = trim($value, "\r\n");
+ // Clean up line breaks and extra spaces.
+ $this->data[$fieldname] = preg_replace("/\s+/", ' ', trim($value, "\r\n"));
}
return $this->data[$fieldname];
/**
* Executes the query on the engine.
*
+ * Implementations of this function should check user context array to limit the results to contexts where the
+ * user have access.
+ *
* @param stdClass $filters Query and filters to apply.
* @param array $usercontexts Contexts where the user has access. True if the user can access all contexts.
* @return \core_search\document[] Results or false if no results
// Get the courses where the current user has access.
$courses = enrol_get_my_courses(array('id', 'cacherev'));
- if (isloggedin() || (isguestuser() && !$CFG->forcelogin)) {
- $courses[SITEID] = get_course(SITEID);
- }
+ $courses[SITEID] = get_course(SITEID);
$site = \course_modinfo::instance(SITEID);
foreach ($courses as $course) {
/**
* Returns documents from the engine based on the data provided.
*
+ * This function does not perform any kind of security checking, the caller code
+ * should check that the current user have moodle/search:query capability.
+ *
* It might return the results from the cache instead.
*
* @param stdClass $formdata
}
foreach ($searchareas as $searcharea) {
+ list($componentname, $varname) = $searcharea->get_config_var_name();
+ $config = $searcharea->get_config();
- list($areaid, $varname) = $searcharea->get_config_var_name();
-
- set_config($varname . '_indexingstart', 0, $areaid);
- set_config($varname . '_indexingend', 0, $areaid);
- set_config($varname . '_lastindexrun', 0, $areaid);
- set_config($varname . '_docsignored', 0, $areaid);
- set_config($varname . '_docsprocessed', 0, $areaid);
- set_config($varname . '_recordsprocessed', 0, $areaid);
+ foreach ($config as $key => $value) {
+ // We reset them all but the enable/disabled one.
+ if ($key !== $varname . '_enabled') {
+ set_config($key, 0, $componentname);
+ }
+ }
}
}
+++ /dev/null
-<?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/>.
-
-/**
- * Adds moodle fields to solr schema.
- *
- * Schema REST API write actions are only available from Solr 4.4 onwards.
- *
- * The schema should be managed and mutable to allow this script
- * to add new fields to the schema.
- *
- * @link https://cwiki.apache.org/confluence/display/solr/Managed+Schema+Definition+in+SolrConfig
- * @package search_solr
- * @copyright 2015 David Monllao {@link http://www.davidmonllao.com}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-define('CLI_SCRIPT', true);
-
-require_once(__DIR__ . '/../../../../config.php');
-
-echo get_string('addingfields', 'search_solr') . "\n";
-
-if (!\core_search\manager::is_global_search_enabled()) {
- throw new moodle_exception('globalsearchdisabled', 'search');
-}
-
-if ($CFG->searchengine !== 'solr') {
- throw new moodle_exception('solrnotselected', 'search_solr');
-}
-
-$schema = new \search_solr\schema();
-$schema->setup();
-
-echo get_string('setupok', 'search_solr') . "\n";
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-$string['addingfields'] = 'Adding Moodle fields to the schema';
$string['connectionerror'] = 'The specified Solr server is not available or the specified index does not exist';
$string['errorcreatingschema'] = 'Error creating the Solr schema: {$a}';
$string['errorvalidatingschema'] = 'Error validating Solr schema, field {$a->fieldname} does not exist. Please <a href="{$a->setupurl}">follow this link</a> to setup the fields required by Moodle.';
require_once(__DIR__ . '/../../../config.php');
require_once($CFG->libdir.'/adminlib.php');
+require_login(null, false);
require_capability('moodle/site:config', context_system::instance());
if (!\core_search\manager::is_global_search_enabled()) {
$schema = new \search_solr\schema();
$schema->setup();
-$url = new moodle_url('/admin/settings.php', array('section' => 'searchsolr'));
+$url = new moodle_url('/admin/settings.php', array('section' => 'manageglobalsearch'));
redirect($url, get_string('setupok', 'search_solr'), 4);
$areaid = optional_param('areaid', false, PARAM_ALPHANUMEXT);
// Moving timestart and timeend further down as they might come as an array if they come from the form.
+$context = context_system::instance();
$pagetitle = get_string('globalsearch', 'search');
-$PAGE->set_context(context_system::instance());
+$PAGE->set_context($context);
$PAGE->set_pagelayout('standard');
$PAGE->set_title($pagetitle);
$PAGE->set_heading($pagetitle);
require_login();
}
+require_capability('moodle/search:query', $context);
+
$searchrenderer = $PAGE->get_renderer('core_search');
if (\core_search\manager::is_global_search_enabled() === false) {
$this->assertArrayHasKey($this->forumpostareaid, \core_search\manager::get_search_areas_list(true));
list($componentname, $varname) = $searcharea->get_config_var_name();
- set_config('enable' . $varname, false, $componentname);
+ set_config($varname . '_enabled', false, $componentname);
\core_search\manager::clear_static();
$this->assertArrayNotHasKey('mod_forum', \core_search\manager::get_search_areas_list(true));
- set_config('enable' . $varname, true, $componentname);
+ set_config($varname . '_enabled', true, $componentname);
// Although the result is wrong, we want to check that \core_search\manager::get_search_areas_list returns cached results.
$this->assertArrayNotHasKey($this->forumpostareaid, \core_search\manager::get_search_areas_list(true));
$this->assertContains($fakeareaid . ' search area is not available.', $ex->getMessage());
}
+ // We clean it all but enabled components.
$search->reset_config($this->forumpostareaid);
+ $this->assertEquals(1, get_config($componentname, $varname . '_enabled'));
$this->assertEquals(0, get_config($componentname, $varname . '_indexingstart'));
$this->assertEquals(0, get_config($componentname, $varname . '_indexingend'));
$this->assertEquals(0, get_config($componentname, $varname . '_lastindexrun'));
-
// No caching.
$configs = $search->get_areas_config(array($this->forumpostareaid => $searcharea));
$this->assertEquals(0, $configs[$this->forumpostareaid]->indexingstart);
$this->assertEquals(0, get_config($componentname, $varname . '_indexingstart'));
$this->assertEquals(0, get_config($componentname, $varname . '_indexingend'));
$this->assertEquals(0, get_config($componentname, $varname . '_lastindexrun'));
-
// No caching.
$configs = $search->get_areas_config(array($this->forumpostareaid => $searcharea));
$this->assertEquals(0, $configs[$this->forumpostareaid]->indexingstart);