Commit a0d29eb9 authored by Robert Lyon's avatar Robert Lyon
Browse files

Adding the ability to search the Text blocktype (Bug #1446912)



To test:

1) You'll need to have some pages with 'text' blocks on them
2) Have elasticsearch installed
3) Re-index site so that the analyzer will be created for block_instance

Change-Id: Id2abe23a78ab9c3476ce31edfd7e7c8048af3861
Signed-off-by: Robert Lyon's avatarRobert Lyon <robertl@catalyst.net.nz>
parent 28621d05
......@@ -4114,7 +4114,7 @@ function xmldb_core_upgrade($oldversion=0) {
// recreate trigger
safe_require('module', 'multirecipientnotification');
PluginModuleMultirecipientnotification::postinst(0);
}
}
return $status;
}
......@@ -38,5 +38,22 @@ function xmldb_search_elasticsearch_upgrade($oldversion=0) {
add_index($table, $index);
}
if ($oldversion < 2015072700) {
log_debug('Adding ability to search by "Text" blocks in elasticsearch');
// Need to add the 'block_instance' to the default types to index for elasticsearch
// Note: the $cfg->plugin_search_elasticsearch_types can be overriding this
// We don't want to run the re-indexing now as that will take ages for large sites
// It should be run from the Extensions -> Elasticsearch -> Configuration page
if ($types = get_field('search_config', 'value', 'plugin', 'elasticsearch', 'field', 'types')) {
$types = explode(',', $types);
if (!in_array('block_instance', $types)) {
$types[] = 'block_instance';
}
$types = implode(',', $types);
update_record('search_config', array('value' => $types), array('plugin' => 'elasticsearch', 'field' => 'types'));
log_warn(get_string('newindextype', 'search.elasticsearch', 'block_instance'), true, false);
}
}
return true;
}
......@@ -33,6 +33,7 @@ $string['dateoldestfirst'] = 'Date (oldest first)';
$string['daterecentfirst'] = 'Date (most recent first)';
$string['deleted'] = 'Deleted';
$string['deletedforumpost'] = 'Deleted forum post';
$string['document'] = 'Document';
$string['filterresultsby'] = 'Filter results by';
$string['forum'] = 'Forum';
$string['forumpost'] = 'Forum post';
......@@ -47,6 +48,7 @@ $string['indexname'] = 'Index name';
$string['indexnamedescription'] = 'Name of the Elasticsearch index. Default is mahara.';
$string['license'] = 'License';
$string['Media'] = 'Media';
$string['newindextype'] = 'A new index type "%s" has been added to your elasticsearch settings. For this to take effect you will need to reindex your site';
$string['noticeenabled'] = 'The Elasticsearch plugin is currently active. To deactivate it, deselect it in the <a href="%s">site options search settings</a>.';
$string['noticenotactive'] = 'The ElasticSearch Server is unreachable on host: %s and port %s. Please make sure it is running.';
$string['noticenotenabled'] = 'The Elasticsearch plugin is not currently enabled. To activate it, select it in the <a href="%s">site options in the search settings</a>.';
......
......@@ -490,7 +490,7 @@ class PluginSearchElasticsearch extends PluginSearch {
set_config_plugin('search', 'elasticsearch', 'port', '9200');
set_config_plugin('search', 'elasticsearch', 'indexname', 'mahara');
set_config_plugin('search', 'elasticsearch', 'analyzer', 'mahara_analyzer');
set_config_plugin('search', 'elasticsearch', 'types', 'usr,interaction_instance,interaction_forum_post,group,view,artefact');
set_config_plugin('search', 'elasticsearch', 'types', 'usr,interaction_instance,interaction_forum_post,group,view,artefact,block_instance');
set_config_plugin('search', 'elasticsearch', 'cronlimit', '50000');
$elasticsearchartefacttypesmap = file_get_contents(__DIR__ . '/elasticsearchartefacttypesmap.txt');
......@@ -1270,7 +1270,10 @@ abstract class ElasticsearchType
public static function getRecordById($type, $id){
$record = get_record($type, 'id', $id);
if ($record) {
$record->ctime = self::checkctime($record->ctime);
// we need to set block_instance creation time later (using view ctime)
if ($type != 'block_instance') {
$record->ctime = self::checkctime($record->ctime);
}
$record->mainfacetterm = static::$mainfacetterm;
}
return $record;
......@@ -1684,6 +1687,10 @@ class ElasticsearchIndexing {
else if ($type == 'usr') {
$insert_sql .= ' WHERE id != 0';
}
else if ($type == 'block_instance') {
$insert_sql .= " WHERE blocktype = 'text'";
}
if ($type == 'artefact') {
$condition = " AND artefacttype IN ";
$condition .= isset($artefacttype) ? "('$artefacttype')" : self::artefacttypes_filter_string();
......
<?php
class ElasticsearchType_block_instance extends ElasticsearchType
{
public static $mappingconf = array(
'mainfacetterm' => array(
'type' => 'string',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
'secfacetterm' => array(
'type' => 'string',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
'id' => array(
'type' => 'long',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
'title' => array(
'type' => 'string',
'include_in_all' => TRUE
),
'description' => array(
'type' => 'string',
'include_in_all' => TRUE
),
// the owner can be owner (user), group, or institution
'owner' => array(
'type' => 'long',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
'group' => array(
'type' => 'long',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
'institution' => array(
'type' => 'string',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
'access' => array(
'type' => 'object',
'index' => 'not_analyzed',
'include_in_all' => FALSE,
// public - logged - friends: if block_instance is visible to public or logged-in users
// if public or logged, the other properties are ignored
'general' => array(
'type' => 'string',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
// array of institutions that have access to the block_instance
'institutions' => array(
'type' => 'string',
'index' => 'not_analyzed',
'index_name' => 'institution',
'include_in_all' => FALSE
),
// array of groups that have access to the block_instance - empty (all), member, admin
'groups' => array(
'type' => 'object',
'index' => 'not_analyzed',
'include_in_all' => FALSE,
// list of groups for which both members and admins have access to the block_instance
'all' => array(
'type' => 'int',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
// list of groups for which only admins have access to the block_instance
'admin' => array(
'type' => 'int',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
// list of groups for which only members have access to the block_instance
'member' => array(
'type' => 'int',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
// list of groups for which only tutors have access to the block_instance
'tutor' => array(
'type' => 'int',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
),
// array of user ids that have access to the block_instance
'usrs' => array(
'type' => 'int',
'index' => 'not_analyzed',
'index_name' => 'usr',
'include_in_all' => FALSE
),
),
'ctime' => array(
'type' => 'date',
'format' => 'YYYY-MM-dd HH:mm:ss',
'include_in_all' => FALSE
),
// sort is the field that will be used to sort the results alphabetically
'sort' => array(
'type' => 'string',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
);
public static $mainfacetterm = 'Text';
public static $secfacetterm = 'Document';
public function __construct($data){
$this->conditions = array();
$this->mapping = array(
'mainfacetterm' => NULL,
'secfacetterm' => NULL,
'id' => NULL,
'title' => NULL,
'description' => NULL,
'owner' => NULL,
'group' => NULL,
'institution' => NULL,
'access' => NULL,
'ctime' => NULL,
'sort' => NULL,
);
parent::__construct($data);
}
public static function getRecordById($type, $id) {
$record = parent::getRecordById($type, $id);
if (!$record) {
return false;
}
// Add the ctime by getting view ctime
$data = self::getRecordDataById($type, $id);
if (!$data) {
return false;
}
// As block_instances do not have certain fields we need to get their
// info either from the view they are on or from their configdata
$record->ctime = parent::checkctime($data->ctime);
$record->description = $data->description;
$record->owner = $data->owner;
$record->group = $data->group;
$record->institution = $data->institution;
// Access: get all the views where the block_instance is included
$access = self::view_access_records($id);
$accessObj = self::access_process($access);
$record->access = $accessObj;
$record->secfacetterm = self::$secfacetterm;
// AS the field "sort" is not analyzed, we need to clean it (remove html tags & lowercase)
$record->sort = strtolower(strip_tags($record->title));
return $record;
}
public static function getRecordDataById($type, $id){
global $USER;
$sql = 'SELECT bi.id, bi.view AS view_id, bi.title, bi.configdata, v.owner, v.institution, v.group, v.ctime
FROM {block_instance} bi
JOIN {view} v ON v.id = bi.view
WHERE bi.id = ?';
$record = get_record_sql($sql, array($id));
if (!$record) {
return false;
}
require_once(get_config('docroot') . 'blocktype/lib.php');
$bi = new BlockInstance($id);
$configdata = $bi->get('configdata');
// We can only deal with blocktypes that have a 'text' configdata at this point
if (!is_array($configdata) || !array_key_exists('text', $configdata)) {
return false;
}
$record->title = str_replace(array("\r\n", "\n", "\r"), ' ', strip_tags($record->title));
$record->description = str_replace(array("\r\n", "\n", "\r"), ' ', strip_tags($configdata['text']));
// If user is owner
if ($USER->get('id') == $record->owner) {
$record->link = 'view/view.php?id=' . $record->view_id;
}
// Get the view info the block is on
$sql = 'SELECT v.id AS id, v.title AS title
FROM {view} v
WHERE v.id = ?';
$views = get_records_sql_array($sql, array($record->view_id));
if ($views) {
$record_views = array();
foreach($views AS $view){
if (isset($view->id)) {
$record_views[$view->id] = $view->title;
}
}
$record->views = $record_views;
}
return $record;
}
/**
* Get all access records of the views in which the block_instance is included
*/
public static function view_access_records($blockid) {
$records = get_records_sql_array('
SELECT va.view AS view_id, va.accesstype, va.group, va.role, va.usr, va.institution
FROM {view_access} va
JOIN {block_instance} bi ON bi.view = va.view
WHERE bi.id = ?
AND (va.startdate IS NULL OR va.startdate < current_timestamp)
AND (va.stopdate IS NULL OR va.stopdate > current_timestamp)
',
array($blockid)
);
return $records;
}
}
......@@ -13,5 +13,5 @@ defined('INTERNAL') || die();
$config = new stdClass();
$config->name = 'elasticsearch';
$config->version = 2015060900;
$config->release = '1.0.2';
$config->version = 2015072700;
$config->release = '1.0.3';
{if $record->link}
<h3 class="title">
<a href="{$WWWROOT}{$record->link}">{$record->title|str_shorten_html:50:true|safe}</a>
{else}
<h3 class="title">{$record->title|str_shorten_html:50:true|safe}
{/if}
<span class="artefacttype">
({str tag=document section=search.elasticsearch})
{if $record->deleted}
({str tag=deleted section=search.elasticsearch})
{/if}
</span></h3>
{if $record->createdbyname}
<div class="createdby">{str tag=createdby section=search.elasticsearch arg1='<a href="`$record->createdby|profile_url`">`$record->createdbyname|safe`</a>'}</div>
{/if}
<div class="detail">{$record->description|str_shorten_html:100:true|safe}</div>
<!-- VIEWS -->
{if $record->views|count gt 0}
<div class="usedon">
{if $record->views}
<strong>{str tag=usedonpage section=search.elasticsearch}:</strong>
<ul>
{foreach from=$record->views key=id item=view}
<li><a href="{$WWWROOT}view/view.php?id={$id}">{$view|str_shorten_html:50:true|safe}</a>
</li>
{/foreach}
</ul>
{/if}
</div>
{/if}
<!-- end VIEWS -->
<!-- TAGS -->
{if $record->tags|count gt 0}
<div class="tags"><strong>{str tag=tags section=search.elasticsearch}:</strong>
{foreach from=$record->tags item=tag name=tags}
<a href="{$WWWROOT}search/elasticsearch/index.php?query={$tag}&tagsonly=true">{$tag}</a>{if !$.foreach.tags.last}, {/if}
{/foreach}
</div>
{/if}
<!-- end TAGS -->
......@@ -38,6 +38,8 @@
{include file="search:elasticsearch:group.tpl" record=$record['db']}
{elseif $record['type'] eq 'artefact'}
{include file="search:elasticsearch:artefact.tpl" record=$record['db'] secfacetterm=$record['secfacetterm']}
{elseif $record['type'] eq 'block_instance'}
{include file="search:elasticsearch:block_instance.tpl" record=$record['db']}
{elseif $record['type'] eq 'collection'}
{include file="search:elasticsearch:collection.tpl" record=$record['db']}
{/if}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment