MDL-62217 search: Privacy providers
authorDavid Monllao <davidm@moodle.com>
Wed, 2 May 2018 14:42:40 +0000 (16:42 +0200)
committerDavid Monllao <davidm@moodle.com>
Wed, 9 May 2018 08:56:02 +0000 (10:56 +0200)
lang/en/search.php
search/classes/privacy/provider.php [new file with mode: 0644]
search/engine/simpledb/classes/privacy/provider.php [new file with mode: 0644]
search/engine/simpledb/lang/en/search_simpledb.php
search/engine/simpledb/tests/privacy_test.php [new file with mode: 0644]
search/engine/solr/classes/privacy/provider.php [new file with mode: 0644]
search/engine/solr/lang/en/search_solr.php
search/engine/solr/tests/privacy_test.php [new file with mode: 0644]
search/tests/fixtures/mock_search_area.php

index ea13271..db7c5d6 100644 (file)
@@ -92,6 +92,7 @@ $string['order_relevance'] = 'Most relevant results first';
 $string['priority'] = 'Priority';
 $string['priority_reindexing'] = 'Reindexing';
 $string['priority_normal'] = 'Normal';
+$string['privacy:metadata'] = 'The search subsystem does not store any personal data.';
 $string['progress'] = 'Progress';
 $string['queryerror'] = 'The query you provided could not be parsed by the search engine: {$a}';
 $string['queueheading'] = 'Additional indexing queue ({$a} items)';
diff --git a/search/classes/privacy/provider.php b/search/classes/privacy/provider.php
new file mode 100644 (file)
index 0000000..790f4fb
--- /dev/null
@@ -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/>.
+
+/**
+ * Privacy Subsystem implementation for core_search.
+ *
+ * @package    core_search
+ * @copyright  2018 David Monllao
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_search\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy Subsystem for core_search implementing null_provider.
+ *
+ * @copyright  2018 David Monllao
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
diff --git a/search/engine/simpledb/classes/privacy/provider.php b/search/engine/simpledb/classes/privacy/provider.php
new file mode 100644 (file)
index 0000000..05b09b9
--- /dev/null
@@ -0,0 +1,162 @@
+<?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 class for requesting user data.
+ *
+ * @package    search_simpledb
+ * @copyright  2018 David Monllao
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace search_simpledb\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+use core_privacy\local\metadata\collection;
+use core_privacy\local\request\writer;
+use core_privacy\local\request\transform;
+use core_privacy\local\request\contextlist;
+use core_privacy\local\request\approved_contextlist;
+
+/**
+ * Provider for the search_simpledb plugin.
+ *
+ * @copyright  2018 David Monllao
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements
+        \core_privacy\local\metadata\provider,
+        \core_privacy\local\request\plugin\provider {
+
+    /**
+     * Returns meta data about this system.
+     *
+     * @param   collection $collection The initialised collection to add items to.
+     * @return  collection     A listing of user data stored through this system.
+     */
+    public static function get_metadata(collection $collection) : collection {
+        $collection->add_database_table(
+            'search_simpledb_index',
+            [
+                'docid' => 'privacy:metadata:index:docid',
+                'itemid' => 'privacy:metadata:index:itemid',
+                'title' => 'privacy:metadata:index:title',
+                'content' => 'privacy:metadata:index:content',
+                'contextid' => 'privacy:metadata:index:contextid',
+                'areaid' => 'privacy:metadata:index:areaid',
+                'type' => 'privacy:metadata:index:type',
+                'courseid' => 'privacy:metadata:index:courseid',
+                'owneruserid' => 'privacy:metadata:index:owneruserid',
+                'modified' => 'privacy:metadata:index:modified',
+                'userid' => 'privacy:metadata:index:userid',
+                'description1' => 'privacy:metadata:index:description1',
+                'description2' => 'privacy:metadata:index:description2',
+            ],
+            'privacy:metadata:index'
+        );
+        return $collection;
+    }
+
+    /**
+     * Get the list of contexts that contain user information for the specified user.
+     *
+     * @param   int         $userid     The user to search.
+     * @return  contextlist   $contextlist  The contextlist containing the list of contexts used in this plugin.
+     */
+    public static function get_contexts_for_userid(int $userid) : contextlist {
+        $contextlist = new \core_privacy\local\request\contextlist();
+
+        $params = ['userid' => $userid, 'owneruserid' => $userid];
+        $sql = "SELECT DISTINCT contextid FROM {search_simpledb_index} WHERE (userid = :userid OR owneruserid = :owneruserid)";
+        $contextlist->add_from_sql($sql, $params);
+
+        return $contextlist;
+    }
+
+    /**
+     * Export all user data for the specified user, in the specified contexts.
+     *
+     * @param   approved_contextlist    $contextlist    The approved contexts to export information for.
+     */
+    public static function export_user_data(approved_contextlist $contextlist) {
+        global $DB;
+
+        // Plugin search_simpledb uses the default document object (core_search\document) which uses FORMAT_PLAIN.
+        $textformat = FORMAT_PLAIN;
+
+        $userid = $contextlist->get_user()->id;
+
+        $ctxfields = \context_helper::get_preload_record_columns_sql('ctx');
+        list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
+        $sql = "SELECT ssi.*, $ctxfields FROM {search_simpledb_index} ssi
+                  JOIN {context} ctx ON ctx.id = ssi.contextid
+                 WHERE ssi.contextid $contextsql AND (ssi.userid = :userid OR ssi.owneruserid = :owneruserid)";
+        $params = ['userid' => $userid, 'owneruserid' => $userid] + $contextparams;
+
+        $records = $DB->get_recordset_sql($sql, $params);
+        foreach ($records as $record) {
+
+            \context_helper::preload_from_record($record);
+            $context = \context::instance_by_id($record->contextid);
+            $document = (object)[
+                'title' => format_string($record->title, true, ['context' => $context]),
+                'content' => format_text($record->content, $textformat, ['context' => $context]),
+                'description1' => format_text($record->description1, $textformat, ['context' => $context]),
+                'description2' => format_text($record->description2, $textformat, ['context' => $context]),
+                'context' => $context->get_context_name(true, true),
+                'modified' => transform::datetime($record->modified),
+
+            ];
+
+            $path = [get_string('search', 'search'), $record->docid];
+            writer::with_context($context)->export_data($path, $document);
+        }
+        $records->close();
+    }
+
+    /**
+     * Delete all data for all users in the specified context.
+     *
+     * @param   context                 $context   The specific context to delete data for.
+     */
+    public static function delete_data_for_all_users_in_context(\context $context) {
+        global $DB;
+
+        $DB->delete_records('search_simpledb_index', ['contextid' => $context->id]);
+
+        if ($context->contextlevel == CONTEXT_USER) {
+            $select = "userid = :userid OR owneruserid = :owneruserid";
+            $params = ['userid' => $context->instanceid, 'owneruserid' => $context->instanceid];
+            $DB->delete_records_select('search_simpledb_index', $select, $params);
+        }
+    }
+
+    /**
+     * Delete all user data for the specified user, in the specified contexts.
+     *
+     * @param   approved_contextlist    $contextlist    The approved contexts and user information to delete information for.
+     */
+    public static function delete_data_for_user(approved_contextlist $contextlist) {
+        global $DB;
+
+        $userid = $contextlist->get_user()->id;
+
+        list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
+        $select = "contextid $contextsql AND (userid = :userid OR owneruserid = :owneruserid)";
+        $params = ['userid' => $userid, 'owneruserid' => $userid] + $contextparams;
+        $DB->delete_records_select('search_simpledb_index', $select, $params);
+    }
+}
index 5063a88..b363e83 100644 (file)
  */
 
 $string['pluginname'] = 'Simple search';
+$string['privacy:metadata:index'] = 'Indexed contents';
+$string['privacy:metadata:index:docid'] = 'Document id (unique)';
+$string['privacy:metadata:index:itemid'] = 'Item identifier (in search area scope)';
+$string['privacy:metadata:index:title'] = 'Title';
+$string['privacy:metadata:index:content'] = 'Contents';
+$string['privacy:metadata:index:contextid'] = 'Document context id';
+$string['privacy:metadata:index:areaid'] = 'Search area id';
+$string['privacy:metadata:index:type'] = 'Document type';
+$string['privacy:metadata:index:courseid'] = 'Course id';
+$string['privacy:metadata:index:owneruserid'] = 'Document owner user id';
+$string['privacy:metadata:index:modified'] = 'Last modification time';
+$string['privacy:metadata:index:userid'] = 'Document user id';
+$string['privacy:metadata:index:description1'] = 'Extra description field';
+$string['privacy:metadata:index:description2'] = 'Extra description field';
 $string['searchinfo'] = 'Search queries';
 $string['searchinfo_help'] = 'Enter the search query.';
diff --git a/search/engine/simpledb/tests/privacy_test.php b/search/engine/simpledb/tests/privacy_test.php
new file mode 100644 (file)
index 0000000..28b6fe2
--- /dev/null
@@ -0,0 +1,194 @@
+<?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/>.
+
+/**
+ * Unit tests for privacy.
+ *
+ * @package   search_simpledb
+ * @copyright 2018 David MonllaĆ³ {@link http://www.davidmonllao.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+use \search_simpledb\privacy\provider;
+use core_privacy\local\request\transform;
+use core_privacy\local\request\writer;
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/search/tests/fixtures/testable_core_search.php');
+require_once($CFG->dirroot . '/search/tests/fixtures/mock_search_area.php');
+
+/**
+ * Unit tests for privacy.
+ *
+ * @package   search_simpledb
+ * @copyright 2018 David MonllaĆ³ {@link http://www.davidmonllao.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class privacy_model_testcase extends \core_privacy\tests\provider_testcase {
+
+    public function setUp() {
+        global $DB;
+
+        if ($this->requires_manual_index_update()) {
+            // We need to update fulltext index manually, which requires an alter table statement.
+            $this->preventResetByRollback();
+        }
+
+        $this->resetAfterTest();
+        set_config('enableglobalsearch', true);
+
+        // Inject search_simpledb engine into the testable core search as we need to add the mock
+        // search component to it.
+
+        $this->engine = new \search_simpledb\engine();
+        $this->search = testable_core_search::instance($this->engine);
+        $areaid = \core_search\manager::generate_areaid('core_mocksearch', 'mock_search_area');
+        $this->search->add_search_area($areaid, new core_mocksearch\search\mock_search_area());
+
+        $this->generator = self::getDataGenerator()->get_plugin_generator('core_search');
+        $this->generator->setup();
+
+        $this->c1 = $this->getDataGenerator()->create_course();
+        $this->c2 = $this->getDataGenerator()->create_course();
+
+        $this->c1context = \context_course::instance($this->c1->id);
+        $this->c2context = \context_course::instance($this->c2->id);
+
+        $this->u1 = $this->getDataGenerator()->create_user();
+        $this->u2 = $this->getDataGenerator()->create_user();
+
+        $this->getDataGenerator()->enrol_user($this->u1->id, $this->c1->id, 'student');
+        $this->getDataGenerator()->enrol_user($this->u1->id, $this->c2->id, 'student');
+        $this->getDataGenerator()->enrol_user($this->u2->id, $this->c1->id, 'student');
+        $this->getDataGenerator()->enrol_user($this->u2->id, $this->c2->id, 'student');
+
+        $record = (object)[
+            'userid' => $this->u1->id,
+            'contextid' => $this->c1context->id,
+            'title' => 'vi',
+            'content' => 'va',
+            'description1' => 'san',
+            'description2' => 'jose'
+        ];
+        $this->generator->create_record($record);
+        $this->generator->create_record((object)['userid' => $this->u1->id, 'contextid' => $this->c2context->id]);
+        $this->generator->create_record((object)['userid' => $this->u2->id, 'contextid' => $this->c2context->id]);
+        $this->generator->create_record((object)['userid' => $this->u2->id, 'contextid' => $this->c1context->id]);
+        $this->generator->create_record((object)['owneruserid' => $this->u1->id, 'contextid' => $this->c1context->id]);
+        $this->generator->create_record((object)['owneruserid' => $this->u1->id, 'contextid' => $this->c2context->id]);
+        $this->generator->create_record((object)['owneruserid' => $this->u2->id, 'contextid' => $this->c1context->id]);
+        $this->generator->create_record((object)['owneruserid' => $this->u2->id, 'contextid' => $this->c2context->id]);
+        $this->search->index();
+
+        $this->setAdminUser();
+    }
+
+    /**
+     * tearDown
+     *
+     * @return void
+     */
+    public function tearDown() {
+        // For unit tests before PHP 7, teardown is called even on skip. So only do our teardown if we did setup.
+        if ($this->generator) {
+            // Moodle DML freaks out if we don't teardown the temp table after each run.
+            $this->generator->teardown();
+            $this->generator = null;
+        }
+    }
+
+    /**
+     * Test export user data.
+     *
+     * @return null
+     */
+    public function test_export_user_data() {
+        global $DB;
+
+        $contextlist = new \core_privacy\local\request\approved_contextlist($this->u1, 'search_simpledb',
+                                                                            [$this->c1context->id]);
+        provider::export_user_data($contextlist);
+        $writer = \core_privacy\local\request\writer::with_context($this->c1context);
+        $this->assertTrue($writer->has_any_data());
+        $u1c1 = $DB->get_record('search_simpledb_index', ['userid' => $this->u1->id, 'contextid' => $this->c1context->id]);
+        $data = $writer->get_data([get_string('search', 'search'), $u1c1->docid]);
+
+        $this->assertEquals($this->c1context->get_context_name(true, true), $data->context);
+        $this->assertEquals('vi', $data->title);
+        $this->assertEquals('va', $data->content);
+        $this->assertEquals('san', $data->description1);
+        $this->assertEquals('jose', $data->description2);
+    }
+
+    /**
+     * Test delete search for context.
+     *
+     * @return null
+     */
+    public function test_delete_data_for_all_users() {
+        global $DB;
+
+        $this->assertEquals(8, $DB->count_records('search_simpledb_index'));
+
+        provider::delete_data_for_all_users_in_context($this->c1context);
+        $this->assertEquals(0, $DB->count_records('search_simpledb_index', ['contextid' => $this->c1context->id]));
+        $this->assertEquals(4, $DB->count_records('search_simpledb_index'));
+
+        $u2context = \context_user::instance($this->u2->id);
+        provider::delete_data_for_all_users_in_context($u2context);
+        $this->assertEquals(0, $DB->count_records('search_simpledb_index', ['contextid' => $u2context->id]));
+        $this->assertEquals(2, $DB->count_records('search_simpledb_index'));
+    }
+
+    /**
+     * Test delete search for user.
+     *
+     * @return null
+     */
+    public function test_delete_data_for_user() {
+        global $DB;
+
+        $contextlist = new \core_privacy\local\request\approved_contextlist($this->u1, 'search_simpledb',
+                                                                            [$this->c1context->id]);
+        provider::delete_data_for_user($contextlist);
+        $select = 'contextid = :contextid AND (owneruserid = :owneruserid OR userid = :userid)';
+        $params = ['contextid' => $this->c1context->id, 'owneruserid' => $this->u1->id, 'userid' => $this->u1->id];
+        $this->assertEquals(0, $DB->count_records_select('search_simpledb_index', $select, $params));
+        $this->assertEquals(2, $DB->count_records('search_simpledb_index', ['contextid' => $this->c1context->id]));
+        $this->assertEquals(6, $DB->count_records('search_simpledb_index'));
+
+        $contextlist = new \core_privacy\local\request\approved_contextlist($this->u2, 'search_simpledb',
+                                                                            [$this->c2context->id]);
+        provider::delete_data_for_user($contextlist);
+        $select = 'contextid = :contextid AND (owneruserid = :owneruserid OR userid = :userid)';
+        $params = ['contextid' => $this->c2context->id, 'owneruserid' => $this->u2->id, 'userid' => $this->u2->id];
+        $this->assertEquals(0, $DB->count_records_select('search_simpledb_index', $select, $params));
+        $this->assertEquals(2, $DB->count_records('search_simpledb_index', ['contextid' => $this->c2context->id]));
+        $this->assertEquals(4, $DB->count_records('search_simpledb_index'));
+    }
+
+    /**
+     * Mssql with fulltext support requires manual updates.
+     *
+     * @return bool
+     */
+    private function requires_manual_index_update() {
+        global $DB;
+        return ($DB->get_dbfamily() === 'mssql' && $DB->is_fulltext_search_supported());
+    }
+}
diff --git a/search/engine/solr/classes/privacy/provider.php b/search/engine/solr/classes/privacy/provider.php
new file mode 100644 (file)
index 0000000..547e51f
--- /dev/null
@@ -0,0 +1,51 @@
+<?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 class for requesting user data.
+ *
+ * @package    search_solr
+ * @copyright  2018 David Monllao
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace search_solr\privacy;
+
+defined('MOODLE_INTERNAL') || die();
+
+use core_privacy\local\metadata\collection;
+
+/**
+ * Provider for the search_solr plugin.
+ *
+ * @copyright  2018 David Monllao
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements
+    // This search engine plugin does not store any data itself.
+    // It has no database tables, and it purely acts as a conduit, sending data externally.
+    \core_privacy\local\metadata\provider {
+
+    /**
+     * Returns meta data about this system.
+     *
+     * @param   collection $collection The initialised collection to add items to.
+     * @return  collection     A listing of user data stored through this system.
+     */
+    public static function get_metadata(collection $collection) : collection {
+        return $collection->add_external_location_link('solr', ['data' => 'privacy:metadata:data'],
+                                                       'privacy:metadata');
+    }
+}
index e87576c..d1bfd36 100644 (file)
@@ -38,6 +38,8 @@ $string['missingconfig'] = 'Your Apache Solr server is not yet configured in Moo
 $string['multivaluedfield'] = 'Field "{$a}" returned an array instead of a scalar. Please delete the current index, create a new one and run setup_schema.php before indexing data in Solr.';
 $string['nodatafromserver'] = 'No data from server';
 $string['pluginname'] = 'Solr';
+$string['privacy:metadata'] = 'This plugin sends data externally to a linked Solr search engine. It does not store data locally.';
+$string['privacy:metadata:data'] = 'Personal data passed through from the search subsystem.';
 $string['schemafieldautocreated'] = 'Field "{$a}" already exists in Solr schema. You probably forgot to run this script before indexing data and fields were autocreated by Solr. Please delete the current index, create a new one and run setup_schema.php again before indexing data in Solr.';
 $string['schemasetupfromsolr5'] = 'Your Solr server version is lower than 5.0. This script can only set your schema if your Solr version is 5.0 or higher. You need to manually set the fields in your schema according to \\search_solr\\document::get_default_fields_definition().';
 $string['searchinfo'] = 'Search queries';
diff --git a/search/engine/solr/tests/privacy_test.php b/search/engine/solr/tests/privacy_test.php
new file mode 100644 (file)
index 0000000..ad90b57
--- /dev/null
@@ -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/>.
+
+/**
+ * Privacy provider tests.
+ *
+ * @package    search_solr
+ * @copyright  2018 David Monllao
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Privacy provider tests class.
+ *
+ * @copyright  2018 David Monllao
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class search_solr_privacy_test extends \core_privacy\tests\provider_testcase {
+
+    /**
+     *  Verify that a collection of metadata is returned for this component and that it just links to an external location.
+     */
+    public function test_get_metadata() {
+        $collection = new \core_privacy\local\metadata\collection('search_solr');
+        $collection = \search_solr\privacy\provider::get_metadata($collection);
+        $this->assertNotEmpty($collection);
+        $items = $collection->get_collection();
+        $this->assertEquals(1, count($items));
+        $this->assertInstanceOf(\core_privacy\local\metadata\types\external_location::class, $items[0]);
+    }
+}
index c1a1025..cdedcd8 100644 (file)
@@ -82,7 +82,7 @@ class mock_search_area extends \core_search\base {
         $doc->set('title', $info->title);
         $doc->set('content', $info->content);
         $doc->set('description1', $info->description1);
-        $doc->set('description1', $info->description2);
+        $doc->set('description2', $info->description2);
         $doc->set('contextid', $info->contextid);
         $doc->set('courseid', $info->courseid);
         $doc->set('userid', $info->userid);