Commit 0ad5b688 authored by Robert Lyon's avatar Robert Lyon

Bug 1755919: Adding related tags page and adjusting tag filter

This patch contains the following:
- created a relatedtags.php page + json file + template to handle the
viewing of related tags for a user, the differences for this to
tags.php page are:
-- it can be viewed publically
-- it requires a tag and viewid

- Adjusted the filters for blog/blogpost, plan/task so they appear
under their own filters as well as 'text' filter

- adjusted the dwoo function list_tags so that we can pass an array of
viewids/tags and/or just a view id

-adjusted the portfolio_search_* functions so they would work for both
my tags and related tags pages

- fixed a filter js problem for tags.php where choosing the filter was
not updating the displayed filter string

behatnotneeded

Change-Id: Ie3a2c3cb56e94ced0e021265bce88e35a9cfba5d
Signed-off-by: Robert Lyon's avatarRobert Lyon <robertl@catalyst.net.nz>
parent 0030295e
......@@ -114,6 +114,7 @@ class PluginBlocktypeBlog extends MaharaCoreBlocktype {
$smarty->assign('editing', $editing);
$smarty->assign('canaddpost', $canaddpost);
$smarty->assign('blogid', $blog->get('id'));
$smarty->assign('view', $instance->get('view'));
$smarty->assign('posts', $posts);
$result = $smarty->fetch('artefact:blog:blog.tpl');
......
......@@ -281,14 +281,14 @@ class PluginBlocktypeTaggedposts extends MaharaCoreBlocktype {
if ($key > 0) {
$tagstr .= ', ';
}
$tagstr .= ($viewownerdisplay) ? '"' . $tag . '"' : '"<a href="' . get_config('wwwroot') . 'tags.php?tag=' . urlencode($tag) . '&sort=name&type=text">' . hsc($tag) . '</a>"';
$tagstr .= ($USER->id != $owner) ? '"<a href="' . get_config('wwwroot') . 'relatedtags.php?tag=' . urlencode($tag) . '&view=' . $view . '">' . hsc($tag) . '</a>"' : '"<a href="' . get_config('wwwroot') . 'tags.php?tag=' . urlencode($tag) . '&sort=name&type=text">' . hsc($tag) . '</a>"';
}
if (!empty($tagsout)) {
foreach ($tagsout as $key => $tag) {
if ($key > 0) {
$tagomitstr .= ', ';
}
$tagomitstr .= ($viewownerdisplay) ? '"' . $tag . '"' : '"<a href="' . get_config('wwwroot') . 'tags.php?tag=' . urlencode($tag) . '&sort=name&type=text">' . hsc($tag) . '</a>"';
$tagomitstr .= ($USER->id != $owner) ? '"<a href="' . get_config('wwwroot') . 'relatedtags.php?tag=' . urlencode($tag) . '&view=' . $view . '">' . hsc($tag) . '</a>"' : '"<a href="' . get_config('wwwroot') . 'tags.php?tag=' . urlencode($tag) . '&sort=name&type=text">' . hsc($tag) . '</a>"';
}
}
if (empty($tagsin)) {
......
......@@ -145,7 +145,8 @@ class PluginArtefactBlog extends PluginArtefact {
public static function get_artefact_type_content_types() {
return array(
'blogpost' => array('text'),
'blog' => array('blog'),
'blogpost' => array('blogpost'),
);
}
......@@ -354,9 +355,11 @@ class ArtefactTypeBlog extends ArtefactType {
$smarty->assign('artefacttitle', '<a href="' . get_config('wwwroot') . 'artefact/artefact.php?artefact='
. $this->get('id') . '&view=' . $options['viewid']
. '">' . hsc($this->get('title')) . '</a>');
$smarty->assign('view', $options['viewid']);
}
else {
$smarty->assign('artefacttitle', hsc($this->get('title')));
$smarty->assign('view', null);
}
if (!empty($options['details']) and get_config('licensemetadata')) {
......@@ -886,6 +889,7 @@ class ArtefactTypeBlogPost extends ArtefactType {
$smarty->assign('artefactdescription', $postcontent);
$smarty->assign('artefacttags', $this->get('tags'));
$smarty->assign('artefactowner', $this->get('owner'));
$smarty->assign('artefactview', (isset($options['viewid']) ? $options['viewid'] : null));
if (!empty($options['details']) and get_config('licensemetadata')) {
$smarty->assign('license', render_license($this));
}
......@@ -1061,6 +1065,7 @@ class ArtefactTypeBlogPost extends ArtefactType {
else {
$by = $post->author ? display_default_name($post->author) : $post->authorname;
$post->postedby = ArtefactTypeBlog::display_postedby($post->ctime, $by);
$post->owner = $post->author;
// Get comment counts
if (!empty($viewoptions['countcomments'])) {
safe_require('artefact', 'comment');
......
......@@ -279,8 +279,8 @@ class PluginArtefactFile extends PluginArtefact {
public static function get_artefact_type_content_types() {
return array(
'file' => array('file'),
'image' => array('file', 'image'),
'profileicon' => array('file', 'image'),
'image' => array('image'),
'profileicon' => array('image'),
'archive' => array('file'),
'video' => array('file'),
'audio' => array('file'),
......@@ -1356,6 +1356,7 @@ class ArtefactTypeFile extends ArtefactTypeFileBase {
if ($USER->is_logged_in()) {
$smarty->assign('ownername', $this->display_owner());
}
$smarty->assign('view', (isset($options['viewid']) ? $options['viewid'] : null));
$smarty->assign('created', strftime(get_string('strftimedaydatetime'), $this->get('ctime')));
$smarty->assign('modified', strftime(get_string('strftimedaydatetime'), $this->get('mtime')));
$smarty->assign('size', $this->describe_size() . ' (' . $this->get('size') . ' ' . get_string('bytes', 'artefact.file') . ')');
......
......@@ -1000,6 +1000,7 @@ class ArtefactTypeHtml extends ArtefactType {
}
$smarty->assign('attachments', $attachments);
}
$smarty->assign('view', (isset($options['viewid']) ? $options['viewid'] : null));
return array(
'html' => $smarty->fetch('artefact.tpl'),
'javascript'=>''
......
......@@ -885,7 +885,7 @@ abstract class ArtefactType implements IArtefactType {
else {
$smarty->assign('license', false);
}
$smarty->assign('view', (!empty($options['viewid']) ? $options['viewid'] : null));
return array(
'html' => $smarty->fetch('artefact.tpl'),
'javascript'=>''
......
......@@ -76,6 +76,7 @@ class PluginBlocktypePlans extends MaharaCoreBlocktype {
'jsonscript' => 'artefact/plans/viewtasks.json.php',
);
}
$configdata['view'] = $instance->get('view');
ArtefactTypeTask::render_tasks($tasks, $template, $configdata, $pagination);
if ($exporter && $tasks['count'] > $tasks['limit']) {
......@@ -87,6 +88,7 @@ class PluginBlocktypePlans extends MaharaCoreBlocktype {
$smarty->assign('owner', $plan->get('owner'));
$smarty->assign('tags', $plan->get('tags'));
$smarty->assign('tasks', $tasks);
$smarty->assign('view', $instance->get('view'));
}
else {
$smarty->assign('noplans','blocktype.plans/plans');
......
......@@ -45,7 +45,8 @@ class PluginArtefactPlans extends PluginArtefact {
public static function get_artefact_type_content_types() {
return array(
'task' => array('text'),
'plan' => array('plan'),
'task' => array('task'),
);
}
......@@ -304,6 +305,7 @@ class ArtefactTypePlan extends ArtefactType {
else {
$smarty->assign('license', false);
}
$smarty->assign('view', (!empty($options['viewid']) ? $options['viewid'] : null));
$smarty->assign('owner', $this->get('owner'));
$smarty->assign('tags', $this->get('tags'));
......@@ -661,6 +663,7 @@ class ArtefactTypeTask extends ArtefactType {
$smarty = smarty_core();
$smarty->assign('tasks', $tasks);
$smarty->assign('options', $options);
$smarty->assign('view', (!empty($options['view']) ? $options['view'] : null));
$tasks['tablerows'] = $smarty->fetch($template);
if ($tasks['limit'] && $pagination) {
......
<?php
/**
*
* @package mahara
* @subpackage core
* @author Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
define('INTERNAL', 1);
define('PUBLIC', 1);
define('JSON', 1);
require(dirname(dirname(__FILE__)) . '/init.php');
require_once('searchlib.php');
require_once('view.php');
require_once('collection.php');
$tag = param_variable('tag');
$tag = urldecode($tag);
$viewid = param_integer('view');
$limit = param_integer('limit', 10);
$offset = param_integer('offset', 0);
$sort = param_alpha('sort', 'name');
$type = param_alpha('type', null);
// Check view id to see if we are allowed access the view and the view is owned by a user
if ($viewid) {
$view = new View($viewid);
$owner = $view->get('owner');
if (!can_view_view($view) || !$owner) {
$errorstr = get_string('accessdenied', 'error');
json_reply(true, $errorstr);
}
}
// Now we have a valid view lets get the user id
$user = new User();
$user->find_by_id($owner);
$displayname = display_name($user);
$userobj = (object) array('type' => 'user', 'id' => $owner, 'owner' => $owner);
if ($USER->is_logged_in()) {
// Find all views owned by owner shared to current user
$rawdata = View::view_search(null, null, $userobj);
}
else {
$rawdata = new stdClass();
// when logged out we restrict the tags to the page/collection being viewed
// Check to see if it is part of a collection
if ($view->get('collection')) {
$rawdata->ids = array();
$viewlist = $view->get('collection')->get('views');
foreach ($viewlist['views'] as $v) {
$rawdata->ids[] = $v->view;
}
$relatedtitle = $view->get('collection')->get('name');
}
else {
// Otherwise just look at the current view
$rawdata->ids = array($view->get('id'));
$relatedtitle = $view->get('title');
}
}
// Now get the subset where either the view / collection has the tag or the artefact(s) on the view have the tag
$data = get_portfolio_items_by_tag($tag, $userobj, $limit, $offset, $sort, $type, true, $rawdata->ids);
$data->isrelated = true;
$data->viewid = $view->get('id');
build_portfolio_search_html($data);
$data->tagdisplay = hsc(str_shorten_text($tag, 50));
$data->tagurl = urlencode($tag);
json_reply(false, array('data' => $data));
......@@ -14,6 +14,8 @@ define('JSON', 1);
require(dirname(dirname(__FILE__)) . '/init.php');
require_once('searchlib.php');
require_once('view.php');
require_once('collection.php');
if ($tag = param_variable('tag', null)) {
$tag = urldecode($tag);
......
......@@ -158,6 +158,7 @@ $string['select'] = 'Select';
$string['tags'] = 'Tags';
$string['tagsdesc'] = 'Search for/enter tags for this item.';
$string['tagsdescprofile'] = 'Search for/enter tags for this item. Items tagged with \'profile\' are displayed in your sidebar.';
$string['viewtags'] = 'Page tags';
$string['youhavenottaggedanythingyet'] = 'You have not tagged anything yet';
$string['mytags'] = 'My tags';
$string['Tag'] = 'Tag';
......@@ -191,6 +192,10 @@ $string['tagfilter_image'] = 'Images';
$string['tagfilter_text'] = 'Text';
$string['tagfilter_view'] = 'Pages';
$string['tagfilter_collection'] = 'Collections';
$string['tagfilter_blog'] = 'Journal';
$string['tagfilter_blogpost'] = 'Journal entry';
$string['tagfilter_plan'] = 'Plan';
$string['tagfilter_task'] = 'Plan task';
$string['edittags'] = 'Edit tags';
$string['selectatagtoedit'] = 'Select a tag to edit';
$string['edittag'] = 'Edit <a href="%s">%s</a>';
......@@ -201,6 +206,10 @@ $string['confirmdeletetag'] = 'Do you really want to delete this tag from all it
$string['deletetagdescription'] = 'Remove this tag from all items in your portfolio';
$string['tagupdatedsuccessfully'] = 'Tag updated successfully';
$string['tagdeletedsuccessfully'] = 'Tag deleted successfully';
$string['relatedtags'] = 'Tagged content of %s';
$string['relatedtagsinview'] = 'Tagged content of %s in portfolio "%s"';
$string['norelatedtaggeditemstoview'] = 'There is nothing you can view with tag "%s" owned by "%s".';
$string['norelatedtaggeditemstoviewfiltered'] = 'There is no %s you can view with tag "%s" owned by "%s".';
$string['selfsearch'] = 'Search my portfolio';
$string['resultsperpage'] = 'Results per page';
......@@ -1286,3 +1295,4 @@ $string['scroll_to_top'] = 'Back to top';
$string['tabgroup'] = 'Group';
$string['tabinstitution'] = 'Institution';
$string['version.'] = 'v.'; // version shortname, used when duplicating pages and collections
$string['viewartefact'] = 'View ';
\ No newline at end of file
......@@ -20,19 +20,33 @@
* @param Smarty
* @return Internationalized string
*/
function Dwoo_Plugin_list_tags(Dwoo $dwoo, $tags, $owner) {
function Dwoo_Plugin_list_tags(Dwoo $dwoo, $tags, $owner, $view = null) {
global $USER;
if (!is_array($tags)) {
return '';
}
foreach ($tags as &$t) {
if ($owner != $USER->get('id')) {
return join(', ', array_map('hsc', $tags));
if (is_array($t)) {
$t = '<a class="tag" href="' . get_config('wwwroot') . 'relatedtags.php?tag=' . urlencode($t['tag']) . '&view=' . $t['view'] . '">' . hsc(str_shorten_text($t['tag'], 50)) . '</a>';
}
foreach ($tags as &$t) {
else if ($view) {
$t = '<a class="tag" href="' . get_config('wwwroot') . 'relatedtags.php?tag=' . urlencode($t) . '&view=' . $view . '">' . hsc(str_shorten_text($t, 50)) . '</a>';
}
else {
$t = hsc(str_shorten_text($t, 50));
}
}
else {
if (is_array($t)) {
$t = '<a class="tag" href="' . get_config('wwwroot') . 'tags.php?tag=' . urlencode($t['tag']) . '&view=' . $t['view'] . '">' . hsc(str_shorten_text($t['tag'], 50)) . '</a>';
}
else {
$t = '<a class="tag" href="' . get_config('wwwroot') . 'tags.php?tag=' . urlencode($t) . '">' . hsc(str_shorten_text($t, 50)) . '</a>';
}
}
}
return join(', ', $tags);
}
......
......@@ -4510,8 +4510,15 @@ function build_portfolio_search_html(&$data) {
else if ($item->type == 'collection') {
$item->typestr = $item->type;
$item->typelabel = get_string('Collection', 'collection');
// Because our 'views' array clashes with a collection objects 'views' array we need to move it out of the way
// before calling the get_url() function
$viewarray = $item->views;
$dummy = new stdClass();
$dummy->id = $item->viewid;
$item->views = array('views' => array(0 => $dummy));
$c = new Collection(0, (array)$item);
$item->url = $c->get_url();
$item->views = $viewarray;
}
else { // artefact
safe_require('artefact', $artefacttypes[$item->artefacttype]->plugin);
......@@ -4527,7 +4534,15 @@ function build_portfolio_search_html(&$data) {
}
}
if (isset($data->isrelated) && $data->isrelated) {
$data->baseurl = get_config('wwwroot') . 'relatedtags.php' . (is_null($data->tag) ? '' : '?tag=' . urlencode($data->tag) . '&view=' . $data->viewid);
$data->basejsonurl = 'json/relatedtagsearch.php';
}
else {
$data->baseurl = get_config('wwwroot') . 'tags.php' . (is_null($data->tag) ? '' : '?tag=' . urlencode($data->tag));
$data->basejsonurl = 'json/tagsearch.php';
}
$data->sortcols = array('name', 'date');
$data->filtercols = array(
'all' => get_string('tagfilter_all'),
......@@ -4536,6 +4551,10 @@ function build_portfolio_search_html(&$data) {
'text' => get_string('tagfilter_text'),
'view' => get_string('tagfilter_view'),
'collection' => get_string('tagfilter_collection'),
'blog' => get_string('tagfilter_blog'),
'blogpost' => get_string('tagfilter_blogpost'),
'plan' => get_string('tagfilter_plan'),
'task' => get_string('tagfilter_task'),
);
$smarty = smarty_core();
......@@ -4546,7 +4565,7 @@ function build_portfolio_search_html(&$data) {
'id' => 'results_pagination',
'class' => 'center',
'url' => $data->baseurl . ($data->sort == 'name' ? '' : '&sort=' . $data->sort) . ($data->filter == 'all' ? '' : '&type=' . $data->filter),
'jsonscript' => 'json/tagsearch.php',
'jsonscript' => $data->basejsonurl,
'datatable' => 'results',
'count' => $data->count,
'limit' => $data->limit,
......
......@@ -1031,7 +1031,7 @@ function get_portfolio_types_from_param($filter) {
return array('view' => false, 'collection' => false, 'artefact' => artefact_get_types_from_filter($filter));
}
function get_portfolio_items_by_tag($tag, $owner, $limit, $offset, $sort='name', $type=null, $returntags=true) {
function get_portfolio_items_by_tag($tag, $owner, $limit, $offset, $sort='name', $type=null, $returntags=true, $viewids=array()) {
// For now, can only be used to search a user's portfolio
if (empty($owner->id) || empty($owner->type)) {
throw new SystemException('get_views_and_artefacts_by_tag: invalid owner');
......@@ -1045,7 +1045,7 @@ function get_portfolio_items_by_tag($tag, $owner, $limit, $offset, $sort='name',
$plugin = 'internal';
safe_require('search', $plugin);
$result = call_static_method(generate_class_name('search', $plugin), 'portfolio_search_by_tag', $tag, $owner, $limit, $offset, $sort, $types, $returntags);
$result = call_static_method(generate_class_name('search', $plugin), 'portfolio_search_by_tag', $tag, $owner, $limit, $offset, $sort, $types, $returntags, $viewids);
$result->filter = $result->type = $type ? $type : 'all';
return $result;
}
......
<?php
/**
*
* @package mahara
* @subpackage core
* @author Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
define('INTERNAL', 1);
define('PUBLIC', 1);
define('MENUITEM', 'myportfolio');
require('init.php');
require_once('searchlib.php');
require_once('view.php');
require_once('collection.php');
// We need both tag and view id to proceed
$tag = param_variable('tag');
$viewid = param_integer('view');
// Check view id to see if we are allowed access the view and the view is owned by a user
if ($viewid) {
$view = new View($viewid);
$owner = $view->get('owner');
if (!can_view_view($view) || !$owner) {
$errorstr = get_string('accessdenied', 'error');
throw new AccessDeniedException($errorstr);
}
if ($owner == $USER->get('id')) {
// we are looking at our own stuff so send them to my tags page
redirect('/tags.php?tag=' . $tag);
}
}
// Now we have a valid view lets get the user displayname
$user = new User();
$user->find_by_id($owner);
$displayname = display_name($user);
$limit = param_integer('limit', 10);
$offset = param_integer('offset', 0);
$sort = param_alpha('sort', 'title');
$type = param_alpha('type', null);
$userobj = (object) array('type' => 'user', 'id' => $owner, 'owner' => $owner);
if ($USER->is_logged_in()) {
// Find all views owned by owner shared to current user
$rawdata = View::view_search(null, null, $userobj);
define('TITLE', get_string('relatedtags', 'mahara', $displayname));
}
else {
$rawdata = new stdClass();
// when logged out we restrict the tags to the page/collection being viewed
// Check to see if it is part of a collection
if ($view->get('collection')) {
$rawdata->ids = array();
$viewlist = $view->get('collection')->get('views');
foreach ($viewlist['views'] as $v) {
$rawdata->ids[] = $v->view;
}
$relatedtitle = $view->get('collection')->get('name');
}
else {
// Otherwise just look at the current view
$rawdata->ids = array($view->get('id'));
$relatedtitle = $view->get('title');
}
define('TITLE', get_string('relatedtagsinview', 'mahara', $displayname, $relatedtitle));
}
// Now get the subset where either the view / collection has the tag or the artefact(s) on the view have the tag
$data = get_portfolio_items_by_tag($tag, $userobj, $limit, $offset, $sort, $type, true, $rawdata->ids);
$data->isrelated = true;
$data->viewid = $view->get('id');
build_portfolio_search_html($data);
$str = array();
foreach (array('tag', 'viewid', 'sort', 'type') as $v) {
$str[$v] = json_encode($$v);
}
$js = <<<EOF
jQuery(function($) {
var p = null;
var params = {
'tag': {$str['tag']},
'view': {$str['viewid']},
'sort': {$str['sort']},
'type': {$str['type']}
};
function rewriteTagLink(elem, keep, replace) {
$(elem).off();
$(elem).on('click', function(e) {
e.preventDefault();
var reqparams = {};
var currenthref = $(this).prop('href');
for (var i = 0; i < replace.length; i++) {
if (getUrlParameter(replace[i], currenthref)) {
reqparams[replace[i]] = getUrlParameter(replace[i], currenthref);
}
}
for (var i = 0; i < keep.length; i++) {
if (params[keep[i]]) {
if (getUrlParameter(keep[i], currenthref)) {
reqparams[keep[i]] = getUrlParameter(keep[i], currenthref);
}
else {
reqparams[keep[i]] = params[keep[i]];
}
}
}
sendjsonrequest(config.wwwroot + 'json/relatedtagsearch.php', reqparams, 'POST', function(data) {
p.updateResults(data);
if (data.data.tag != params.tag) {
// Replace the tag in the Search Results heading
var heading_tag = $('#results_heading a.tag').first();
if (heading_tag.length) {
heading_tag.prop('href', currenthref);
heading_tag.html(data.data.tagdisplay);
}
if (data.data.tag) {
params.tag = data.data.tag;
}
}
// Rewrite tag links in the filter list:
$('#results_filter a').each(function () {
var newurl = $(this).prop('href');
$(this).prop('href', updateUrlParameter(newurl, 'tag', data.data.tag));
});
// Rewrite tag links in the sort list:
$('#results_sort a').each(function () {
var newurl = $(this).prop('href');
$(this).prop('href', updateUrlParameter(newurl, 'tag', data.data.tag));
});
// Change selected Sort By links above the Search results:
if (data.data.sort != params.sort) {
$('#results_sort a').each(function () {
if ($(this).hasClass('selected') && data.data.sort != getUrlParameter('sort', $(this).prop('href'))) {
$(this).removeClass('selected');
}
else if (!$(this).hasClass('selected') && data.data.sort == getUrlParameter('sort', $(this).prop('href'))) {
$(this).addClass('selected');
}
});
params.sort = data.data.sort;
}
// Change selected Filter By links above the Search results:
$('#results_filter a').each(function () {
if ($(this).hasClass('selected') && data.data.type != getUrlParameter('type', $(this).prop('href'))) {
$(this).removeClass('selected');
}
else if (!$(this).hasClass('selected') && data.data.type == getUrlParameter('type', $(this).prop('href'))) {
$(this).addClass('selected');
$('#currentfilter').text($(this).text());
$('#results_filter').parent().removeClass('open');
}
});
});
return false;
});
}
p = {$data->pagination_js}
$('#results a.tag').each(function () {rewriteTagLink(this, ['tag', 'view'], ['tag'])});
$('#results_sort a').each(function () {rewriteTagLink(this, ['tag', 'view', 'sort', 'type'], ['tag', 'sort'])});
$('#results_filter a').each(function () {rewriteTagLink(this, ['tag', 'view', 'sort', 'type'], ['tag', 'type'])});
});
EOF;
$data->queryprefix = (strpos($data->baseurl, '?') === false ? '?' : '&');
$noresultsmessage = false;
if ($data->count <= 0) {
if ($type) {
$noresultsmessage = get_string('norelatedtaggeditemstoviewfiltered', 'mahara', $type, hsc($tag), $displayname);
}
else {
$noresultsmessage = get_string('norelatedtaggeditemstoview', 'mahara', hsc($tag), $displayname);
}
}
$smarty = smarty(array('paginator'));
$smarty->assign('tag', $tag);
$smarty->assign('viewid', $view->get('id'));
$smarty->assign('results', $data);
$smarty->assign('noresultsmessage', $noresultsmessage);
$smarty->assign('INLINEJAVASCRIPT', $js);
$smarty->display('relatedtags.tpl');
......@@ -20,6 +20,7 @@ $string['artefacttypelegend'] = 'Artefact types';
$string['artefacttypemapdescription'] = 'Enter the hierarchy for each artefact type separated by | (one artefact type per row).';
$string['artefacttypemaplegend'] = 'Artefact types hierarchy';
$string['atoz'] = 'A to Z';
$string['blog'] = 'Journal';
$string['blogpost'] = 'Journal entry';
$string['bypassindexname'] = 'Bypass index';
$string['bypassindexnamedescription'] = '(Optional) If provided, Mahara will load index data into this index name instead of the main index name.';
......@@ -46,6 +47,7 @@ $string['forumtopic'] = 'Forum topic';
$string['Group'] = 'Group';
$string['host'] = 'Host';
$string['hostdescription'] = 'Hostname of the Elasticsearch server. Default is 127.0.0.1.';
$string['html'] = 'Text';
$string['indexingusername'] = 'Authentication write username';
$string['indexingusernamedescription'] = '(Optional) Username to pass to Elasticsearch via HTTP basic auth for writing to index if different from reading from index';
$string['indexingpassword'] = 'Authentication write password';
......
......@@ -1006,8 +1006,9 @@ class PluginSearchInternal extends PluginSearch {
* @param string $sort
* @param array $types view/artefacttype filters
* @param boolean $returntags Return all the tags that have been attached to each result
* @param array $viewids Only return specified views / artefacts in specified views - combined with $tag
*/
public static function portfolio_search_by_tag($tag, $owner, $limit, $offset, $sort, $types, $returntags) {
public static function portfolio_search_by_tag($tag, $owner, $limit, $offset, $sort, $types, $returntags, $viewids = array()) {
$viewfilter = is_null($types) || $types['view'] == true ? 'AND TRUE' : 'AND FALSE';
$collectionfilter = is_null($types) || $types['collection'] == true ? 'AND TRUE' : 'AND FALSE';
......@@ -1024,29 +1025,49 @@ class PluginSearchInternal extends PluginSearch {
if (!is_null($tag)) {
$artefacttypefilter .= ' AND at.tag = ?';
$viewfilter .= ' AND vt.tag = ?';
$collectionfilter .= ' AND ct.tag = ?';
$values = array($owner->id, $tag, $owner->id, $tag, $owner->id, $tag);
$collectionfilter .= ' AND (ct.tag = ? OR vt.tag = ?)';
$values = array($owner->id, $tag, $owner->id, $tag, $owner->id, $tag, $tag);
}
else {
$values = array($owner->id, $owner->id, $owner->id);
}
if (!empty($viewids) && is_array($viewids)) {
$viewidstr = implode(',', $viewids);
$artefactjoin = ' JOIN {view_artefact} va ON (va.artefact = a.parent OR va.artefact = a.id)
LEFT JOIN {artefact_blog_blogpost} abb ON abb.blogpost = a.id ';
$artefactwhere = ' AND va.view IN (' . $viewidstr . ') AND (abb.published IS NULL OR abb.published = 1) ';
$viewwhere = ' AND v.id IN (' . $viewidstr . ') ';
$collectionwhere = ' AND cv.view IN (' . $viewidstr . ') ';
}
else {
$artefactjoin = '';
$artefactwhere = '';
$viewwhere = '';
$collectionwhere = '';
}
$from = "
FROM (
(SELECT a.id, a.title, a.description, 'artefact' AS type, a.artefacttype, " . db_format_tsfield('a.ctime', 'ctime') . ",
a.owner, a.group, a.institution, NULL AS urlid
FROM {artefact} a JOIN {artefact_tag} at ON (a.id = at.artefact)
WHERE a.owner = ?" . $artefacttypefilter . ")
FROM {artefact} a
JOIN {artefact_tag} at ON (a.id = at.artefact) " . $artefactjoin . "
WHERE a.owner = ?" . $artefactwhere . $artefacttypefilter . ")
UNION
(SELECT v.id, v.title, v.description, 'view' AS type, NULL AS artefacttype, " . db_format_tsfield('v.ctime', 'ctime') . ",
v.owner, v.group, v.institution, v.urlid
FROM {view} v JOIN {view_tag} vt ON (v.id = vt.view)
WHERE v.owner = ? " . $viewfilter . ")
FROM {view} v
JOIN {view_tag} vt ON (v.id = vt.view)
LEFT JOIN {collection_view} cv ON cv.view = v.id
WHERE v.owner = ? AND cv.view IS NULL " . $viewwhere . $viewfilter . ")
UNION
(SELECT c.id, c.name, c.description, 'collection' AS type, NULL AS artefacttype, " . db_format_tsfield('c.ctime', 'ctime') . ",
c.owner, c.group, c.institution, NULL AS urlid
FROM {collection} c JOIN {collection_tag} ct ON (c.id = ct.collection)
WHERE c.owner = ? " . $collectionfilter . ")
FROM {collection} c
JOIN {collection_view} cv ON cv.collection = c.id
LEFT JOIN {collection_tag} ct ON (c.id = ct.collection)
LEFT JOIN {view_tag} vt ON vt.view = cv.view
WHERE c.owner = ? " . $collectionwhere . $collectionfilter . ")
) p";
$result = (object) array(
......@@ -1067,6 +1088,51 @@ class PluginSearchInternal extends PluginSearch {
$ids = array('view' => array(), 'collection' => array(), 'artefact' => array());
foreach ($data as &$d) {
$ids[$d->type][$d->id] = 1;
if ($d->type == 'artefact') {
// VIEWS get all the views the artefact is included into.
// artefact parents are folder, blog, plan, cpd
$sql = 'SELECT COALESCE(v.id, vp.id) AS id, COALESCE(v.title, vp.title) AS title
FROM {artefact} a
LEFT OUTER JOIN {view_artefact} va ON va.artefact = a.id
LEFT OUTER JOIN {view} v ON v.id = va.view
LEFT OUTER JOIN {artefact} parent ON parent.id = a.parent
LEFT OUTER JOIN {view_artefact} vap ON (vap.artefact = parent.id and parent.artefacttype in (\'plan\', \'folder\'))
LEFT OUTER JOIN {view} vp ON vp.id = vap.view
WHERE a.id = ?';
if (!empty($viewids)) {
$sql .= ' AND (va.view IN (' . $viewidstr . ')
OR vap.view IN (' . $viewidstr . '))';
}
$views = get_records_sql_array($sql, array($d->id));
if ($views) {
$record_views = array ();
foreach ( $views as $view ) {
if (isset ( $view->id )) {
$record_views[$view->id] = $view->title;
$d->viewid = $view->id; // just needs to be any valid view
}
}
$d->views = $record_views;
}
}
else if ($d->type == 'collection') {
$c = new Collection($d->id);
$views = $c->get('views');