Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: integrated moodleoverflow into the global search #62

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions classes/search/moodleoverflowposts.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
<?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 api for moodleoverflowposts
* Copyright 2020 Robin Tschudi
*/

namespace mod_moodleoverflow\search;
use core_search\document;
defined('MOODLE_INTERNAL') || die();
require_once(dirname(__FILE__) . '/../../locallib.php');

class moodleoverflowposts extends \core_search\base_mod {

/**
* @var array Internal quick static cache.
*/
protected $postsdata = array();
protected $moodleoverflows = array();
protected $discussions = array();

protected static $levels = [CONTEXT_MODULE];

public function uses_file_indexing() {
return false;
}

public function get_document($record, $options = array()) {
try {
$cm = $this->get_cm('moodleoverflow', $record->moodleoverflowid, $record->course);
$context = \context_module::instance($cm->id);
} catch (\dml_missing_record_exception $ex) {
debugging('Error retrieving ' . $this->areaid . ' ' . $record->id . ' document, not all required data is available: ' .
$ex->getMessage(), DEBUG_DEVELOPER);
return false;
} catch (\dml_exception $ex) {
debugging('Error retrieving ' . $this->areaid . ' ' . $record->id . ' document: ' . $ex->getMessage(), DEBUG_DEVELOPER);
return false;
}

$doc = \core_search\document_factory::instance($record->id, $this->componentname, $this->areaname);

$doc->set('title', content_to_text($record->title, true));
$doc->set('content', content_to_text($record->message, FORMAT_HTML));
$doc->set('contextid', $context->id);
$doc->set('type', \core_search\manager::TYPE_TEXT);
$doc->set('courseid', $record->course);
$doc->set('modified', $record->modified);
$doc->set('userid', $record->userid);
$doc->set('owneruserid', \core_search\manager::NO_OWNER_ID);
$postdata[$record->id[0]] = array('discussionid' => $record->discussion, 'moodleoverflowid' => $record->moodleoverflowid);
if (isset($options['lastindexedtime']) && ($options['lastindexedtime'] < $record->created)) {
// If the document was created after the last index time, it must be new.
$doc->set_is_new(true);
}

return $doc;
}

private function get_discussion_from_id($discussionid) {
global $DB;
if (isset($this->discussions[$discussionid])) {
return $this->discussions[$discussionid];
} else {
if (!$discussion = $DB->get_record('moodleoverflow_discussions', array('id' => $discussionid))) {
return false;
}
$this->discussions[$discussionid] = $discussion;
return $discussion;
}
}

private function get_moodleoverflow_from_id($moodleoverflowid) {
global $DB;
if (isset($this->moodleoverflows[$moodleoverflowid])) {
return $this->moodleoverflows[$moodleoverflowid];
} else {
if (!$moodleoverflow = $DB->get_record('moodleoverflow', array('id' => $moodleoverflowid))) {
return false;
}
$this->moodleoverflows[$moodleoverflowid] = $moodleoverflow;
return $moodleoverflow;
}
}

public function check_access($id) {
try {
$post = moodleoverflow_get_post_full($id);
if (!$post) {
return \core_search\manager::ACCESS_DELETED;
}
if (!$discussion = $this->get_discussion_from_id($post->discussion)) {
return \core_search\manager::ACCESS_DELETED;
}
if (!$moodleoverflow = $this->get_moodleoverflow_from_id($post->moodleoverflow)) {
return \core_search\manager::ACCESS_DELETED;
}
$context = moodleoverflow_get_context($post->moodleoverflow);
} catch (\dml_missing_record_exception $ex) {
return \core_search\manager::ACCESS_DELETED;
} catch (\dml_exception $ex) {
return \core_search\manager::ACCESS_DENIED;
}
if (moodleoverflow_user_can_see_discussion($moodleoverflow, $discussion, $context)) {
return \core_search\manager::ACCESS_GRANTED;
}
return \core_search\manager::ACCESS_DENIED;
}

public function get_discussionid_for_document(document $doc) {
global $DB;
$postid = $doc->get('itemid');
if (isset($this->postsdata[$postid]) && isset($this->postsdata[$postid]['discussionid'])) {
return $this->postsdata[$postid]['discussionid'];
} else {
$discussionid = $DB->get_field('moodleoverflow_posts', 'discussion', array('id' => $postid));
if (!isset($this->postsdata[$postid])) {
$this->postsdata[$postid] = array();
}
$this->postsdata[$postid]['discussionid'] = $discussionid;
return $discussionid;
}
}

public function get_moodleoverflowid_for_document(document $doc) {
global $DB;
$discussionid = $this->get_discussionid_for_document($doc);
$postid = $doc->get('itemid');
if (isset($this->postsdata[$postid]) && isset($this->postsdata[$postid]["moodleoverflowid"])) {
return $this->postsdata[$postid]["moodleoverflowid"];
} else {
$moodleoverflowid = $DB->get_field('moodleoverflow_discussions', 'moodleoverflow', array('id' => $discussionid));
if (!isset($this->postsdata[$postid])) {
$this->postsdata[$postid] = array();
}
$this->postsdata[$postid]['moodleoverflowid'] = $moodleoverflowid;
return $moodleoverflowid;
}
}

public function get_doc_url(document $doc) {
return new \moodle_url('/mod/moodleoverflow/discussion.php', array('d' => $this->get_discussionid_for_document($doc)),
"p" . $doc->get('itemid'));
}

public function get_context_url(document $doc) {
return new \moodle_url('/mod/moodleoverflow/view.php', array('m' => $this->get_moodleoverflowid_for_document($doc)));
}

public function get_document_recordset($modifiedfrom = 0, \context $context = null) {
global $DB;
list($contextjoin, $contextparams) = $this->get_context_restriction_sql($context, 'moodleoverflow', 'discussions');
if ($contextjoin === null) {
return null;
}
$sql = "SELECT md.name as title, mp.*, mo.course, mo.id as moodleoverflowid FROM {moodleoverflow_posts} mp
JOIN {moodleoverflow_discussions} md ON mp.discussion = md.id
JOIN {moodleoverflow} mo ON md.moodleoverflow = mo.id
$contextjoin
WHERE mp.modified >= ? ORDER BY mp.modified ASC";
return $DB->get_recordset_sql($sql, array_merge($contextparams, [$modifiedfrom]));
}
}
5 changes: 4 additions & 1 deletion lang/en/moodleoverflow.php
Original file line number Diff line number Diff line change
Expand Up @@ -395,4 +395,7 @@
$string['updategrades'] = 'Update grades';
$string['gradesreport'] = 'Grades report';
$string['gradesupdated'] = 'Grades updated';
$string['taskupdategrades'] = 'Moodleoverflow maintenance job to update grades';
$string['taskupdategrades'] = 'Moodleoverflow maintenance job to update grades';

// Search.
$string['search:moodleoverflowposts'] = 'Moodleoverflow Posts';
6 changes: 3 additions & 3 deletions locallib.php
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ function moodleoverflow_get_post_full($postid) {
$params['postid'] = $postid;

$post = $DB->get_record_sql($sql, $params);
if ($post->userid === 0) {
if (isset($post->userid) && $post->userid === 0) {
$post->message = get_string('privacy:anonym_post_message', 'mod_moodleoverflow');
}

Expand Down Expand Up @@ -1641,11 +1641,11 @@ function moodleoverflow_delete_discussion($discussion, $course, $cm, $moodleover
/**
* Deletes a single moodleoverflow post.
*
* @param int $post The post ID
* @param object $post The post object
* @param array $children The child posts
* @param object $course The course object.
* @param object $cm The course module
* @param int $moodleoverflow The moodleoverflow ID
* @param object $moodleoverflow The moodleoverflow object
*
* @return bool Whether the deletion was successful
*/
Expand Down
34 changes: 34 additions & 0 deletions tests/behat/behat_mod_moodleoverflow.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,38 @@ protected function add_new_discussion($moodleoverflowname, TableNode $table, $bu
$this->execute('behat_forms::press_button', get_string('posttomoodleoverflow', 'moodleoverflow'));
$this->execute('behat_general::i_wait_to_be_redirected');
}

/**
* @Given I go to :link
*/
public function i_go_to($link) {
$this->visitPath($link);
}

/**
* Fills in form field with specified id|name|label|value
* Example: When I fill in "username" with: "bwayne"
* Example: And I fill in "bwayne" for "username"
*
* @When /^(?:|I )fill in "(?P<field>(?:[^"]|\\")*)" with "(?P<value>(?:[^"]|\\")*)"$/
* @When /^(?:|I )fill in "(?P<field>(?:[^"]|\\")*)" with:$/
* @When /^(?:|I )fill in "(?P<value>(?:[^"]|\\")*)" for "(?P<field>(?:[^"]|\\")*)"$/
*/
public function fill_field($field, $value) {
$field = $this->fix_step_argument($field);
$value = $this->fix_step_argument($value);
$this->getSession()->getPage()->fillField($field, $value);
}

/**
* Returns fixed step argument (with \\" replaced back to ")
*
* @param string $argument
*
* @return string
*/
protected function fix_step_argument($argument) {
return str_replace('\\"', '"', $argument);
}

}
62 changes: 62 additions & 0 deletions tests/behat/test_search.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
@mod @mod_moodleoverflow @mod_moodleoverflow_search
Feature: Search moodle for moodleoverflow discussions
In order to find discussions
I need to be able to search them

Background: : Add a moodleoverflow and a discussion
Given the following config values are set as admin:
| enableglobalsearch | 1 |
| searchengine | simpledb |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | [email protected] |
| student1 | Student | 1 | [email protected] |
| student2 | Student | 2 | [email protected] |
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 I log in as "teacher1"
And I am on "Course 1" course homepage
And I turn editing mode on
And I add a "Moodleoverflow" to section "1" and I fill the form with:
| Moodleoverflow name | Test moodleoverflow name |
| Description | Test forum description |
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
And I add a new discussion to "Test moodleoverflow name" moodleoverflow with:
| Subject | Forum post 1 |
| Message | This is the body |
And I log out
And I log in as "teacher1"
And I update the global search index
And I log out

Scenario: As a teacher I should see all discussions in my course
Given I log in as "teacher1"
And I go to "search/index.php"
And I fill in "id_q" with "Forum post 1"
And I press "id_submitbutton"
Then I should see "Forum post 1"
And I should see "This is the body"

Scenario: As an enrolled student I should see all discussions in my course
Given I log in as "student1"
And I go to "search/index.php"
And I fill in "id_q" with "Forum post 1"
And I press "id_submitbutton"
Then I should see "Forum post 1"
And I should see "This is the body"

@test
Scenario: As an unenrolled student I should see all discussions in my course
Given I log in as "student2"
And I go to "search/index.php"
And I fill in "id_q" with "Forum post 1"
And I press "id_submitbutton"
Then I should not see "Forum post 1"
And I should not see "This is the body"
Loading