Commit d707c7de authored by Robert Lyon's avatar Robert Lyon Committed by Gerrit Code Review
Browse files

Merge changes I29be28c2,I833caaa9,I665d03d0,I4383f3ec,I6b71ed16, ...

* changes:
  Bug 1722861: Allow admins to delete institution tag
  Bug 1722861: Display tag prefix on tagged journal search
  Bug 1722861: On file edit, display the tag prefix
  Bug 1722861: Fix the institution tags display on tags.php
  Bug 1722861: Select and save institution tags
  Bug 1722861: Add the create institution tag logic
  Bug 1774103: Looking to combine all the *_tag tables
  Bug 1774103: New structure for the tags table
  Bug 1722861: Add the institution tags page
  Bug 1722861: Add the option to use institution tags
parents 02a5b3b8 1ea2673b
......@@ -270,7 +270,25 @@ $elements['externalauthjs'] = array(
'value' => $js,
);
$tags = get_column_sql('SELECT tag FROM {usr_tag} WHERE usr = ? AND NOT tag ' . db_ilike() . " 'lastinstitution:%'", array($user->id));
$tags = array();
if ($tagsarray = get_records_sql_array("SELECT t.tag, t.prefix, t.ownerid
FROM (
SELECT ut.tag, NULL AS prefix, 0 AS ownerid
FROM {tag} ut
WHERE resourcetype = ? AND resourceid = ? AND ownertype <> 'instituion'
AND NOT tag " . db_ilike() . " 'lastinstitution:%'
UNION
SELECT it.tag, it.ownerid AS prefix, i.id AS ownerid
FROM {tag} it
JOIN {institution} i ON i.name = it.ownerid
WHERE resourcetype = ? AND resourceid = ?
AND tag " . db_ilike() . " 'lastinstitution:%'
) t
GROUP BY t.tag, t.prefix, t.ownerid", array('usr', $user->id, 'usr', $user->id))) {
foreach ($tagsarray as $k => $v) {
$tags[] = $v->tag;
}
}
$elements['tags'] = array(
'defaultvalue' => $tags,
......@@ -603,18 +621,26 @@ function edituser_site_submit(Pieform $form, $values) {
// Update user's primary email address
set_user_primary_email($user->id, $values['email']);
delete_records('usr_tag', 'usr', $user->id);
delete_records('tag', 'resourcetype', 'usr', 'resourceid', $user->id);
if (is_array($values['tags'])) {
$values['tags'] = check_case_sensitive($values['tags'], 'usr_tag');
$values['tags'] = check_case_sensitive($values['tags'], 'tag');
foreach(array_unique($values['tags']) as $tag) {
if (empty($tag)) {
continue;
}
if ($tagid = get_field('tag', 'resourceid', 'resourcetype', 'institution', 'tag', $tag)) {
$tag = 'tagid_' . $tagid;
}
insert_record(
'usr_tag',
'tag',
(object) array(
'usr' => $user->id,
'tag' => strtolower($tag),
'resourcetype' => 'usr',
'resourceid' => $user->id,
'ownertype' => 'user',
'ownerid' => $user->id,
'tag' => $tag,
'ctime' => db_format_timestamp(time()),
'editedby' => $USER->get('id'),
)
);
}
......
......@@ -267,6 +267,7 @@ if ($institution || $add) {
$data->showonlineusers = 2;
$data->allowinstitutionpublicviews = get_config('allowpublicviews') ? 1 : 0;
$data->allowinstitutionsmartevidence = 0;
$data->tags = 0;
$data->licensemandatory = 0;
$data->licensedefault = '';
$data->dropdownmenu = get_config('dropdownmenu') ? 1 : 0;
......@@ -592,6 +593,13 @@ if ($institution || $add) {
'disabled' => is_plugin_active('framework', 'module') == false,
'help' => true,
);
$elements['allowinstitutiontags'] = array(
'type' => 'switchbox',
'title' => get_string('allowinstitutiontags'),
'description' => get_string('allowinstitutiontagsdescription'),
'defaultvalue' => $data->tags,
'help' => true,
);
$elements['reviewselfdeletion'] = array(
'type' => 'switchbox',
'title' => get_string('reviewsselfdeletion', 'admin'),
......@@ -828,8 +836,6 @@ function institution_submit(Pieform $form, $values) {
$newinstitution = new Institution($institution);
$newinstitution->displayname = $values['displayname'];
$oldinstitution = get_record('institution', 'name', $institution);
// Clear out any cached menus for this institution
clear_menu_cache($institution);
}
$newinstitution->showonlineusers = !isset($values['showonlineusers']) ? 2 : $values['showonlineusers'];
......@@ -945,6 +951,7 @@ function institution_submit(Pieform $form, $values) {
$newinstitution->allowinstitutionpublicviews = (isset($values['allowinstitutionpublicviews']) && $values['allowinstitutionpublicviews']) ? 1 : 0;
$newinstitution->allowinstitutionsmartevidence = (isset($values['allowinstitutionsmartevidence']) && $values['allowinstitutionsmartevidence']) ? 1 : 0;
$newinstitution->tags = (isset($values['allowinstitutiontags']) && $values['allowinstitutiontags']) ? 1 : 0;
// do not set 'reviewselfdeletion' if it has never been changed at institution level
// and the value is the same as site setting 'defaultreviewselfdeletion'
......@@ -1164,7 +1171,8 @@ function institution_submit(Pieform $form, $values) {
$SESSION->add_ok_msg($message);
$nexturl = '/admin/users/institutions.php';
}
// Clear out any cached menus for this institution
clear_menu_cache();
redirect($nexturl);
}
......
<?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('INSTITUTIONALADMIN', 1);
define('SECTION_PLUGINTYPE', 'core');
define('SECTION_PLUGINNAME', 'admin');
define('MENUITEM', 'manageinstitutions/institutiontags');
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
require_once(get_config('libroot') . 'institution.php');
$institution = param_alphanum('institution', false);
$new = param_boolean('new', 0);
// Get all the institutions that the current user has access to.
$institutionelement = get_institution_selector(true, false, false, false, false, true);
if (!$institutionelement || empty($institutionelement['options'])) {
throw new AccessDeniedException(get_string('cantlistinstitutioncollections', 'collection'));
}
if (!$institution || !$USER->can_edit_institution($institution, true)) {
$institution = empty($institutionelement['value']) ? $institutionelement['defaultvalue'] : $institutionelement['value'];
}
else if (!empty($institution)) {
$institutionelement['defaultvalue'] = $institution;
}
define('TITLE', get_string('institutiontags'));
$institutionselector = pieform(array(
'name' => 'usertypeselect',
'class' => 'form-inline',
'elements' => array(
'institution' => $institutionelement,
)
));
// The institution drop-down selector if applicable.
$wwwroot = get_config('wwwroot');
$js = <<< EOF
function reloadTags() {
window.location.href = '{$wwwroot}admin/users/institutiontags.php?institution='+$('#usertypeselect_institution').val();
}
$(document).ready(function() {
$('#usertypeselect_institution').on('change', reloadTags);
});
EOF;
// Check if user is a institution admin
$canedit = $USER->get('admin') || $USER->is_institutional_admin();
if (!$canedit) {
throw new AccessDeniedException(get_string('cantlistinstitutiontags'));
}
// Building the new tag form.
$elements = array(
'tag' => array(
'type' => 'text',
'defaultvalue' => null,
'title' => get_string('institutiontag'),
'size' => 30,
'description' => get_string('institutiontagdesc'),
'rules' => array(
'required' => true,
),
),
'submit' => array(
'type' => 'submitcancel',
'class' => 'btn-primary',
'value' => array(get_string('save'), get_string('cancel')),
'confirm' => null,
)
);
$form = pieform(array(
'name' => 'institutiontag',
'plugintype' => 'core',
'pluginname' => 'tags',
'elements' => $elements,
));
/**
* Submit the new institution tag form
*
* @param Pieform $form The form to submit
* @param array $values The values submitted
*/
function institutiontag_submit(Pieform $form, $values) {
global $SESSION, $institution, $USER;
$id = insert_record('tag',
(object) array(
'resourcetype' => 'institution',
'resourceid' => get_field('institution', 'id', 'name', $institution),
'ownertype' => 'institution',
'ownerid' => $institution,
'tag' => $values['tag'],
'ctime' => db_format_timestamp(time()),
'mtime' => db_format_timestamp(time()),
'editedby' => $USER->id,
), 'id', true);
if ($id) {
$SESSION->add_ok_msg(get_string('institutiontagsaved'));
}
else {
$SESSION->add_error_msg(get_string('institutiontagcantbesaved'));
}
redirect("/admin/users/institutiontags.php?institution={$institution}");
}
/**
* Cancel the submission of the new institution tag form.
*/
function institutiontag_cancel_submit() {
global $institution;
redirect("/admin/users/institutiontags.php?institution={$institution}");
}
/**
* Validate the submitted data from the new institution tag form. New tags must not:
* - be empty strings
* - match an existing tag within the institution
*
* @param Pieform $form The form to validate
* @param array $values The values submitted
*/
function institutiontag_validate(Pieform $form, $values) {
global $institution;
// Don't even start attempting to parse if there are previous errors
if ($form->has_errors()) {
return;
}
if (empty(trim($values['tag'])) || trim($values['tag']) === '') {
$form->set_error('tag', get_string('error:emptytag'));
return;
}
$id = get_field('institution', 'id', 'name', $institution);
if (record_exists('tag', 'resourcetype', 'institution', 'resourceid', $id, 'tag', $values['tag'])) {
$form->set_error('tag', get_string('error:duplicatetag'));
return;
}
}
// Get the institution tags and their used status.
$typecast = is_postgres() ? '::varchar' : '';
$sql = "
SELECT id, tag, SUM(count) AS count
FROM (
SELECT id, tag, 0 AS count
FROM {tag}
WHERE resourcetype = 'institution'
AND ownertype = 'institution' AND ownerid IN (?)
UNION
SELECT t2.id, t2.tag AS tag, COUNT(t2.tag) AS count
FROM {tag} t
JOIN {tag} t2 ON t2.id" . $typecast . " = SUBSTRING(t.tag, 7)
JOIN {institution} i ON i.name = t2.ownerid
WHERE t.resourcetype IN ('artefact', 'view', 'collection') AND i.name = ?
GROUP BY 1, 2
) AS tags
GROUP BY tags.tag, tags.id
ORDER BY LOWER(tags.tag)";
$tags = get_records_sql_assoc($sql, array($institution, $institution));
// Delete tag.
$delete = param_integer('delete', null);
if ($delete) {
db_begin();
if (isset($tags[$delete]) && $tags[$delete]->count == 0 && delete_records_select('tag', " ownertype = 'institution' AND ownerid = ? AND id = ?", array($institution, $delete))) {
$SESSION->add_ok_msg(get_string('institutiontagdeleted'));
}
else {
$SESSION->add_error_msg(get_string('institutiontagdeletefail'));
}
db_commit();
redirect("/admin/users/institutiontags.php?institution=" . $institution);
}
if (!$tags) {
$tags = array();
}
$smarty = smarty(array('paginator'));
setpageicon($smarty, 'icon-university');
$smarty->assign('institutionselector', $institutionselector);
$smarty->assign('INLINEJAVASCRIPT', $js);
$smarty->assign('canedit', $canedit);
$smarty->assign('institution', $institution);
$smarty->assign('new', $new);
$smarty->assign('form', $form);
$smarty->assign('tags', $tags);
$smarty->assign('SUBPAGETOP', 'admin/users/institutiontagsactions.tpl');
$smarty->assign('addonelink', get_config('wwwroot') . "admin/users/institutiontags.php?new=1&institution={$institution}");
$smarty->display('admin/users/institutiontags.tpl');
......@@ -348,13 +348,13 @@ function search_folders_and_files($username, $search='') {
$filetypesql = "('" . join("','", $filetypes) . "')";
$ownersql = artefact_owner_sql($user->id);
//retrieve folders and files of a specific Mahara folder
$typecast = is_postgres() ? '::varchar' : '';
// Retrieve folders and files of a specific Mahara folder
$sql = "SELECT
*
FROM
{artefact} a
LEFT JOIN {artefact_tag} at ON (at.artefact = a.id)
LEFT JOIN {tag} at ON (at.resourcetype = 'artefact' AND at.resourceid = a.id" . $typecast . ")
WHERE
$ownersql
AND
......
......@@ -107,31 +107,32 @@ class PluginBlocktypeTaggedposts extends MaharaCoreBlocktype {
}
$tagsout = array_filter($tagsout);
$sqlvalues = array($view);
$typecast = is_postgres() ? '::varchar' : '';
$sql =
'SELECT a.title, p.title AS parenttitle, a.id, a.parent, a.owner, a.description, a.allowcomments, at.tag, a.ctime, a.mtime
"SELECT a.title, p.title AS parenttitle, a.id, a.parent, a.owner, a.description, a.allowcomments, at.tag, a.ctime, a.mtime
FROM {artefact} a
JOIN {artefact} p ON a.parent = p.id
JOIN {artefact_blog_blogpost} ab ON (ab.blogpost = a.id AND ab.published = 1)
JOIN {artefact_tag} at ON (at.artefact = a.id)
WHERE a.artefacttype = \'blogpost\'
AND a.owner = (SELECT "owner" from {view} WHERE id = ?)';
JOIN {tag} at ON (at.resourcetype = 'artefact' AND at.resourceid = a.id" . $typecast . ")
WHERE a.artefacttype = 'blogpost'
AND a.owner = (SELECT \"owner\" from {view} WHERE id = ?)";
if (!empty($tagsin)) {
foreach ($tagsin as $tagin) {
$sql .= ' AND EXISTS (
SELECT * FROM {artefact_tag} AS at
WHERE a.id = at.artefact
$sql .= " AND EXISTS (
SELECT * FROM {tag} AS at
WHERE at.resourcetype = 'artefact' AND at.resourceid = a.id" . $typecast . "
AND at.tag = ?
)';
)";
}
$sqlvalues = array_merge($sqlvalues, $tagsin);
}
if (!empty($tagsout)) {
foreach ($tagsout as $tagout) {
$sql .= ' AND NOT EXISTS (
SELECT * FROM {artefact_tag} AS at
WHERE a.id = at.artefact
$sql .= " AND NOT EXISTS (
SELECT * FROM {tag} AS at
WHERE at.resourcetype = 'artefact' AND at.resourceid = a.id" . $typecast . "
AND at.tag = ?
)';
)";
}
$sqlvalues = array_merge($sqlvalues, $tagsout);
}
......@@ -234,7 +235,7 @@ class PluginBlocktypeTaggedposts extends MaharaCoreBlocktype {
$result->comments = $comments;
// get all tags for this post
$taglist = get_records_array('artefact_tag', 'artefact', $result->id, "tag DESC");
$taglist = get_records_sql_array("SELECT tag FROM {tag} WHERE resourcetype = 'artefact' AND resourceid = ? ORDER BY tag DESC", array($result->id));
foreach ($taglist as $t) {
$result->taglist[] = $t->tag;
}
......@@ -281,6 +282,15 @@ class PluginBlocktypeTaggedposts extends MaharaCoreBlocktype {
if ($key > 0) {
$tagstr .= ', ';
}
if (strpos($tag, 'tagid_') !== false) {
$tags = get_records_sql_array("
SELECT CONCAT(i.displayname, ': ', t.tag) AS tag, t.resourceid
FROM {tag} t
LEFT JOIN {institution} i ON i.name = t.ownerid
WHERE t.id = ?", array(substr($tag, 6, 5))
);
$tag = $tags[0]->tag;
}
$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)) {
......@@ -318,12 +328,11 @@ class PluginBlocktypeTaggedposts extends MaharaCoreBlocktype {
private static function get_chooseable_tags() {
global $USER;
$typecast = is_postgres() ? '::varchar' : '';
return get_records_sql_array("
SELECT at.tag
FROM
{artefact_tag} at
JOIN {artefact} a
ON a.id = at.artefact
FROM {tag} at
JOIN {artefact} a ON (at.resourcetype ='artefact' AND at.resourceid = a.id" . $typecast . ")
WHERE
a.owner = ?
AND a.artefacttype = 'blogpost'
......@@ -345,7 +354,18 @@ class PluginBlocktypeTaggedposts extends MaharaCoreBlocktype {
$elements = array();
if (!empty($tags)) {
$tagselect = array();
$tagrecords = get_records_array('blocktype_taggedposts_tags', 'block_instance', $instance->get('id'), 'tagtype desc, tag', 'tag, tagtype');
$typecast = is_postgres() ? '::varchar' : '';
$tagrecords = get_records_sql_array("
SELECT
(CASE
WHEN bt.tag LIKE 'tagid_%' THEN CONCAT(i.displayname, ': ', t.tag)
ELSE bt.tag
END) AS tag, bt.tagtype
FROM {blocktype_taggedposts_tags} bt
LEFT JOIN {tag} t ON t.id" . $typecast . " = SUBSTRING(bt.tag, 7)
LEFT JOIN {institution} i ON i.name = t.ownerid
WHERE bt.block_instance = ?
ORDER BY tagtype DESC", array($instance->get('id')));
if ($tagrecords) {
foreach ($tagrecords as $tag) {
if ($tag->tagtype == PluginBlocktypeTaggedposts::TAGTYPE_INCLUDE) {
......@@ -459,6 +479,16 @@ EOF;
$value = PluginBlocktypeTaggedposts::TAGTYPE_EXCLUDE;
$tag = substr($tag, 1);
}
// If tag is institution tag, save it's correct form.
if (strpos($tag, ':')) {
$tagarray = explode(': ', $tag);
$sql = "SELECT t.id
FROM {tag} t
JOIN {institution} i ON i.name = t.ownerid
WHERE t.tag = ? AND t.resourcetype = 'institution' AND i.displayname = ?";
$insttagid = get_field_sql($sql, array($tagarray[1], $tagarray[0]));
$tag = 'tagid_' . $insttagid;
}
$todb = new stdClass();
$todb->block_instance = $instance->get('id');
$todb->tag = htmlspecialchars_decode($tag);
......
......@@ -28,16 +28,28 @@ if ($page < 1) {
}
$tagsperpage = 5;
$values = array($USER->id);
$sql = "SELECT at.tag FROM {artefact_tag} at
JOIN {artefact} a ON a.id = at.artefact
$typecast = is_postgres() ? '::varchar' : '';
$sql = "SELECT
(CASE
WHEN at.tag LIKE 'tagid_%' THEN CONCAT(i.displayname, ': ', t2.tag)
ELSE at.tag
END) AS tag
FROM {tag} at
LEFT JOIN {tag} t2 ON t2.id" . $typecast . " = SUBSTRING(at.tag, 7)
LEFT JOIN {institution} i ON i.name = t2.ownerid
JOIN {artefact} a ON (at.resourcetype = 'artefact' AND at.resourceid = a.id" . $typecast . ")
WHERE a.owner = ?
AND at.resourcetype = 'artefact'
AND at.resourceid = a.id" . $typecast . "
AND a.artefacttype = 'blogpost'";
if ($request !== '') {
$sql .= " AND at.tag LIKE '%' || ? || '%'";
$sql .= " AND (at.tag LIKE '%' || ? || '%' OR t2.tag LIKE '%' || ? || '%')";
$values[] = $request;
$values[] = $request;
}
$sql .= " GROUP BY at.tag
ORDER BY at.tag ASC";
// We need to do group/order by alias of first column (tag) so we use column positioning
$sql .= " GROUP BY 1, i.displayname
ORDER BY 1 ASC";
$more = true;
$tmptags = array();
$alltags = get_records_sql_array($sql, $values);
......
......@@ -1056,7 +1056,7 @@ class ArtefactTypeBlogPost extends ArtefactType {
if ($tags = ArtefactType::tags_from_id_list($postids)) {
foreach($tags as &$at) {
$data[$at->artefact]->tags[] = $at->tag;
$data[$at->resourceid]->tags[] = $at->tag;
}
}
......
......@@ -693,13 +693,24 @@ abstract class ArtefactTypeFileBase extends ArtefactType {
}
}
}
$where = 'artefact IN (' . join(',', array_keys($filedata)) . ')';
$tags = get_records_select_array('artefact_tag', $where);
$tagwhere = "'" . join("','", array_keys($filedata)) . "'";
$typecast = is_postgres() ? '::varchar' : '';
$tags = get_records_sql_array("
SELECT
(CASE
WHEN t.tag LIKE 'tagid_%' THEN CONCAT(i.displayname, ': ', t2.tag)
ELSE t.tag
END) AS tag, t.resourceid
FROM {tag} t
LEFT JOIN {tag} t2 ON t2.id" . $typecast . " = SUBSTRING(t.tag, 7)
LEFT JOIN {institution} i ON i.name = t2.ownerid
WHERE t.resourcetype = 'artefact' AND t.resourceid IN (" . $tagwhere . ")");
if ($tags) {
foreach ($tags as $t) {
$filedata[$t->artefact]->tags[] = $t->tag;
$filedata[$t->resourceid]->tags[] = $t->tag;
}
}
$where = 'artefact IN (' . join(',', array_keys($filedata)) . ')';
if ($group) { // Fetch permissions for each artefact
$perms = get_records_select_array('artefact_access_role', $where);
if ($perms) {
......
......@@ -588,6 +588,8 @@ abstract class ArtefactType implements IArtefactType {
* this method, and call parent::commit() in your own function.
*/
public function commit() {
global $USER;
static $last_source, $last_output;
$is_new = false;
......@@ -634,20 +636,40 @@ abstract class ArtefactType implements IArtefactType {
}
if (!$is_new) {
$deleted = delete_records('artefact_tag', 'artefact', $this->id);
$deleted = delete_records('tag', 'resourcetype', 'artefact', 'resourceid', $this->id);
}
if (is_array($this->tags)) {
$this->tags = check_case_sensitive($this->tags, 'artefact_tag');
if ($this->group) {
$ownertype = 'group';
$ownerid = $this->group;
}
else if ($this->institution) {
$ownertype = 'institution';
$ownerid = $this->institution;
}
else {
$ownertype = 'user';
$ownerid = $this->owner;
}
$this->tags = check_case_sensitive($this->tags, 'tag');
foreach (array_unique($this->tags) as $tag) {
if (empty($tag)) {
continue;
}
insert_record(
'artefact_tag',
if ($institutiontag = get_record('tag', 'tag', $tag, 'resourcetype', 'institution', 'ownertype', 'institution')) {
$tag = 'tagid_' . $institutiontag->id;
}
insert_record('tag',
(object) array(
'artefact' => $this->id,
'tag' => $tag,
'resourcetype' => 'artefact',
'resourceid' => $this->get('id'),
'ownertype' => $ownertype,
'ownerid' => $ownerid,
'tag' => $tag,
'ctime' => db_format_timestamp(time()),
'editedby' => $USER->get('id'),
)
);
}
......@@ -831,7 +853,7 @@ abstract class ArtefactType implements IArtefactType {
BlockInstance::bulk_remove_artefacts($artefactids);
delete_records_select('view_artefact', "artefact IN $idstr");
delete_records_select('artefact_tag', "artefact IN $idstr");
delete_records_select('tag', "resourcetype = 'artefact' AND resourceid IN ('" . join("','", array_map('intval', $artefactids)) . "')");
delete_records_select('artefact_access_role', "artefact IN $idstr");
delete_records_select('artefact_access_usr', "artefact IN $idstr");
execute_sql("UPDATE {usr} SET profileicon = NULL WHERE profileicon IN $idstr");
......@@ -1215,8 +1237,18 @@ abstract class ArtefactType implements IArtefactType {
if (empty($artefactids)) {
return array();
}