MDL-31989 search: get_config method to search areas
authorDavid Monllao <davidm@moodle.com>
Tue, 23 Feb 2016 02:44:20 +0000 (10:44 +0800)
committerDan Poltawski <dan@moodle.com>
Tue, 23 Feb 2016 10:47:59 +0000 (10:47 +0000)
Also content_to_text moved to weblib.

25 files changed:
admin/settings/plugins.php
lang/en/role.php
lib/adminlib.php
lib/amd/build/search-input.min.js
lib/amd/src/search-input.js
lib/db/access.php
lib/editorlib.php
lib/navigationlib.php
lib/outputrenderers.php
lib/weblib.php
mod/forum/classes/search/post.php
mod/forum/tests/search_test.php
mod/glossary/classes/search/entry.php
mod/glossary/tests/search_test.php
mod/page/classes/search/activity.php
search/classes/area/base.php
search/classes/area/base_activity.php
search/classes/document.php
search/classes/engine.php
search/classes/manager.php
search/engine/solr/cli/setup_schema.php [deleted file]
search/engine/solr/lang/en/search_solr.php
search/engine/solr/setup_schema.php
search/index.php
search/tests/manager_test.php

index f9c169c..089961b 100644 (file)
@@ -489,7 +489,7 @@ $temp->add(new admin_setting_heading('searchareasheading', new lang_string('avai
 $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);
index e7eb45e..d3475e7 100644 (file)
@@ -345,6 +345,7 @@ $string['role:switchroles'] = 'Switch to other roles';
 $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';
index 9678c18..eedbcea 100644 (file)
@@ -1458,7 +1458,11 @@ class admin_settingpage implements part_of_admin_tree {
             return false;
         }
 
-        $this->settings->{$setting->name} = $setting;
+        $name = $setting->name;
+        if ($setting->plugin) {
+            $name = $setting->plugin . $name;
+        }
+        $this->settings->{$name} = $setting;
         return true;
     }
 
@@ -9333,7 +9337,7 @@ class admin_setting_searchsetupinfo extends admin_setting {
         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');
@@ -9383,7 +9387,7 @@ class admin_setting_searchsetupinfo extends admin_setting {
 
         // 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));
 
index afcd007..3a10548 100644 (file)
Binary files a/lib/amd/build/search-input.min.js and b/lib/amd/build/search-input.min.js differ
index 153d4fd..85f9bb1 100644 (file)
@@ -59,6 +59,11 @@ define(['jquery'], function($) {
 
         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();
index ccc30c9..729267e 100644 (file)
@@ -2057,5 +2057,20 @@ $capabilities = array(
         '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
+        )
     )
+
 );
index 891eadc..383f2bf 100644 (file)
@@ -169,27 +169,6 @@ function editors_head_setup() {
     }
 }
 
-/**
- * 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.
  *
index 7e63f22..b593327 100644 (file)
@@ -2644,7 +2644,7 @@ class global_navigation extends navigation_node {
         }
 
         // 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');
         }
index b950a0d..066f82e 100644 (file)
@@ -3133,7 +3133,7 @@ EOD;
         // 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 '';
         }
 
@@ -3153,7 +3153,7 @@ EOD;
         $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);
 
index 8f3c333..f3ed1ef 100644 (file)
@@ -1914,6 +1914,27 @@ function html_to_text($html, $width = 75, $dolinks = true) {
     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
  *
index 106a843..3efa21e 100644 (file)
@@ -94,7 +94,7 @@ class post extends \core_search\area\base_mod {
         // 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);
index 57299a8..6dc5033 100644 (file)
@@ -68,10 +68,10 @@ class mod_forum_search_testcase extends advanced_testcase {
         // 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());
     }
 
index f1f3d63..4d1f082 100644 (file)
@@ -90,7 +90,7 @@ class entry extends \core_search\area\base_mod {
         // 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);
index 4b080bd..5263eeb 100644 (file)
@@ -67,10 +67,10 @@ class mod_glossary_search_testcase extends advanced_testcase {
         // 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());
     }
 
index 9db4f2d..56b8bae 100644 (file)
@@ -64,12 +64,12 @@ class activity extends \core_search\area\base_activity {
         // 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;
     }
index 7617d2f..0976bcf 100644 (file)
@@ -144,6 +144,7 @@ abstract class base {
      *
      * 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() {
@@ -157,6 +158,23 @@ abstract class base {
         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?
      *
@@ -164,7 +182,7 @@ abstract class base {
      */
     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');
     }
 
     /**
@@ -193,7 +211,7 @@ abstract class base {
      * 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
index c210094..0fdc839 100644 (file)
@@ -89,7 +89,7 @@ abstract class base_activity extends base_mod {
         // 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);
index dc45a1b..7a0451e 100644 (file)
@@ -209,7 +209,8 @@ class document implements \renderable, \templatable {
         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];
index e6569e8..bd77769 100644 (file)
@@ -299,6 +299,9 @@ abstract class engine {
     /**
      * 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
index 9ea9a73..3f8f7da 100644 (file)
@@ -347,9 +347,7 @@ class manager {
 
         // 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) {
 
@@ -391,6 +389,9 @@ class manager {
     /**
      * 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
@@ -579,15 +580,15 @@ class manager {
         }
 
         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);
+                }
+            }
         }
     }
 
diff --git a/search/engine/solr/cli/setup_schema.php b/search/engine/solr/cli/setup_schema.php
deleted file mode 100644 (file)
index b6697f3..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-<?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";
index 2ee4ccd..9869aa5 100644 (file)
@@ -22,7 +22,6 @@
  * @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.';
index 3c9cf3a..5ed2872 100644 (file)
@@ -31,6 +31,7 @@
 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()) {
@@ -44,5 +45,5 @@ if ($CFG->searchengine !== 'solr') {
 $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);
index c707fa9..233ddda 100644 (file)
@@ -30,8 +30,9 @@ $title = optional_param('title', '', PARAM_NOTAGS);
 $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);
@@ -40,6 +41,8 @@ if (!empty($CFG->forcelogin)) {
     require_login();
 }
 
+require_capability('moodle/search:query', $context);
+
 $searchrenderer = $PAGE->get_renderer('core_search');
 
 if (\core_search\manager::is_global_search_enabled() === false) {
index 787740a..36fbde4 100644 (file)
@@ -78,12 +78,12 @@ class search_manager_testcase extends advanced_testcase {
         $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));
@@ -122,11 +122,12 @@ class search_manager_testcase extends advanced_testcase {
             $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);
@@ -140,7 +141,6 @@ class search_manager_testcase extends advanced_testcase {
         $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);