Merge branch 'MDL-57455_master' of git://github.com/markn86/moodle

This commit is contained in:
Jake Dallimore 2017-10-16 10:34:01 +08:00
commit 6b76e041f4
18 changed files with 967 additions and 97 deletions

View File

@ -47,6 +47,9 @@ class backup_data_activity_structure_step extends backup_activity_structure_step
'assessed', 'assesstimestart', 'assesstimefinish', 'defaultsort',
'defaultsortdir', 'editany', 'notification', 'timemodified', 'config', 'completionentries'));
$tags = new backup_nested_element('recordstags');
$tag = new backup_nested_element('tag', array('id'), array('itemid', 'rawname'));
$fields = new backup_nested_element('fields');
$field = new backup_nested_element('field', array('id'), array(
@ -84,6 +87,9 @@ class backup_data_activity_structure_step extends backup_activity_structure_step
$record->add_child($ratings);
$ratings->add_child($rating);
$data->add_child($tags);
$tags->add_child($tag);
// Define sources
$data->set_source_table('data', array('id' => backup::VAR_ACTIVITYID));
@ -104,6 +110,18 @@ class backup_data_activity_structure_step extends backup_activity_structure_step
'component' => backup_helper::is_sqlparam('mod_data'),
'ratingarea' => backup_helper::is_sqlparam('entry')));
$rating->set_source_alias('rating', 'value');
if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
$tag->set_source_sql('SELECT t.id, ti.itemid, t.rawname
FROM {tag} t
JOIN {tag_instance} ti
ON ti.tagid = t.id
WHERE ti.itemtype = ?
AND ti.component = ?
AND ti.contextid = ?', array(
backup_helper::is_sqlparam('data_records'),
backup_helper::is_sqlparam('mod_data'),
backup::VAR_CONTEXTID));
}
}
// Define id annotations

View File

@ -42,6 +42,7 @@ class restore_data_activity_structure_step extends restore_activity_structure_st
$paths[] = new restore_path_element('data_record', '/activity/data/records/record');
$paths[] = new restore_path_element('data_content', '/activity/data/records/record/contents/content');
$paths[] = new restore_path_element('data_rating', '/activity/data/records/record/ratings/rating');
$paths[] = new restore_path_element('data_record_tag', '/activity/data/recordstags/tag');
}
// Return the paths wrapped into standard activity structure
@ -121,6 +122,28 @@ class restore_data_activity_structure_step extends restore_activity_structure_st
$this->set_mapping('data_content', $oldid, $newitemid, true); // files by this itemname
}
/**
* Add tags to restored records.
*
* @param stdClass $data Tag
*/
protected function process_data_record_tag($data) {
$data = (object)$data;
if (!core_tag_tag::is_enabled('mod_data', 'data_records')) { // Tags disabled in server, nothing to process.
return;
}
if (!$itemid = $this->get_mappingid('data_record', $data->itemid)) {
// Some orphaned tag, we could not find the data record for it - ignore.
return;
}
$tag = $data->rawname;
$context = context_module::instance($this->task->get_moduleid());
core_tag_tag::add_item_tag('mod_data', 'data_records', $itemid, $context, $tag);
}
protected function process_data_rating($data) {
global $DB;

34
mod/data/db/tag.php Normal file
View File

@ -0,0 +1,34 @@
<?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/>.
/**
* Tag areas in component mod_data
*
* @package mod_data
* @copyright 2017 Andrew Hancox <andrewdchancox@googlemail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$tagareas = array(
array(
'itemtype' => 'data_records',
'component' => 'mod_data',
'callback' => 'mod_data_get_tagged_records',
'callbackfile' => '/mod/data/locallib.php',
),
);

View File

@ -33,8 +33,7 @@ $d = optional_param('d', 0, PARAM_INT); // database id
$rid = optional_param('rid', 0, PARAM_INT); //record id
$cancel = optional_param('cancel', '', PARAM_RAW); // cancel an add
$mode ='addtemplate'; //define the mode for this page, only 1 mode available
$tags = optional_param_array('tags', [], PARAM_TAGLIST);
$url = new moodle_url('/mod/data/edit.php');
if ($rid !== 0) {
@ -182,6 +181,7 @@ if ($datarecord = data_submitted() and confirm_sesskey()) {
if ($processeddata->validated) {
// Enough data to update the record.
data_update_record_fields_contents($data, $record, $context, $datarecord, $processeddata);
core_tag_tag::set_item_tags('mod_data', 'data_records', $rid, $context, $tags);
$viewurl = new moodle_url('/mod/data/view.php', array(
'd' => $data->id,
@ -209,6 +209,8 @@ if ($datarecord = data_submitted() and confirm_sesskey()) {
// Now populate the fields contents of the new record.
data_add_fields_contents_to_new_record($data, $context, $recordid, $fields, $datarecord, $processeddata);
core_tag_tag::set_item_tags('mod_data', 'data_records', $recordid, $context, $tags);
if (!empty($datarecord->saveandview)) {
$viewurl = new moodle_url('/mod/data/view.php', array(
'd' => $data->id,
@ -287,6 +289,12 @@ if ($data->addtemplate){
$patterns[] = "[[".$field->field->name."#id]]";
$replacements[] = 'field_'.$field->field->id;
}
if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
$patterns[] = "##tags##";
$replacements[] = data_generate_tag_form($rid);
}
$newtext = str_ireplace($patterns, $replacements, $data->{$mode});
} else { //if the add template is not yet defined, print the default form!

View File

@ -32,6 +32,7 @@ $d = required_param('d', PARAM_INT);
$exportuser = optional_param('exportuser', false, PARAM_BOOL); // Flag for exporting user details
$exporttime = optional_param('exporttime', false, PARAM_BOOL); // Flag for exporting date/time information
$exportapproval = optional_param('exportapproval', false, PARAM_BOOL); // Flag for exporting user details
$tags = optional_param('exporttags', false, PARAM_BOOL); // Flag for exporting user details.
$PAGE->set_url('/mod/data/export.php', array('d'=>$d));
@ -111,7 +112,7 @@ foreach ($formdata as $key => $value) {
$currentgroup = groups_get_activity_group($cm);
$exportdata = data_get_exportdata($data->id, $fields, $selectedfields, $currentgroup, $context,
$exportuser, $exporttime, $exportapproval);
$exportuser, $exporttime, $exportapproval, $tags);
$count = count($exportdata);
switch ($formdata['exporttype']) {
case 'csv':

View File

@ -85,6 +85,11 @@ class mod_data_export_form extends moodleform {
if ($this->_data->approval) {
$mform->addElement('checkbox', 'exportapproval', get_string('includeapproval', 'data'));
}
if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
$mform->addElement('checkbox', 'exporttags', get_string('includetags', 'data'));
}
$this->add_action_buttons(true, get_string('exportentries', 'data'));
}

View File

@ -116,7 +116,7 @@ if (!$formdata = $form->get_data()) {
$errorfield = '';
$safetoskipfields = array(get_string('user'), get_string('username'), get_string('email'),
get_string('timeadded', 'data'), get_string('timemodified', 'data'),
get_string('approved', 'data'));
get_string('approved', 'data'), get_string('tags', 'data'));
foreach ($fieldnames as $name => $id) {
if (!isset($rawfields[$name])) {
if (!in_array($name, $safetoskipfields)) {
@ -156,6 +156,21 @@ if (!$formdata = $form->get_data()) {
$DB->insert_record('data_content', $content);
}
}
if (core_tag_tag::is_enabled('mod_data', 'data_records') &&
isset($fieldnames[get_string('tags', 'data')])) {
$columnindex = $fieldnames[get_string('tags', 'data')];
$rawtags = $record[$columnindex];
$tags = explode(',', $rawtags);
foreach ($tags as $tag) {
$tag = trim($tag);
if (empty($tag)) {
continue;
}
core_tag_tag::add_item_tag('mod_data', 'data_records', $recordid, $context, $tag);
}
}
$recordsadded++;
print get_string('added', 'moodle', $recordsadded) . ". " . get_string('entry', 'data') . " (ID $recordid)<br />\n";
}

View File

@ -201,6 +201,7 @@ $string['expired'] = 'Sorry, this activity closed on {$a} and is no longer avail
$string['importentries'] = 'Import entries';
$string['importsuccess'] = 'The preset has been successfully applied.';
$string['includeapproval'] = 'Include approval status';
$string['includetags'] = 'Include tags';
$string['includetime'] = 'Include time added/modified';
$string['includeuserdetails'] = 'Include user details';
$string['indicator:cognitivedepth'] = 'Database cognitive';
@ -305,6 +306,7 @@ $string['recorddeleted'] = 'Entry deleted';
$string['recorddisapproved'] = 'Entry unapproved';
$string['recordsnotsaved'] = 'No entry was saved. Please check the format of the uploaded file.';
$string['recordssaved'] = 'entries saved';
$string['removealldatatags'] = 'Remove all database tags';
$string['requireapproval'] = 'Approval required';
$string['requireapproval_help'] = 'If enabled, entries require approving by a teacher before they are viewable by everyone.';
$string['required'] = 'Required';
@ -345,6 +347,9 @@ $string['subplugintype_datafield'] = 'Database field type';
$string['subplugintype_datafield_plural'] = 'Database field types';
$string['subplugintype_datapreset'] = 'Preset';
$string['subplugintype_datapreset_plural'] = 'Presets';
$string['tagarea_data_records'] = 'Data records';
$string['tags'] = 'tags';
$string['tagsdeleted'] = 'Database tags have been deleted';
$string['teachersandstudents'] = '{$a->teachers} and {$a->students}';
$string['templates'] = 'Templates';
$string['templatesaved'] = 'Template saved';

View File

@ -32,6 +32,7 @@ define ('DATA_LASTNAME', -2);
define ('DATA_APPROVED', -3);
define ('DATA_TIMEADDED', 0);
define ('DATA_TIMEMODIFIED', -4);
define ('DATA_TAGS', -5);
define ('DATA_CAP_EXPORT', 'mod/data:viewalluserpresets');
@ -622,6 +623,17 @@ function data_generate_default_template(&$data, $template, $recordid=0, $form=fa
$token
);
}
if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
$label = new html_table_cell(get_string('tags') . ':');
if ($form) {
$cell = data_generate_tag_form();
} else {
$cell = new html_table_cell('##tags##');
}
$table->data[] = new html_table_row(array($label, $cell));
}
if ($template == 'listtemplate') {
$cell = new html_table_cell('##edit## ##more## ##delete## ##approve## ##disapprove## ##export##');
$cell->colspan = 2;
@ -666,6 +678,75 @@ function data_generate_default_template(&$data, $template, $recordid=0, $form=fa
}
}
/**
* Build the form elements to manage tags for a record.
*
* @param int|bool $recordid
* @param string[] $selected raw tag names
* @return string
*/
function data_generate_tag_form($recordid = false, $selected = []) {
global $CFG, $DB, $OUTPUT, $PAGE;
$tagtypestoshow = \core_tag_area::get_showstandard('mod_data', 'data_records');
$showstandard = ($tagtypestoshow != core_tag_tag::HIDE_STANDARD);
$typenewtags = ($tagtypestoshow != core_tag_tag::STANDARD_ONLY);
$str = html_writer::start_tag('div', array('class' => 'datatagcontrol'));
$namefield = empty($CFG->keeptagnamecase) ? 'name' : 'rawname';
$tagcollid = \core_tag_area::get_collection('mod_data', 'data_records');
$tags = [];
$selectedtags = [];
if ($showstandard) {
$tags += $DB->get_records_menu('tag', array('isstandard' => 1, 'tagcollid' => $tagcollid),
$namefield, 'id,' . $namefield . ' as fieldname');
}
if ($recordid) {
$selectedtags += core_tag_tag::get_item_tags_array('mod_data', 'data_records', $recordid);
}
if (!empty($selected)) {
list($sql, $params) = $DB->get_in_or_equal($selected, SQL_PARAMS_NAMED);
$params['tagcollid'] = $tagcollid;
$sql = "SELECT id, $namefield FROM {tag} WHERE tagcollid = :tagcollid AND rawname $sql";
$selectedtags += $DB->get_records_sql_menu($sql, $params);
}
$tags += $selectedtags;
$str .= '<select class="custom-select" name="tags[]" id="tags" multiple>';
foreach ($tags as $tagid => $tag) {
$selected = key_exists($tagid, $selectedtags) ? 'selected' : '';
$str .= "<option value='$tag' $selected>$tag</option>";
}
$str .= '</select>';
if (has_capability('moodle/tag:manage', context_system::instance()) && $showstandard) {
$url = new moodle_url('/tag/manage.php', array('tc' => core_tag_area::get_collection('mod_data',
'data_records')));
$str .= ' ' . $OUTPUT->action_link($url, get_string('managestandardtags', 'tag'));
}
$PAGE->requires->js_call_amd('core/form-autocomplete', 'enhance', $params = array(
'#tags',
$typenewtags,
'',
get_string('entertags', 'tag'),
false,
$showstandard,
get_string('noselection', 'form')
)
);
$str .= html_writer::end_tag('div');
return $str;
}
/**
* Search for a field name and replaces it with another one in all the
@ -1442,6 +1523,12 @@ function data_print_template($template, $records, $data, $search='', $page=0, $r
$replacement[] = '';
}
if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
$patterns[] = "##tags##";
$replacement[] = $OUTPUT->tag_list(
core_tag_tag::get_item_tags('mod_data', 'data_records', $record->id), '', 'data-tags');
}
// actual replacement of the tags
$newtext = str_ireplace($patterns, $replacement, $data->{$template});
@ -1824,6 +1911,12 @@ function data_print_preference_form($data, $perpage, $search, $sort='', $order='
$replacement[] = '<label class="accesshide" for="u_ln">' . get_string('authorlastname', 'data') . '</label>' .
'<input type="text" class="form-control" size="16" id="u_ln" name="u_ln" value="' . s($ln) . '" />';
if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
$patterns[] = "/##tags##/";
$selectedtags = isset($search_array[DATA_TAGS]->rawtagnames) ? $search_array[DATA_TAGS]->rawtagnames : [];
$replacement[] = data_generate_tag_form(false, $selectedtags);
}
// actual replacement of the tags
$newtext = preg_replace($patterns, $replacement, $data->asearchtemplate);
@ -2707,6 +2800,9 @@ function data_reset_course_form_definition(&$mform) {
$mform->addElement('checkbox', 'reset_data_comments', get_string('deleteallcomments'));
$mform->disabledIf('reset_data_comments', 'reset_data', 'checked');
$mform->addElement('checkbox', 'reset_data_tags', get_string('removealldatatags', 'data'));
$mform->disabledIf('reset_data_tags', 'reset_data', 'checked');
}
/**
@ -2791,6 +2887,8 @@ function data_reset_userdata($data) {
$ratingdeloptions->contextid = $datacontext->id;
$rm->delete_ratings($ratingdeloptions);
core_tag_tag::delete_instances('mod_data', null, $datacontext->id);
}
}
@ -2833,6 +2931,8 @@ function data_reset_userdata($data) {
}
$notenrolled[$record->userid] = true;
core_tag_tag::remove_all_item_tags('mod_data', 'data_records', $record->id);
$DB->delete_records('comments', array('itemid' => $record->id, 'commentarea' => 'database_entry'));
$DB->delete_records('data_content', array('recordid' => $record->id));
$DB->delete_records('data_records', array('id' => $record->id));
@ -2870,6 +2970,22 @@ function data_reset_userdata($data) {
$status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallcomments'), 'error'=>false);
}
// Remove all the tags.
if (!empty($data->reset_data_tags)) {
if ($datas = $DB->get_records_sql($alldatassql, array($data->courseid))) {
foreach ($datas as $dataid => $unused) {
if (!$cm = get_coursemodule_from_instance('data', $dataid)) {
continue;
}
$context = context_module::instance($cm->id);
core_tag_tag::delete_instances('mod_data', null, $context->id);
}
}
$status[] = array('component' => $componentstr, 'item' => get_string('tagsdeleted', 'data'), 'error' => false);
}
// updating dates - shift may be negative too
if ($data->timeshift) {
// Any changes to the list of dates that needs to be rolled should be same during course restore and course reset.
@ -3016,10 +3132,11 @@ function data_export_ods($export, $dataname, $count) {
* @param bool $userdetails whether to include the details of the record author
* @param bool $time whether to include time created/modified
* @param bool $approval whether to include approval status
* @param bool $tags whether to include tags
* @return array
*/
function data_get_exportdata($dataid, $fields, $selectedfields, $currentgroup=0, $context=null,
$userdetails=false, $time=false, $approval=false) {
$userdetails=false, $time=false, $approval=false, $tags = false) {
global $DB;
if (is_null($context)) {
@ -3051,6 +3168,9 @@ function data_get_exportdata($dataid, $fields, $selectedfields, $currentgroup=0,
if ($approval) {
$exportdata[0][] = get_string('approved', 'data');
}
if ($tags) {
$exportdata[0][] = get_string('tags', 'data');
}
$datarecords = $DB->get_records('data_records', array('dataid'=>$dataid));
ksort($datarecords);
@ -3086,6 +3206,10 @@ function data_get_exportdata($dataid, $fields, $selectedfields, $currentgroup=0,
if ($approval) { // Add approval status
$exportdata[$line][] = (int) $record->approved;
}
if ($tags) {
$itemtags = \core_tag_tag::get_item_tags_array('mod_data', 'data_records', $record->id);
$exportdata[$line][] = implode(', ', $itemtags);
}
}
$line++;
}
@ -3783,14 +3907,14 @@ function data_get_recordids($alias, $searcharray, $dataid, $recordids) {
}
list($insql, $params) = $DB->get_in_or_equal($recordids, SQL_PARAMS_NAMED);
$nestselect = 'SELECT c' . $alias . '.recordid
FROM {data_content} c' . $alias . ',
{data_fields} f,
{data_records} r,
{user} u ';
$nestwhere = 'WHERE u.id = r.userid
AND f.id = c' . $alias . '.fieldid
AND r.id = c' . $alias . '.recordid
AND r.dataid = :dataid
FROM {data_content} c' . $alias . '
INNER JOIN {data_fields} f
ON f.id = c' . $alias . '.fieldid
INNER JOIN {data_records} r
ON r.id = c' . $alias . '.recordid
INNER JOIN {user} u
ON u.id = r.userid ';
$nestwhere = 'WHERE r.dataid = :dataid
AND c' . $alias .'.recordid ' . $insql . '
AND ';
@ -3801,6 +3925,25 @@ function data_get_recordids($alias, $searcharray, $dataid, $recordids) {
} else if ($searchcriteria == DATA_TIMEMODIFIED) {
$nestsql = $nestselect . $nestwhere . $nestsearch->field . ' >= :timemodified GROUP BY c' . $alias . '.recordid';
$params['timemodified'] = $nestsearch->data;
} else if ($searchcriteria == DATA_TAGS) {
if (empty($nestsearch->rawtagnames)) {
return [];
}
$i = 0;
$tagwhere = [];
$tagselect = '';
foreach ($nestsearch->rawtagnames as $tagrawname) {
$tagselect .= " INNER JOIN {tag_instance} AS ti_$i
ON ti_$i.component = 'mod_data'
AND ti_$i.itemtype = 'data_records'
AND ti_$i.itemid = r.id
INNER JOIN {tag} AS t_$i
ON ti_$i.tagid = t_$i.id ";
$tagwhere[] = " t_$i.rawname = :trawname_$i ";
$params["trawname_$i"] = $tagrawname;
$i++;
}
$nestsql = $nestselect . $tagselect . $nestwhere . implode(' AND ', $tagwhere);
} else { // First name or last name.
$thing = $DB->sql_like($nestsearch->field, ':search1', false);
$nestsql = $nestselect . $nestwhere . $thing . ' GROUP BY c' . $alias . '.recordid';
@ -3947,6 +4090,8 @@ function data_delete_record($recordid, $data, $courseid, $cmid) {
data_rss_delete_file($data);
}
core_tag_tag::remove_all_item_tags('mod_data', 'data_records', $recordid);
// Trigger an event for deleting this record.
$event = \mod_data\event\record_deleted::create(array(
'objectid' => $deleterecord->id,

View File

@ -771,6 +771,250 @@ function data_get_entries_left_to_view($data, $numentries, $canmanageentries) {
return 0;
}
/**
* Returns data records tagged with a specified tag.
*
* This is a callback used by the tag area mod_data/data_records to search for data records
* tagged with a specific tag.
*
* @param core_tag_tag $tag
* @param bool $exclusivemode if set to true it means that no other entities tagged with this tag
* are displayed on the page and the per-page limit may be bigger
* @param int $fromctx context id where the link was displayed, may be used by callbacks
* to display items in the same context first
* @param int $ctx context id where to search for records
* @param bool $rec search in subcontexts as well
* @param int $page 0-based number of page being displayed
* @return \core_tag\output\tagindex
*/
function mod_data_get_tagged_records($tag, $exclusivemode = false, $fromctx = 0, $ctx = 0, $rec = true, $page = 0) {
global $DB, $OUTPUT, $USER;
$perpage = $exclusivemode ? 20 : 5;
// Build the SQL query.
$ctxselect = context_helper::get_preload_record_columns_sql('ctx');
$query = "SELECT dr.id, dr.dataid, dr.approved, d.timeviewfrom, d.timeviewto, dr.groupid, d.approval, dr.userid,
d.requiredentriestoview, cm.id AS cmid, c.id AS courseid, c.shortname, c.fullname, $ctxselect
FROM {data_records} dr
JOIN {data} d
ON d.id = dr.dataid
JOIN {modules} m
ON m.name = 'data'
JOIN {course_modules} cm
ON cm.module = m.id AND cm.instance = d.id
JOIN {tag_instance} tt
ON dr.id = tt.itemid
JOIN {course} c
ON cm.course = c.id
JOIN {context} ctx
ON ctx.instanceid = cm.id AND ctx.contextlevel = :coursemodulecontextlevel
WHERE tt.itemtype = :itemtype
AND tt.tagid = :tagid
AND tt.component = :component
AND cm.deletioninprogress = 0
AND dr.id %ITEMFILTER%
AND c.id %COURSEFILTER%";
$params = array(
'itemtype' => 'data_records',
'tagid' => $tag->id,
'component' => 'mod_data',
'coursemodulecontextlevel' => CONTEXT_MODULE
);
if ($ctx) {
$context = $ctx ? context::instance_by_id($ctx) : context_system::instance();
$query .= $rec ? ' AND (ctx.id = :contextid OR ctx.path LIKE :path)' : ' AND ctx.id = :contextid';
$params['contextid'] = $context->id;
$params['path'] = $context->path . '/%';
}
$query .= " ORDER BY ";
if ($fromctx) {
// In order-clause specify that modules from inside "fromctx" context should be returned first.
$fromcontext = context::instance_by_id($fromctx);
$query .= ' (CASE WHEN ctx.id = :fromcontextid OR ctx.path LIKE :frompath THEN 0 ELSE 1 END),';
$params['fromcontextid'] = $fromcontext->id;
$params['frompath'] = $fromcontext->path . '/%';
}
$query .= ' c.sortorder, cm.id, dr.id';
$totalpages = $page + 1;
// Use core_tag_index_builder to build and filter the list of items.
$builder = new core_tag_index_builder('mod_data', 'data_records', $query, $params, $page * $perpage, $perpage + 1);
$now = time();
$entrycount = [];
$activitygroupmode = [];
$usergroups = [];
$titlefields = [];
while ($item = $builder->has_item_that_needs_access_check()) {
context_helper::preload_from_record($item);
$modinfo = get_fast_modinfo($item->courseid);
$cm = $modinfo->get_cm($item->cmid);
$context = \context_module::instance($cm->id);
$courseid = $item->courseid;
if (!$builder->can_access_course($courseid)) {
$builder->set_accessible($item, false);
continue;
}
if (!$cm->uservisible) {
$builder->set_accessible($item, false);
continue;
}
if (!has_capability('mod/data:viewentry', $context)) {
$builder->set_accessible($item, false);
continue;
}
if ($USER->id != $item->userid && (($item->timeviewfrom && $now < $item->timeviewfrom)
|| ($item->timeviewto && $now > $item->timeviewto))) {
$builder->set_accessible($item, false);
continue;
}
if ($USER->id != $item->userid && $item->approval && !$item->approved) {
$builder->set_accessible($item, false);
continue;
}
if ($item->requiredentriestoview) {
if (!isset($entrycount[$item->dataid])) {
$entrycount[$item->dataid] = $DB->count_records('data_records', array('dataid' => $item->dataid));
}
$sufficiententries = $item->requiredentriestoview > $entrycount[$item->dataid];
$builder->set_accessible($item, $sufficiententries);
}
if (!isset($activitygroupmode[$cm->id])) {
$activitygroupmode[$cm->id] = groups_get_activity_groupmode($cm);
}
if (!isset($usergroups[$item->groupid])) {
$usergroups[$item->groupid] = groups_is_member($item->groupid, $USER->id);
}
if ($activitygroupmode[$cm->id] == SEPARATEGROUPS && !$usergroups[$item->groupid]) {
$builder->set_accessible($item, false);
continue;
}
$builder->set_accessible($item, true);
}
$items = $builder->get_items();
if (count($items) > $perpage) {
$totalpages = $page + 2; // We don't need exact page count, just indicate that the next page exists.
array_pop($items);
}
// Build the display contents.
if ($items) {
$tagfeed = new core_tag\output\tagfeed();
foreach ($items as $item) {
context_helper::preload_from_record($item);
$modinfo = get_fast_modinfo($item->courseid);
$cm = $modinfo->get_cm($item->cmid);
$pageurl = new moodle_url('/mod/data/view.php', array(
'rid' => $item->id,
'd' => $item->dataid
));
if (!isset($titlefields[$item->dataid])) {
$titlefields[$item->dataid] = data_get_tag_title_field($item->dataid);
}
$pagename = data_get_tag_title_for_entry($titlefields[$item->dataid], $item);
$pagename = html_writer::link($pageurl, $pagename);
$courseurl = course_get_url($item->courseid, $cm->sectionnum);
$cmname = html_writer::link($cm->url, $cm->get_formatted_name());
$coursename = format_string($item->fullname, true, array('context' => context_course::instance($item->courseid)));
$coursename = html_writer::link($courseurl, $coursename);
$icon = html_writer::link($pageurl, html_writer::empty_tag('img', array('src' => $cm->get_icon_url())));
$tagfeed->add($icon, $pagename, $cmname . '<br>' . $coursename);
}
$content = $OUTPUT->render_from_template('core_tag/tagfeed', $tagfeed->export_for_template($OUTPUT));
return new core_tag\output\tagindex($tag, 'mod_data', 'data_records', $content, $exclusivemode,
$fromctx, $ctx, $rec, $page, $totalpages);
}
}
/**
* Get the title of a field to show when displaying tag results.
*
* @param int $dataid The id of the data field
* @return stdClass The field data from the 'data_fields' table as well as it's priority
*/
function data_get_tag_title_field($dataid) {
global $DB, $CFG;
$validfieldtypes = array('text', 'textarea', 'menu', 'radiobutton', 'checkbox', 'multimenu', 'url');
$fields = $DB->get_records('data_fields', ['dataid' => $dataid]);
$template = $DB->get_field('data', 'addtemplate', ['id' => $dataid]);
$filteredfields = [];
foreach ($fields as $field) {
if (!in_array($field->type, $validfieldtypes)) {
continue;
}
$field->addtemplateposition = strpos($template, '[['.$field->name.']]');
if ($field->addtemplateposition === false) {
continue;
}
require_once($CFG->dirroot . '/mod/data/field/' . $field->type . '/field.class.php');
$classname = 'data_field_' . $field->type;
$field->priority = $classname::get_priority();
$filteredfields[] = $field;
}
$sort = function($record1, $record2) {
// If a content's fieldtype is compulsory in the database than it would have priority than any other non-compulsory content.
if (($record1->required && $record2->required) || (!$record1->required && !$record2->required)) {
if ($record1->priority === $record2->priority) {
return $record1->id < $record2->id ? 1 : -1;
}
return $record1->priority < $record2->priority ? -1 : 1;
} else if ($record1->required && !$record2->required) {
return 1;
} else {
return -1;
}
};
usort($filteredfields, $sort);
return array_shift($filteredfields);
}
/**
* Get the title of an entry to show when displaying tag results.
*
* @param stdClass $field The field from the 'data_fields' table
* @param stdClass $entry The entry from the 'data_records' table
* @return string The title of the entry
*/
function data_get_tag_title_for_entry($field, $entry) {
global $CFG, $DB;
require_once($CFG->dirroot . '/mod/data/field/' . $field->type . '/field.class.php');
$classname = 'data_field_' . $field->type;
$sql = "SELECT dc.*
FROM {data_content} dc
INNER JOIN {data_fields} df
ON dc.fieldid = df.id
WHERE df.id = :fieldid
AND dc.recordid = :recordid";
$fieldcontents = $DB->get_record_sql($sql, array('recordid' => $entry->id, 'fieldid' => $field->id));
return $classname::get_content_value($fieldcontents);
}
/**
* Search entries in a database.
*
@ -908,26 +1152,7 @@ function data_search_entries($data, $cm, $context, $mode, $currentgroup, $search
$initialparams['myid3'] = $params['myid2'];
}
if (!empty($advanced)) { // If advanced box is checked.
$i = 0;
foreach ($searcharray as $key => $val) { // what does $searcharray hold?
if ($key == DATA_FIRSTNAME or $key == DATA_LASTNAME) {
$i++;
$searchselect .= " AND ".$DB->sql_like($val->field, ":search_flname_$i", false);
$params['search_flname_'.$i] = "%$val->data%";
continue;
}
if ($key == DATA_TIMEMODIFIED) {
$searchselect .= " AND $val->field >= :timemodified";
$params['timemodified'] = $val->data;
continue;
}
$advtables .= ', {data_content} c'.$key.' ';
$advwhere .= ' AND c'.$key.'.recordid = r.id';
$advsearchselect .= ' AND ('.$val->sql.') ';
$advparams = array_merge($advparams, $val->params);
}
} else if ($search) {
if ($search) {
$searchselect = " AND (".$DB->sql_like('c.content', ':search1', false)."
OR ".$DB->sql_like('u.firstname', ':search2', false)."
OR ".$DB->sql_like('u.lastname', ':search3', false)." ) ";
@ -965,26 +1190,8 @@ function data_search_entries($data, $cm, $context, $mode, $currentgroup, $search
$params['myid2'] = $USER->id;
$initialparams['myid3'] = $params['myid2'];
}
$i = 0;
if (!empty($advanced)) { // If advanced box is checked.
foreach ($searcharray as $key => $val) { // what does $searcharray hold?
if ($key == DATA_FIRSTNAME or $key == DATA_LASTNAME) {
$i++;
$searchselect .= " AND ".$DB->sql_like($val->field, ":search_flname_$i", false);
$params['search_flname_'.$i] = "%$val->data%";
continue;
}
if ($key == DATA_TIMEMODIFIED) {
$searchselect .= " AND $val->field >= :timemodified";
$params['timemodified'] = $val->data;
continue;
}
$advtables .= ', {data_content} c'.$key.' ';
$advwhere .= ' AND c'.$key.'.recordid = r.id AND c'.$key.'.fieldid = '.$key;
$advsearchselect .= ' AND ('.$val->sql.') ';
$advparams = array_merge($advparams, $val->params);
}
} else if ($search) {
if ($search) {
$searchselect = " AND (".$DB->sql_like('c.content', ':search1', false)." OR
".$DB->sql_like('u.firstname', ':search2', false)." OR
".$DB->sql_like('u.lastname', ':search3', false)." ) ";
@ -1146,6 +1353,17 @@ function data_build_search_array($data, $paging, $searcharray, $defaults = null,
}
}
$rawtagnames = optional_param_array('tags', false, PARAM_TAGLIST);
if ($rawtagnames) {
$searcharray[DATA_TAGS] = new stdClass();
$searcharray[DATA_TAGS]->params = [];
$searcharray[DATA_TAGS]->rawtagnames = $rawtagnames;
$searcharray[DATA_TAGS]->sql = '';
} else {
unset($searcharray[DATA_TAGS]);
}
if (!$paging) {
// Name searching.
$fn = optional_param('u_fn', $fn, PARAM_NOTAGS);

View File

@ -146,3 +146,7 @@
#page-mod-data-edit .mod-data-input {
margin-left: 10px;
}
#page-mod-data-edit .datatagcontrol {
padding-left: 10px;
}

View File

@ -259,6 +259,11 @@ if ($mode != 'csstemplate' and $mode != 'jstemplate') {
echo '<option value="[['.$field->name.'#id]]" title="'.$field->description.' id">'.$field->name.' id - [['.$field->name.'#id]]</option>';
}
echo '</optgroup>';
if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
echo '<optgroup label="'.get_string('other', 'data').'">';
echo '<option value="##tags##">' . get_string('tags') . ' - ##tags##</option>';
echo '</optgroup>';
}
}
// Print special tags. fix for MDL-7031
@ -284,6 +289,11 @@ if ($mode != 'csstemplate' and $mode != 'jstemplate') {
echo '<option value="##user##">' .get_string('user'). ' - ##user##</option>';
echo '<option value="##userpicture##">' . get_string('userpic') . ' - ##userpicture##</option>';
echo '<option value="##approvalstatus##">' .get_string('approvalstatus', 'data'). ' - ##approvalstatus##</option>';
if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
echo '<option value="##tags##">' . get_string('tags') . ' - ##tags##</option>';
}
if ($mode != 'singletemplate') {
// more points to single template - not useable there
echo '<option value="##comments##">' .get_string('comments', 'data'). ' - ##comments##</option>';

View File

@ -4,68 +4,134 @@ Feature: Users can view and search database entries
As a user
I need to list and search the database entries
Scenario: Students can add view, list and search entries
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Student | 1 | student1@example.com |
| teacher1 | Teacher | 1 | teacher1@example.com |
| username | firstname | lastname | email |
| student1 | Bob | 1 | student1@example.com |
| student2 | Alice | 2 | student2@example.com |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "tags" exist:
| name | isstandard |
| Tag1 | 1 |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| data | Test database name | n | C1 | data1 |
| activity | name | intro | course | idnumber |
| data | Test database name | Database intro | C1 | data1 |
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I add a "Text input" field to "Test database name" database and I fill the form with:
| Field name | Test field name |
| Field name | Test field name |
| Field description | Test field description |
And I add a "Text input" field to "Test database name" database and I fill the form with:
| Field name | Test field 2 name |
| Field description | Test field 2 description |
# To generate the default templates.
And I follow "Templates"
And I add an entry to "Test database name" database with:
| Test field name | Teacher entry 1 |
And I press "Save and add another"
And I add an entry to "Test database name" database with:
| Test field name | Teacher entry 2 |
And I press "Save and add another"
And I add an entry to "Test database name" database with:
| Test field name | Teacher entry 3 |
And I press "Save and view"
And I log out
When I log in as "student1"
Scenario: Students can add view, list and search entries
Given I log in as "student1"
And I am on "Course 1" course homepage
And I follow "Test database name"
Then I should see "Teacher entry 1"
And I should see "Teacher entry 2"
And I should see "Teacher entry 3"
And I add an entry to "Test database name" database with:
| Test field name | Student entry 1 |
And I press "Save and add another"
And I add an entry to "Test database name" database with:
| Test field name | Student entry 2 |
And I press "Save and add another"
And I add an entry to "Test database name" database with:
| Test field name | Student entry 3 |
And I press "Save and view"
And I follow "Test database name"
Then I should see "Student entry 1"
And I should see "Student entry 2"
And I should see "Student entry 3"
And I follow "View single"
And I should see "Teacher entry 1"
And I should not see "Teacher entry 2"
And I should see "Student entry 1"
And I should not see "Student entry 2"
And "2" "link" should exist
And "3" "link" should exist
And I follow "Next"
And I should see "Teacher entry 2"
And I should not see "Teacher entry 1"
And I should see "Student entry 2"
And I should not see "Student entry 1"
And I click on "3" "link" in the "region-main" "region"
And I should see "Teacher entry 3"
And I should not see "Teacher entry 2"
And I should see "Student entry 3"
And I should not see "Student entry 2"
And I follow "Previous"
And I should see "Teacher entry 2"
And I should not see "Teacher entry 1"
And I should not see "Teacher entry 3"
And I should see "Student entry 2"
And I should not see "Student entry 1"
And I should not see "Student entry 3"
And I follow "Search"
And I set the field "Test field name" to "Teacher entry 1"
And I set the field "Test field name" to "Student entry 1"
And I press "Save settings"
And I should see "Teacher entry 1"
And I should not see "Teacher entry 2"
And I should not see "Teacher entry 3"
And I should see "Student entry 1"
And I should not see "Student entry 2"
And I should not see "Student entry 3"
And I follow "Search"
And I set the field "Test field name" to "Teacher entry"
And I set the field "Test field name" to "Student entry"
And I set the field "Order" to "Descending"
And I press "Save settings"
And "Teacher entry 3" "text" should appear before "Teacher entry 2" "text"
And "Teacher entry 2" "text" should appear before "Teacher entry 1" "text"
And "Student entry 3" "text" should appear before "Student entry 2" "text"
And "Student entry 2" "text" should appear before "Student entry 1" "text"
@javascript
Scenario: Check that searching by tags works as expected
Given I log in as "student1"
And I am on "Course 1" course homepage
And I add an entry to "Test database name" database with:
| Test field name | Student original entry untagged |
| Test field 2 name | Student original entry untagged 2 |
And I add an entry to "Test database name" database with:
| Test field name | Student original entry tagged |
| Test field 2 name | Student original entry tagged 2 |
And I set the field with xpath "//div[@class='datatagcontrol']//input[@type='text']" to "Tag1"
And I click on "[data-value='Tag1']" "css_element"
And I press "Save and view"
And I should see "Student original entry"
And I should see "Tag1" in the "div.tag_list" "css_element"
And I follow "Edit"
And I should see "Tag1" in the ".form-autocomplete-selection" "css_element"
And I follow "View list"
And I should see "Tag1" in the "div.tag_list" "css_element"
And I follow "Search"
And I set the field with xpath "//div[@class='datatagcontrol']//input[@type='text']" to "Tag1"
And I click on "[data-value='Tag1']" "css_element"
When I press "Save settings"
Then I should see "Student original entry tagged"
And I should see "Student original entry tagged 2"
And I should not see "Student original entry untagged"
And I should not see "Student original entry untagged 2"
Scenario: Check that searching by first and last name works as expected
Given I log in as "student1"
And I am on "Course 1" course homepage
And I add an entry to "Test database name" database with:
| Test field name | Student entry 1 |
And I press "Save and view"
And I log out
And I log in as "student2"
And I am on "Course 1" course homepage
And I add an entry to "Test database name" database with:
| Test field name | Student entry 2 |
And I press "Save and view"
And I log out
When I log in as "teacher1"
And I am on "Course 1" course homepage
And I follow "Test database name"
And I follow "Search"
And I set the field "Author first name" to "Bob"
And I press "Save settings"
Then I should see "Student entry 1"
And I should not see "Student entry 2"
And I set the field "Author first name" to ""
And I set the field "Author surname" to "2"
And I press "Save settings"
And I should not see "Student entry 1"
And I should see "Student entry 2"

View File

@ -209,15 +209,24 @@ class mod_data_generator extends testing_module_generator {
*
* @param mod_data $data
* @param array $contents
* @param int $groupid
* @param array $tags
* @param array $options
* @return data_field_{type}
*/
public function create_entry($data, array $contents, $groupid = 0) {
public function create_entry($data, array $contents, $groupid = 0, $tags = [], array $options = null) {
global $DB;
$this->databaserecordcount++;
$recordid = data_add_record($data, $groupid);
if (isset($options['approved'])) {
data_approve_entry($recordid, !empty($options['approved']));
} else {
$approved = null;
}
$fields = $DB->get_records('data_fields', array('dataid' => $data->id));
// Validating whether required field are filled.
@ -309,6 +318,12 @@ class mod_data_generator extends testing_module_generator {
}
}
if (!empty($tags)) {
$cm = get_coursemodule_from_instance('data', $data->id);
core_tag_tag::set_item_tags('mod_data', 'data_records', $recordid,
context_module::instance($cm->id), $tags);
}
return $recordid;
}
}

View File

@ -198,8 +198,10 @@ class mod_data_generator_testcase extends advanced_testcase {
$fieldcontents[$fieldrecord->id] = $contents[$count++];
}
$datarecordid = $this->getDataGenerator()->get_plugin_generator('mod_data')->create_entry($data, $fieldcontents,
$groupa->id);
$tags = ['Cats', 'mice'];
$datarecordid = $this->getDataGenerator()->get_plugin_generator('mod_data')->create_entry($data,
$fieldcontents, $groupa->id, $tags);
$this->assertEquals(1, $DB->count_records('data_records', array('dataid' => $data->id)));
$this->assertEquals(count($contents), $DB->count_records('data_content', array('recordid' => $datarecordid)));
@ -229,5 +231,7 @@ class mod_data_generator_testcase extends advanced_testcase {
$this->assertEquals($contents[$contentstartid]->content1, '1');
$this->assertEquals($contents[++$contentstartid]->content, 'http://example.url');
$this->assertEquals($contents[$contentstartid]->content1, 'sampleurl');
$this->assertEquals(array('Cats', 'mice'),
array_values(core_tag_tag::get_item_tags_array('mod_data', 'data_records', $datarecordid)));
}
}

View File

@ -976,6 +976,271 @@ class mod_data_lib_testcase extends advanced_testcase {
$this->assertEquals(1, $completiondata->completionstate);
}
public function test_mod_data_get_tagged_records() {
$this->resetAfterTest();
$this->setAdminUser();
// Setup test data.
$datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
$course1 = $this->getDataGenerator()->create_course();
$fieldrecord = new StdClass();
$fieldrecord->name = 'field-1';
$fieldrecord->type = 'text';
$data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true));
$field1 = $datagenerator->create_field($fieldrecord, $data1);
$datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']);
$datagenerator->create_entry($data1, [$field1->field->id => 'value12'], 0, ['Cats', 'mice']);
$datagenerator->create_entry($data1, [$field1->field->id => 'value13'], 0, ['Cats']);
$datagenerator->create_entry($data1, [$field1->field->id => 'value14'], 0);
$tag = core_tag_tag::get_by_name(0, 'Cats');
// Admin can see everything.
$res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
$this->assertContains('value11', $res->content);
$this->assertContains('value12', $res->content);
$this->assertContains('value13', $res->content);
$this->assertNotContains('value14', $res->content);
}
public function test_mod_data_get_tagged_records_approval() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Setup test data.
$datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
$course2 = $this->getDataGenerator()->create_course();
$course1 = $this->getDataGenerator()->create_course();
$fieldrecord = new StdClass();
$fieldrecord->name = 'field-1';
$fieldrecord->type = 'text';
$data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id));
$field1 = $datagenerator->create_field($fieldrecord, $data1);
$data2 = $this->getDataGenerator()->create_module('data', array('course' => $course2->id, 'approval' => true));
$field2 = $datagenerator->create_field($fieldrecord, $data2);
$record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']);
$record21 = $datagenerator->create_entry($data2, [$field2->field->id => 'value21'], 0, ['Cats'], ['approved' => false]);
$tag = core_tag_tag::get_by_name(0, 'Cats');
// Admin can see everything.
$res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
$this->assertContains('value11', $res->content);
$this->assertContains('value21', $res->content);
$this->assertEmpty($res->prevpageurl);
$this->assertEmpty($res->nextpageurl);
// Create and enrol a user.
$student = self::getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual');
$this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual');
$this->setUser($student);
// User can search data records inside a course.
core_tag_index_builder::reset_caches();
$res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
$this->assertContains('value11', $res->content);
$this->assertNotContains('value21', $res->content);
$recordtoupdate = new stdClass();
$recordtoupdate->id = $record21;
$recordtoupdate->approved = true;
$DB->update_record('data_records', $recordtoupdate);
core_tag_index_builder::reset_caches();
$res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
$this->assertContains('value11', $res->content);
$this->assertContains('value21', $res->content);
}
public function test_mod_data_get_tagged_records_time() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Setup test data.
$datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
$course2 = $this->getDataGenerator()->create_course();
$course1 = $this->getDataGenerator()->create_course();
$fieldrecord = new StdClass();
$fieldrecord->name = 'field-1';
$fieldrecord->type = 'text';
$timefrom = time() - YEARSECS;
$timeto = time() - WEEKSECS;
$data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true));
$field1 = $datagenerator->create_field($fieldrecord, $data1);
$data2 = $this->getDataGenerator()->create_module('data', array('course' => $course2->id,
'timeviewfrom' => $timefrom,
'timeviewto' => $timeto));
$field2 = $datagenerator->create_field($fieldrecord, $data2);
$record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']);
$record21 = $datagenerator->create_entry($data2, [$field2->field->id => 'value21'], 0, ['Cats']);
$tag = core_tag_tag::get_by_name(0, 'Cats');
// Admin can see everything.
$res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
$this->assertContains('value11', $res->content);
$this->assertContains('value21', $res->content);
$this->assertEmpty($res->prevpageurl);
$this->assertEmpty($res->nextpageurl);
// Create and enrol a user.
$student = self::getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual');
$this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual');
$this->setUser($student);
// User can search data records inside a course.
core_tag_index_builder::reset_caches();
$res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
$this->assertContains('value11', $res->content);
$this->assertNotContains('value21', $res->content);
$data2->timeviewto = time() + YEARSECS;
$DB->update_record('data', $data2);
core_tag_index_builder::reset_caches();
$res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
$this->assertContains('value11', $res->content);
$this->assertContains('value21', $res->content);
}
public function test_mod_data_get_tagged_records_course_enrolment() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Setup test data.
$datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
$course2 = $this->getDataGenerator()->create_course();
$course1 = $this->getDataGenerator()->create_course();
$fieldrecord = new StdClass();
$fieldrecord->name = 'field-1';
$fieldrecord->type = 'text';
$data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true));
$field1 = $datagenerator->create_field($fieldrecord, $data1);
$data2 = $this->getDataGenerator()->create_module('data', array('course' => $course2->id));
$field2 = $datagenerator->create_field($fieldrecord, $data2);
$record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']);
$record21 = $datagenerator->create_entry($data2, [$field2->field->id => 'value21'], 0, ['Cats']);
$tag = core_tag_tag::get_by_name(0, 'Cats');
// Admin can see everything.
$res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
$this->assertContains('value11', $res->content);
$this->assertContains('value21', $res->content);
$this->assertEmpty($res->prevpageurl);
$this->assertEmpty($res->nextpageurl);
// Create and enrol a user.
$student = self::getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual');
$this->setUser($student);
core_tag_index_builder::reset_caches();
// User can search data records inside a course.
$coursecontext = context_course::instance($course1->id);
$res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
$this->assertContains('value11', $res->content);
$this->assertNotContains('value21', $res->content);
$this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual');
core_tag_index_builder::reset_caches();
$res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
$this->assertContains('value11', $res->content);
$this->assertContains('value21', $res->content);
}
public function test_mod_data_get_tagged_records_course_groups() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Setup test data.
$datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
$course2 = $this->getDataGenerator()->create_course();
$course1 = $this->getDataGenerator()->create_course();
$groupa = $this->getDataGenerator()->create_group(array('courseid' => $course2->id, 'name' => 'groupA'));
$groupb = $this->getDataGenerator()->create_group(array('courseid' => $course2->id, 'name' => 'groupB'));
$fieldrecord = new StdClass();
$fieldrecord->name = 'field-1';
$fieldrecord->type = 'text';
$data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true));
$field1 = $datagenerator->create_field($fieldrecord, $data1);
$data2 = $this->getDataGenerator()->create_module('data', array('course' => $course2->id));
$field2 = $datagenerator->create_field($fieldrecord, $data2);
set_coursemodule_groupmode($data2->cmid, SEPARATEGROUPS);
$record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'],
0, ['Cats', 'Dogs']);
$record21 = $datagenerator->create_entry($data2, [$field2->field->id => 'value21'],
$groupa->id, ['Cats']);
$record22 = $datagenerator->create_entry($data2, [$field2->field->id => 'value22'],
$groupb->id, ['Cats']);
$tag = core_tag_tag::get_by_name(0, 'Cats');
// Admin can see everything.
$res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
$this->assertContains('value11', $res->content);
$this->assertContains('value21', $res->content);
$this->assertContains('value22', $res->content);
$this->assertEmpty($res->prevpageurl);
$this->assertEmpty($res->nextpageurl);
// Create and enrol a user.
$student = self::getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual');
$this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual');
groups_add_member($groupa, $student);
$this->setUser($student);
core_tag_index_builder::reset_caches();
// User can search data records inside a course.
$res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
$this->assertContains('value11', $res->content);
$this->assertContains('value21', $res->content);
$this->assertNotContains('value22', $res->content);
groups_add_member($groupb, $student);
core_tag_index_builder::reset_caches();
$res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
$this->assertContains('value11', $res->content);
$this->assertContains('value21', $res->content);
$this->assertContains('value22', $res->content);
}
/**
* Test check_updates_since callback.
*/

View File

@ -257,6 +257,40 @@ class mod_data_search_test extends advanced_testcase {
$this->assertEquals($this->approvedatarecordcount, count($recordids));
}
public function test_advanced_search_tags() {
$this->resetAfterTest();
$this->setAdminUser();
// Setup test data.
$datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
$course1 = $this->getDataGenerator()->create_course();
$fieldrecord = new StdClass();
$fieldrecord->name = 'field-1';
$fieldrecord->type = 'text';
$fieldrecord->titlefield = true;
$data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true));
$field1 = $datagenerator->create_field($fieldrecord, $data1);
$record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']);
$record12 = $datagenerator->create_entry($data1, [$field1->field->id => 'value12'], 0, ['Cats', 'mice']);
$record13 = $datagenerator->create_entry($data1, [$field1->field->id => 'value13'], 0, ['Bats']);
$searcharray = [];
$searcharray[DATA_TAGS] = new stdClass();
$searcharray[DATA_TAGS]->params = [];
$searcharray[DATA_TAGS]->rawtagnames = ['Cats'];
$searcharray[DATA_TAGS]->sql = '';
$recordids = data_get_all_recordids($data1->id);
$newrecordids = data_get_advance_search_ids($recordids, $searcharray, $data1->id);
$this->assertContains($record11, $newrecordids);
$this->assertContains($record12, $newrecordids);
$this->assertNotContains($record13, $newrecordids);
}
/**
* Indexing database entries contents.
*

View File

@ -24,7 +24,7 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2017051500; // The current module version (Date: YYYYMMDDXX)
$plugin->version = 2017091400; // The current module version (Date: YYYYMMDDXX)
$plugin->requires = 2017050500; // Requires this Moodle version
$plugin->component = 'mod_data'; // Full name of the plugin (used for diagnostics)
$plugin->cron = 0;