MDL-18910 moving modedit features to modname_supports()
[moodle.git] / mod / data / lib.php
CommitLineData
3d4b223a 1<?php // $Id$
2///////////////////////////////////////////////////////////////////////////
3// //
4// NOTICE OF COPYRIGHT //
5// //
6// Moodle - Modular Object-Oriented Dynamic Learning Environment //
7// http://moodle.org //
8// //
9// Copyright (C) 2005 Moodle Pty Ltd http://moodle.com //
10// //
11// This program is free software; you can redistribute it and/or modify //
12// it under the terms of the GNU General Public License as published by //
13// the Free Software Foundation; either version 2 of the License, or //
14// (at your option) any later version. //
15// //
16// This program is distributed in the hope that it will be useful, //
17// but WITHOUT ANY WARRANTY; without even the implied warranty of //
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
19// GNU General Public License for more details: //
20// //
21// http://www.gnu.org/copyleft/gpl.html //
22// //
23///////////////////////////////////////////////////////////////////////////
24
214b1cf7 25require_once($CFG->libdir . '/portfoliolib.php');
26
b8b554ac 27// Some constants
0997e51a 28define ('DATA_MAX_ENTRIES', 50);
29define ('DATA_PERPAGE_SINGLE', 1);
b572ce19 30
714bec74 31define ('DATA_FIRSTNAME', -1);
32define ('DATA_LASTNAME', -2);
bb5740f4 33define ('DATA_APPROVED', -3);
3239b010 34define ('DATA_TIMEADDED', 0);
35define ('DATA_TIMEMODIFIED', -4);
714bec74 36
a7e35395 37define ('DATA_CAP_EXPORT', 'mod/data:viewalluserpresets');
38// Users having assigned the default role "Non-editing teacher" can export database records
39// Using the mod/data capability "viewalluserpresets" existing in Moodle 1.9.x.
8429163d 40// In Moodle >= 2, new roles may be introduced and used instead.
a7e35395 41
668fc89a 42class data_field_base { // Base class for Database Field Types (see field/*/field.class.php)
3d4b223a 43
668fc89a 44 var $type = 'unknown'; // Subclasses must override the type with their name
45 var $data = NULL; // The database object that this field belongs to
46 var $field = NULL; // The field object itself, if we know it
3d4b223a 47
668fc89a 48 var $iconwidth = 16; // Width of the icon for this fieldtype
49 var $iconheight = 16; // Width of the icon for this fieldtype
0997e51a 50
8429163d 51 var $cm; // course module or cmifno
52 var $context; // activity context
0997e51a 53
b8b554ac 54// Constructor function
8429163d 55 function __construct($field=0, $data=0, $cm=0) { // Field or data or both, each can be id or object
9c00b5d7 56 global $DB;
0997e51a 57
58 if (empty($field) && empty($data)) {
29c1bb15 59 print_error('missingfield', 'data');
0997e51a 60 }
b572ce19 61
0997e51a 62 if (!empty($field)) {
63 if (is_object($field)) {
64 $this->field = $field; // Programmer knows what they are doing, we hope
9c00b5d7 65 } else if (!$this->field = $DB->get_record('data_fields', array('id'=>$field))) {
29c1bb15 66 print_error('invalidfieldid', 'data');
0997e51a 67 }
68 if (empty($data)) {
9c00b5d7 69 if (!$this->data = $DB->get_record('data', array('id'=>$this->field->dataid))) {
29c1bb15 70 print_error('invalidid', 'data');
0997e51a 71 }
72 }
73 }
b572ce19 74
0997e51a 75 if (empty($this->data)) { // We need to define this properly
76 if (!empty($data)) {
77 if (is_object($data)) {
78 $this->data = $data; // Programmer knows what they are doing, we hope
9c00b5d7 79 } else if (!$this->data = $DB->get_record('data', array('id'=>$data))) {
29c1bb15 80 print_error('invalidid', 'data');
0997e51a 81 }
82 } else { // No way to define it!
29c1bb15 83 print_error('missingdata', 'data');
0997e51a 84 }
85 }
b572ce19 86
8429163d 87 if ($cm) {
88 $this->cm = $cm;
89 } else {
90 $this->cm = get_coursemodule_from_instance('data', $this->data->id);
91 }
92
0997e51a 93 if (empty($this->field)) { // We need to define some default values
94 $this->define_default_field();
95 }
8429163d 96
97 $this->context = get_context_instance(CONTEXT_MODULE, $this->cm->id);
3d4b223a 98 }
0997e51a 99
6403e679 100
b8b554ac 101// This field just sets up a default field object
0997e51a 102 function define_default_field() {
103 if (empty($this->data->id)) {
104 notify('Programmer error: dataid not defined in field class');
105 }
106 $this->field = new object;
107 $this->field->id = 0;
108 $this->field->dataid = $this->data->id;
109 $this->field->type = $this->type;
110 $this->field->param1 = '';
111 $this->field->param2 = '';
112 $this->field->param3 = '';
113 $this->field->name = '';
114 $this->field->description = '';
b572ce19 115
0997e51a 116 return true;
3d4b223a 117 }
0997e51a 118
b572ce19 119// Set up the field object according to data in an object. Now is the time to clean it!
0997e51a 120 function define_field($data) {
121 $this->field->type = $this->type;
122 $this->field->dataid = $this->data->id;
123
124 $this->field->name = trim($data->name);
125 $this->field->description = trim($data->description);
126
127 if (isset($data->param1)) {
128 $this->field->param1 = trim($data->param1);
129 }
130 if (isset($data->param2)) {
8921fdb7 131 $this->field->param2 = trim($data->param2);
0997e51a 132 }
133 if (isset($data->param3)) {
134 $this->field->param3 = trim($data->param3);
135 }
136 if (isset($data->param4)) {
137 $this->field->param4 = trim($data->param4);
138 }
139 if (isset($data->param5)) {
140 $this->field->param5 = trim($data->param5);
141 }
142
143 return true;
3d4b223a 144 }
6403e679 145
b8b554ac 146// Insert a new field in the database
147// We assume the field object is already defined as $this->field
0997e51a 148 function insert_field() {
9c00b5d7 149 global $DB;
150
0997e51a 151 if (empty($this->field)) {
152 notify('Programmer error: Field has not been defined yet! See define_field()');
153 return false;
154 }
155
9c00b5d7 156 if (!$this->field->id = $DB->insert_record('data_fields',$this->field)){
3d4b223a 157 notify('Insertion of new field failed!');
0997e51a 158 return false;
3d4b223a 159 }
0997e51a 160 return true;
3d4b223a 161 }
162
0997e51a 163
b8b554ac 164// Update a field in the database
0997e51a 165 function update_field() {
9c00b5d7 166 global $DB;
167
168 if (!$DB->update_record('data_fields', $this->field)) {
0997e51a 169 notify('updating of new field failed!');
170 return false;
3d4b223a 171 }
0997e51a 172 return true;
173 }
3d4b223a 174
b8b554ac 175// Delete a field completely
0997e51a 176 function delete_field() {
9c00b5d7 177 global $DB;
178
0997e51a 179 if (!empty($this->field->id)) {
0997e51a 180 $this->delete_content();
8429163d 181 $DB->delete_records('data_fields', array('id'=>$this->field->id));
3d4b223a 182 }
0997e51a 183 return true;
184 }
185
b8b554ac 186// Print the relevant form element in the ADD template for this field
0997e51a 187 function display_add_field($recordid=0){
9c00b5d7 188 global $DB;
189
0997e51a 190 if ($recordid){
9c00b5d7 191 $content = $DB->get_field('data_content', 'content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid));
0997e51a 192 } else {
3d4b223a 193 $content = '';
194 }
6403e679 195
344e15e6 196 // beware get_field returns false for new, empty records MDL-18567
197 if ($content===false) {
198 $content='';
199 }
200
9706fa56 201 $str = '<div title="'.s($this->field->description).'">';
0997e51a 202 $str .= '<input style="width:300px;" type="text" name="field_'.$this->field->id.'" id="field_'.$this->field->id.'" value="'.s($content).'" />';
bbe39b6c 203 $str .= '</div>';
0997e51a 204
3d4b223a 205 return $str;
206 }
207
b8b554ac 208// Print the relevant form element to define the attributes for this field
209// viewable by teachers only.
0997e51a 210 function display_edit_field() {
a656d951 211 global $CFG, $DB;
0997e51a 212
213 if (empty($this->field)) { // No field has been defined yet, try and make one
214 $this->define_default_field();
3d4b223a 215 }
216 print_simple_box_start('center','80%');
0997e51a 217
b7dc2256 218 echo '<form id="editfield" action="'.$CFG->wwwroot.'/mod/data/field.php" method="post">'."\n";
0997e51a 219 echo '<input type="hidden" name="d" value="'.$this->data->id.'" />'."\n";
220 if (empty($this->field->id)) {
221 echo '<input type="hidden" name="mode" value="add" />'."\n";
222 $savebutton = get_string('add');
223 } else {
224 echo '<input type="hidden" name="fid" value="'.$this->field->id.'" />'."\n";
225 echo '<input type="hidden" name="mode" value="update" />'."\n";
226 $savebutton = get_string('savechanges');
227 }
228 echo '<input type="hidden" name="type" value="'.$this->type.'" />'."\n";
229 echo '<input name="sesskey" value="'.sesskey().'" type="hidden" />'."\n";
6403e679 230
0997e51a 231 print_heading($this->name());
232
3d4b223a 233 require_once($CFG->dirroot.'/mod/data/field/'.$this->type.'/mod.html');
0997e51a 234
85db96c5 235 echo '<div class="mdl-align">';
0997e51a 236 echo '<input type="submit" value="'.$savebutton.'" />'."\n";
ec865e2d 237 echo '<input type="submit" name="cancel" value="'.get_string('cancel').'" />'."\n";
e357c206 238 echo '</div>';
0997e51a 239
240 echo '</form>';
241
3d4b223a 242 print_simple_box_end();
243 }
6403e679 244
b8b554ac 245// Display the content of the field in browse mode
0997e51a 246 function display_browse_field($recordid, $template) {
9c00b5d7 247 global $DB;
248
249 if ($content = $DB->get_record('data_content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))) {
6403e679 250 if (isset($content->content)) {
9706fa56 251 $options = new object();
c8505cac 252 if ($this->field->param1 == '1') { // We are autolinking this field, so disable linking within us
253 //$content->content = '<span class="nolink">'.$content->content.'</span>';
254 //$content->content1 = FORMAT_HTML;
255 $options->filter=false;
256 }
1f697b99 257 $options->para = false;
258 $str = format_text($content->content, $content->content1, $options);
3d4b223a 259 } else {
260 $str = '';
261 }
262 return $str;
263 }
264 return false;
265 }
6403e679 266
b8b554ac 267// Update the content of one data field in the data_content table
0997e51a 268 function update_content($recordid, $value, $name=''){
9c00b5d7 269 global $DB;
270
9706fa56 271 $content = new object();
0997e51a 272 $content->fieldid = $this->field->id;
c87fbb27 273 $content->recordid = $recordid;
274 $content->content = clean_param($value, PARAM_NOTAGS);
0997e51a 275
9c00b5d7 276 if ($oldcontent = $DB->get_record('data_content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))) {
3d4b223a 277 $content->id = $oldcontent->id;
9c00b5d7 278 return $DB->update_record('data_content', $content);
0997e51a 279 } else {
9c00b5d7 280 return $DB->insert_record('data_content', $content);
3d4b223a 281 }
0997e51a 282 }
6403e679 283
b8b554ac 284// Delete all content associated with the field
0997e51a 285 function delete_content($recordid=0) {
9c00b5d7 286 global $DB;
0997e51a 287
0997e51a 288 if ($recordid) {
8429163d 289 $conditions = array('fieldid'=>$this->field->id, 'recordid'=>$recordid);
0997e51a 290 } else {
8429163d 291 $conditions = array('fieldid'=>$this->field->id);
3d4b223a 292 }
0997e51a 293
8429163d 294 if ($rs = $DB->get_recordset('data_content', $conditions)) {
295 $fs = get_file_storage();
296 foreach ($rs as $content) {
297 $fs->delete_area_files($this->context->id, 'data_content', $content->id);
298 }
299 $rs->close();
0997e51a 300 }
301
8429163d 302 return $DB->delete_records('data_content', $conditions);
0997e51a 303 }
6403e679 304
b8b554ac 305// Check if a field from an add form is empty
f9eab7b0 306 function notemptyfield($value, $name) {
3d4b223a 307 return !empty($value);
308 }
6403e679 309
b8b554ac 310// Just in case a field needs to print something before the whole form
0997e51a 311 function print_before_form() {
3d4b223a 312 }
0997e51a 313
b8b554ac 314// Just in case a field needs to print something after the whole form
5f5bcda8 315 function print_after_form() {
5f5bcda8 316 }
6403e679 317
318
b8b554ac 319// Returns the sortable field for the content. By default, it's just content
320// but for some plugins, it could be content 1 - content4
cf3e199b 321 function get_sort_field() {
322 return 'content';
323 }
0997e51a 324
b8b554ac 325// Returns the SQL needed to refer to the column. Some fields may need to CAST() etc.
64452eb4 326 function get_sort_sql($fieldname) {
327 return $fieldname;
328 }
329
b8b554ac 330// Returns the name/type of the field
331 function name() {
0997e51a 332 return get_string('name'.$this->type, 'data');
333 }
6403e679 334
b8b554ac 335// Prints the respective type icon
0997e51a 336 function image() {
337 global $CFG;
338
5bac6d10 339 $str = '<a href="field.php?d='.$this->data->id.'&amp;fid='.$this->field->id.'&amp;mode=display&amp;sesskey='.sesskey().'">';
0997e51a 340 $str .= '<img src="'.$CFG->modpixpath.'/data/field/'.$this->type.'/icon.gif" ';
051aad68 341 $str .= 'height="'.$this->iconheight.'" width="'.$this->iconwidth.'" alt="'.$this->type.'" title="'.$this->type.'" /></a>';
0997e51a 342 return $str;
343 }
344
8429163d 345// Per default, it is assumed that fields support text exporting. Override this (return false) on fields not supporting text exporting.
b8b554ac 346 function text_export_supported() {
347 return true;
348 }
6403e679 349
8429163d 350// Per default, return the record's text value only from the "content" field. Override this in fields class if necesarry.
b8b554ac 351 function export_text_value($record) {
352 if ($this->text_export_supported()) {
353 return $record->content;
354 }
355 }
0997e51a 356
8429163d 357 function file_ok($relativepath) {
358 return false;
359 }
b8b554ac 360}
3d4b223a 361
362
b572ce19 363/*****************************************************************************
364/* Given a template and a dataid, generate a default case template *
365 * input @param template - addtemplate, singletemplate, listtempalte, rsstemplate*
366 * @param dataid *
367 * output null *
368 *****************************************************************************/
a44e7081 369function data_generate_default_template(&$data, $template, $recordid=0, $form=false, $update=true) {
9c00b5d7 370 global $DB;
d118d06a 371
edaa546a 372 if (!$data && !$template) {
3d4b223a 373 return false;
374 }
5cd07964 375 if ($template == 'csstemplate' or $template == 'jstemplate' ) {
f24eb261 376 return '';
377 }
6403e679 378
b8b554ac 379 // get all the fields for that database
9c00b5d7 380 if ($fields = $DB->get_records('data_fields', array('dataid'=>$data->id), 'id')) {
6403e679 381
e7a5de86 382 $str = '<div class="defaulttemplate">';
e357c206 383 $str .= '<table cellpadding="5">';
3d4b223a 384
f41cadeb 385 foreach ($fields as $field) {
3d4b223a 386
176e5c6c 387 $str .= '<tr><td valign="top" align="right">';
91f3f616 388 // Yu: commenting this out, the id was wrong and will fix later
389 //if ($template == 'addtemplate') {
390 //$str .= '<label';
391 //if (!in_array($field->type, array('picture', 'checkbox', 'date', 'latlong', 'radiobutton'))) {
392 // $str .= ' for="[['.$field->name.'#id]]"';
393 //}
394 //$str .= '>'.$field->name.'</label>';
8429163d 395
91f3f616 396 //} else {
e357c206 397 $str .= $field->name.': ';
91f3f616 398 //}
3d4b223a 399 $str .= '</td>';
400
401 $str .='<td>';
b8b554ac 402 if ($form) { // Print forms instead of data
d118d06a 403 $fieldobj = data_get_field($field, $data);
404 $str .= $fieldobj->display_add_field($recordid);
f62f7d8f 405
b8b554ac 406 } else { // Just print the tag
d118d06a 407 $str .= '[['.$field->name.']]';
408 }
3d4b223a 409 $str .= '</td></tr>';
6403e679 410
3d4b223a 411 }
bb828644 412 if ($template == 'listtemplate') {
8185aeb6 413 $str .= '<tr><td align="center" colspan="2">##edit## ##more## ##delete## ##approve## ##export##</td></tr>';
bb828644 414 } else if ($template == 'singletemplate') {
8185aeb6 415 $str .= '<tr><td align="center" colspan="2">##edit## ##delete## ##approve## ##export##</td></tr>';
714bec74 416 } else if ($template == 'asearchtemplate') {
417 $str .= '<tr><td valign="top" align="right">'.get_string('authorfirstname', 'data').': </td><td>##firstname##</td></tr>';
418 $str .= '<tr><td valign="top" align="right">'.get_string('authorlastname', 'data').': </td><td>##lastname##</td></tr>';
3d4b223a 419 }
420
176e5c6c 421 $str .= '</table>';
3d4b223a 422 $str .= '</div>';
423
d118d06a 424 if ($template == 'listtemplate'){
9e5537eb 425 $str .= '<hr />';
3d4b223a 426 }
f9eab7b0 427
d118d06a 428 if ($update) {
aab98aaf 429 $newdata = new object();
d118d06a 430 $newdata->id = $data->id;
f41cadeb 431 $newdata->{$template} = $str;
9c00b5d7 432 if (!$DB->update_record('data', $newdata)) {
d118d06a 433 notify('Error updating template');
a44e7081 434 } else {
435 $data->{$template} = $str;
3d4b223a 436 }
3d4b223a 437 }
d118d06a 438
439 return $str;
3d4b223a 440 }
441}
442
443
f9eab7b0 444/***********************************************************************
445 * Search for a field name and replaces it with another one in all the *
446 * form templates. Set $newfieldname as '' if you want to delete the *
447 * field from the form. *
448 ***********************************************************************/
0997e51a 449function data_replace_field_in_templates($data, $searchfieldname, $newfieldname) {
9c00b5d7 450 global $DB;
451
f9eab7b0 452 if (!empty($newfieldname)) {
453 $prestring = '[[';
454 $poststring = ']]';
9706fa56 455 $idpart = '#id';
735a7952 456
457 } else {
f9eab7b0 458 $prestring = '';
459 $poststring = '';
9706fa56 460 $idpart = '';
f9eab7b0 461 }
6403e679 462
9706fa56 463 $newdata = new object();
735a7952 464 $newdata->id = $data->id;
9c00b5d7 465 $newdata->singletemplate = str_ireplace('[['.$searchfieldname.']]',
466 $prestring.$newfieldname.$poststring, $data->singletemplate);
6403e679 467
9c00b5d7 468 $newdata->listtemplate = str_ireplace('[['.$searchfieldname.']]',
469 $prestring.$newfieldname.$poststring, $data->listtemplate);
6403e679 470
9c00b5d7 471 $newdata->addtemplate = str_ireplace('[['.$searchfieldname.']]',
472 $prestring.$newfieldname.$poststring, $data->addtemplate);
6403e679 473
9c00b5d7 474 $newdata->addtemplate = str_ireplace('[['.$searchfieldname.'#id]]',
475 $prestring.$newfieldname.$idpart.$poststring, $data->addtemplate);
9706fa56 476
9c00b5d7 477 $newdata->rsstemplate = str_ireplace('[['.$searchfieldname.']]',
478 $prestring.$newfieldname.$poststring, $data->rsstemplate);
6403e679 479
9c00b5d7 480 return $DB->update_record('data', $newdata);
f9eab7b0 481}
482
483
484/********************************************************
485 * Appends a new field at the end of the form template. *
486 ********************************************************/
0997e51a 487function data_append_new_field_to_templates($data, $newfieldname) {
9c00b5d7 488 global $DB;
0997e51a 489
9706fa56 490 $newdata = new object();
0997e51a 491 $newdata->id = $data->id;
ed69c723 492 $change = false;
0997e51a 493
f9eab7b0 494 if (!empty($data->singletemplate)) {
9c00b5d7 495 $newdata->singletemplate = $data->singletemplate.' [[' . $newfieldname .']]';
ed69c723 496 $change = true;
0997e51a 497 }
498 if (!empty($data->addtemplate)) {
9c00b5d7 499 $newdata->addtemplate = $data->addtemplate.' [[' . $newfieldname . ']]';
ed69c723 500 $change = true;
f9eab7b0 501 }
502 if (!empty($data->rsstemplate)) {
9c00b5d7 503 $newdata->rsstemplate = $data->singletemplate.' [[' . $newfieldname . ']]';
ed69c723 504 $change = true;
505 }
506 if ($change) {
9c00b5d7 507 $DB->update_record('data', $newdata);
f9eab7b0 508 }
f9eab7b0 509}
510
511
3d4b223a 512/************************************************************************
b572ce19 513 * given a field name *
0997e51a 514 * this function creates an instance of the particular subfield class *
515 ************************************************************************/
516function data_get_field_from_name($name, $data){
9c00b5d7 517 global $DB;
518
519 $field = $DB->get_record('data_fields', array('name'=>$name));
0997e51a 520
521 if ($field) {
522 return data_get_field($field, $data);
523 } else {
524 return false;
525 }
526}
527
528/************************************************************************
b572ce19 529 * given a field id *
3d4b223a 530 * this function creates an instance of the particular subfield class *
531 ************************************************************************/
0997e51a 532function data_get_field_from_id($fieldid, $data){
9c00b5d7 533 global $DB;
534
535 $field = $DB->get_record('data_fields', array('id'=>$fieldid));
3d4b223a 536
0997e51a 537 if ($field) {
538 return data_get_field($field, $data);
5782be6b 539 } else {
d6f0e247 540 return false;
3d4b223a 541 }
3d4b223a 542}
543
0997e51a 544/************************************************************************
b572ce19 545 * given a field id *
0997e51a 546 * this function creates an instance of the particular subfield class *
547 ************************************************************************/
548function data_get_field_new($type, $data) {
549 global $CFG;
b572ce19 550
0997e51a 551 require_once($CFG->dirroot.'/mod/data/field/'.$type.'/field.class.php');
552 $newfield = 'data_field_'.$type;
553 $newfield = new $newfield(0, $data);
554 return $newfield;
555}
556
3d4b223a 557/************************************************************************
558 * returns a subclass field object given a record of the field, used to *
559 * invoke plugin methods *
560 * input: $param $field - record from db *
561 ************************************************************************/
8429163d 562function data_get_field($field, $data, $cm=null) {
0997e51a 563 global $CFG;
b572ce19 564
0997e51a 565 if ($field) {
3d4b223a 566 require_once('field/'.$field->type.'/field.class.php');
567 $newfield = 'data_field_'.$field->type;
8429163d 568 $newfield = new $newfield($field, $data, $cm);
3d4b223a 569 return $newfield;
570 }
571}
572
573
8429163d 574/**
575 * Given record object (or id), returns true if the record belongs to the current user
576 * @param mixed $rid - record object or id
577 * @return bool
578 */
579function data_isowner($record) {
9c00b5d7 580 global $USER, $DB;
3d4b223a 581
8429163d 582 if (!isloggedin()) {
3d4b223a 583 return false;
584 }
585
8429163d 586 if (!is_object($record)) {
587 if (!$record = $DB->get_record('data_records', array('id'=>$record))) {
588 return false;
589 }
3d4b223a 590 }
591
8429163d 592 return ($record->userid == $USER->id);
3d4b223a 593}
594
595/***********************************************************************
596 * has a user reached the max number of entries? *
597 * input object $data *
598 * output bool *
599 ***********************************************************************/
b572ce19 600function data_atmaxentries($data){
601 if (!$data->maxentries){
3d4b223a 602 return false;
b572ce19 603
3d4b223a 604 } else {
605 return (data_numentries($data) >= $data->maxentries);
606 }
607}
608
609/**********************************************************************
610 * returns the number of entries already made by this user *
611 * input @param object $data *
612 * uses global $CFG, $USER *
613 * output int *
614 **********************************************************************/
615function data_numentries($data){
8429163d 616 global $USER, $DB;
9c00b5d7 617 $sql = 'SELECT COUNT(*) FROM {data_records} WHERE dataid=? AND userid=?';
618 return $DB->count_records_sql($sql, array($data->id, $USER->id));
3d4b223a 619}
620
621/****************************************************************
622 * function that takes in a dataid and adds a record *
623 * this is used everytime an add template is submitted *
624 * input @param int $dataid, $groupid *
625 * output bool *
626 ****************************************************************/
0997e51a 627function data_add_record($data, $groupid=0){
9c00b5d7 628 global $USER, $DB;
6403e679 629
c088d603 630 $cm = get_coursemodule_from_instance('data', $data->id);
bbbf2d40 631 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
b572ce19 632
9706fa56 633 $record = new object();
3d4b223a 634 $record->userid = $USER->id;
0997e51a 635 $record->dataid = $data->id;
3d4b223a 636 $record->groupid = $groupid;
0997e51a 637 $record->timecreated = $record->timemodified = time();
0468976c 638 if (has_capability('mod/data:approve', $context)) {
6e0119dd 639 $record->approved = 1;
640 } else {
641 $record->approved = 0;
642 }
9c00b5d7 643 return $DB->insert_record('data_records', $record);
3d4b223a 644}
645
646/*******************************************************************
647 * check the multple existence any tag in a template *
648 * input @param string *
649 * output true-valid, false-invalid *
650 * check to see if there are 2 or more of the same tag being used. *
651 * input @param int $dataid, *
652 * @param string $template *
653 * output bool *
654 *******************************************************************/
9c00b5d7 655function data_tags_check($dataid, $template) {
656 global $DB;
657
b8b554ac 658 // first get all the possible tags
9c00b5d7 659 $fields = $DB->get_records('data_fields', array('dataid'=>$dataid));
b8b554ac 660 // then we generate strings to replace
661 $tagsok = true; // let's be optimistic
b572ce19 662 foreach ($fields as $field){
d118d06a 663 $pattern="/\[\[".$field->name."\]\]/i";
b572ce19 664 if (preg_match_all($pattern, $template, $dummy)>1){
3d4b223a 665 $tagsok = false;
d118d06a 666 notify ('[['.$field->name.']] - '.get_string('multipletags','data'));
3d4b223a 667 }
668 }
b8b554ac 669 // else return true
3d4b223a 670 return $tagsok;
671}
672
673/************************************************************************
674 * Adds an instance of a data *
675 ************************************************************************/
676function data_add_instance($data) {
8429163d 677 global $DB;
3d4b223a 678
57244db3 679 if (empty($data->assessed)) {
680 $data->assessed = 0;
d6af3cfa 681 }
682
3d4b223a 683 $data->timemodified = time();
684
c18269c7 685 if (! $data->id = $DB->insert_record('data', $data)) {
3d4b223a 686 return false;
687 }
688
612607bd 689 data_grade_item_update($data);
b572ce19 690
3d4b223a 691 return $data->id;
692}
693
694/************************************************************************
695 * updates an instance of a data *
696 ************************************************************************/
697function data_update_instance($data) {
8429163d 698 global $DB;
6403e679 699
04366d79 700 $data->timemodified = time();
b572ce19 701 $data->id = $data->instance;
6403e679 702
57244db3 703 if (empty($data->assessed)) {
704 $data->assessed = 0;
17e5f3fc 705 }
b572ce19 706
05ac14ca 707 if (empty($data->notification)) {
708 $data->notification = 0;
709 }
710
c18269c7 711 if (! $DB->update_record('data', $data)) {
3d4b223a 712 return false;
713 }
04366d79 714
04366d79 715 data_grade_item_update($data);
b572ce19 716
04366d79 717 return true;
b572ce19 718
3d4b223a 719}
720
721/************************************************************************
722 * deletes an instance of a data *
723 ************************************************************************/
b8b554ac 724function data_delete_instance($id) { // takes the dataid
8429163d 725 global $DB;
3d4b223a 726
8429163d 727 if (!$data = $DB->get_record('data', array('id'=>$id))) {
3d4b223a 728 return false;
729 }
730
8429163d 731 $cm = get_coursemodule_from_instance('data', $data->id);
732 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
b572ce19 733
8429163d 734/// Delete all the associated information
6403e679 735
8429163d 736 // files
737 $fs = get_file_storage();
738 $fs->delete_area_files($context->id, 'data_content');
3d4b223a 739
8429163d 740 // get all the records in this data
741 $sql = "SELECT r.id
742 FROM {data_records} r
743 WHERE r.dataid = ?";
6403e679 744
8429163d 745 $DB->delete_records_select('data_content', "recordid IN ($sql)", array($id));
3d4b223a 746
747 // delete all the records and fields
c18269c7 748 $DB->delete_records('data_records', array('dataid'=>$id));
749 $DB->delete_records('data_fields', array('dataid'=>$id));
3d4b223a 750
751 // Delete the instance itself
c18269c7 752 $result = $DB->delete_records('data', array('id'=>$id));
04366d79 753
8429163d 754 // cleanup gradebook
b82cacea 755 data_grade_item_delete($data);
b572ce19 756
04366d79 757 return $result;
3d4b223a 758}
759
760/************************************************************************
761 * returns a summary of data activity of this user *
762 ************************************************************************/
763function data_user_outline($course, $user, $mod, $data) {
8429163d 764 global $DB;
9c00b5d7 765
766 if ($countrecords = $DB->count_records('data_records', array('dataid'=>$data->id, 'userid'=>$user->id))) {
9706fa56 767 $result = new object();
63701c78 768 $result->info = get_string('numrecords', 'data', $countrecords);
9c00b5d7 769 $lastrecord = $DB->get_record_sql('SELECT id,timemodified FROM {data_records}
770 WHERE dataid = ? AND userid = ?
771 ORDER BY timemodified DESC', array($data->id, $user->id), true);
3d4b223a 772 $result->time = $lastrecord->timemodified;
773 return $result;
774 }
775 return NULL;
3d4b223a 776}
777
778/************************************************************************
779 * Prints all the records uploaded by this user *
780 ************************************************************************/
781function data_user_complete($course, $user, $mod, $data) {
9c00b5d7 782 global $DB;
783
784 if ($records = $DB->get_records('data_records', array('dataid'=>$data->id,'userid'=>$user->id), 'timemodified DESC')) {
3d45b8e5 785 data_print_template('singletemplate', $records, $data);
3d4b223a 786 }
787}
788
04366d79 789/**
790 * Return grade for given user or all users.
791 *
792 * @param int $dataid id of data
793 * @param int $userid optional user id, 0 means all users
794 * @return array array of grades, false if none
795 */
612607bd 796function data_get_user_grades($data, $userid=0) {
8429163d 797 global $DB;
04366d79 798
9c00b5d7 799 $user = $userid ? "AND u.id = :userid" : "";
800 $params = array('userid'=>$userid, 'dataid'=>$data->id);
04366d79 801
ac9b0805 802 $sql = "SELECT u.id, u.id AS userid, avg(drt.rating) AS rawgrade
9c00b5d7 803 FROM {user} u, {data_records} dr,
804 {data_ratings} drt
04366d79 805 WHERE u.id = dr.userid AND dr.id = drt.recordid
9c00b5d7 806 AND drt.userid != u.id AND dr.dataid = :dataid
04366d79 807 $user
808 GROUP BY u.id";
809
9c00b5d7 810 return $DB->get_records_sql($sql, $params);
04366d79 811}
812
813/**
775f811a 814 * Update activity grades
04366d79 815 *
775f811a 816 * @param object $data
817 * @param int $userid specific user only, 0 means all
04366d79 818 */
775f811a 819function data_update_grades($data, $userid=0, $nullifnone=true) {
9c00b5d7 820 global $CFG, $DB;
821 require_once($CFG->libdir.'/gradelib.php');
04366d79 822
775f811a 823 if (!$data->assessed) {
824 data_grade_item_update($data);
b572ce19 825
775f811a 826 } else if ($grades = data_get_user_grades($data, $userid)) {
827 data_grade_item_update($data, $grades);
b572ce19 828
775f811a 829 } else if ($userid and $nullifnone) {
830 $grade = new object();
831 $grade->userid = $userid;
832 $grade->rawgrade = NULL;
833 data_grade_item_update($data, $grade);
b572ce19 834
04366d79 835 } else {
775f811a 836 data_grade_item_update($data);
837 }
838}
839
840/**
841 * Update all grades in gradebook.
842 */
843function data_upgrade_grades() {
844 global $DB;
845
846 $sql = "SELECT COUNT('x')
847 FROM {data} d, {course_modules} cm, {modules} m
848 WHERE m.name='data' AND m.id=cm.module AND cm.instance=d.id";
849 $count = $DB->count_records_sql($sql);
850
851 $sql = "SELECT d.*, cm.idnumber AS cmidnumber, d.course AS courseid
852 FROM {data} d, {course_modules} cm, {modules} m
853 WHERE m.name='data' AND m.id=cm.module AND cm.instance=d.id";
854 if ($rs = $DB->get_recordset_sql($sql)) {
855 // too much debug output
775f811a 856 $pbar = new progress_bar('dataupgradegrades', 500, true);
857 $i=0;
858 foreach ($rs as $data) {
859 $i++;
860 upgrade_set_timeout(60*5); // set up timeout, may also abort execution
861 data_update_grades($data, 0, false);
862 $pbar->update($i, $count, "Updating Database grades ($i/$count).");
04366d79 863 }
775f811a 864 $rs->close();
04366d79 865 }
866}
867
868/**
612607bd 869 * Update/create grade item for given data
04366d79 870 *
871 * @param object $data object with extra cmidnumber
0b5a80a1 872 * @param mixed optional array/object of grade(s); 'reset' means reset grades in gradebook
04366d79 873 * @return object grade_item
874 */
0b5a80a1 875function data_grade_item_update($data, $grades=NULL) {
612607bd 876 global $CFG;
9c00b5d7 877 require_once($CFG->libdir.'/gradelib.php');
04366d79 878
13534ef7 879 $params = array('itemname'=>$data->name, 'idnumber'=>$data->cmidnumber);
b572ce19 880
04366d79 881 if (!$data->assessed or $data->scale == 0) {
612607bd 882 $params['gradetype'] = GRADE_TYPE_NONE;
b572ce19 883
04366d79 884 } else if ($data->scale > 0) {
885 $params['gradetype'] = GRADE_TYPE_VALUE;
886 $params['grademax'] = $data->scale;
887 $params['grademin'] = 0;
b572ce19 888
04366d79 889 } else if ($data->scale < 0) {
890 $params['gradetype'] = GRADE_TYPE_SCALE;
891 $params['scaleid'] = -$data->scale;
892 }
b572ce19 893
0b5a80a1 894 if ($grades === 'reset') {
895 $params['reset'] = true;
896 $grades = NULL;
897 }
898
899 return grade_update('mod/data', $data->course, 'mod', 'data', $data->id, 0, $grades, $params);
04366d79 900}
901
902/**
903 * Delete grade item for given data
904 *
905 * @param object $data object
906 * @return object grade_item
907 */
908function data_grade_item_delete($data) {
612607bd 909 global $CFG;
910 require_once($CFG->libdir.'/gradelib.php');
b572ce19 911
b67ec72f 912 return grade_update('mod/data', $data->course, 'mod', 'data', $data->id, 0, NULL, array('deleted'=>1));
04366d79 913}
914
3d4b223a 915/************************************************************************
916 * returns a list of participants of this database *
917 ************************************************************************/
918function data_get_participants($dataid) {
b8b554ac 919// Returns the users with data in one data
920// (users with records in data_records, data_comments and data_ratings)
8429163d 921 global $DB;
9c00b5d7 922
923 $records = $DB->get_records_sql("SELECT DISTINCT u.id, u.id
924 FROM {user} u, {data_records} r
925 WHERE r.dataid = ? AND u.id = r.userid", array($dataid));
926
927 $comments = $DB->get_records_sql("SELECT DISTINCT u.id, u.id
928 FROM {user} u, {data_records} r, {data_comments} c
929 WHERE r.dataid = ? AND u.id = r.userid AND r.id = c.recordid", array($dataid));
930
931 $ratings = $DB->get_records_sql("SELECT DISTINCT u.id, u.id
932 FROM {user} u, {data_records} r, {data_ratings} a
933 WHERE r.dataid = ? AND u.id = r.userid AND r.id = a.recordid", array($dataid));
3d4b223a 934
935 $participants = array();
b572ce19 936
8429163d 937 if ($records) {
3d4b223a 938 foreach ($records as $record) {
939 $participants[$record->id] = $record;
940 }
941 }
8429163d 942 if ($comments) {
3d4b223a 943 foreach ($comments as $comment) {
944 $participants[$comment->id] = $comment;
945 }
946 }
8429163d 947 if ($ratings) {
cf040300 948 foreach ($ratings as $rating) {
949 $participants[$rating->id] = $rating;
950 }
951 }
b572ce19 952
3d4b223a 953 return $participants;
954}
955
b8b554ac 956// junk functions
3d4b223a 957/************************************************************************
958 * takes a list of records, the current data, a search string, *
959 * and mode to display prints the translated template *
960 * input @param array $records *
961 * @param object $data *
962 * @param string $search *
cd2f6950 963 * @param string $template *
3d4b223a 964 * output null *
965 ************************************************************************/
d53e5129 966function data_print_template($template, $records, $data, $search='', $page=0, $return=false) {
9c00b5d7 967 global $CFG, $DB;
c088d603 968 $cm = get_coursemodule_from_instance('data', $data->id);
dabfd0ed 969 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
b572ce19 970
3d45b8e5 971 static $fields = NULL;
972 static $isteacher;
63701c78 973 static $dataid = NULL;
b572ce19 974
63701c78 975 if (empty($dataid)) {
976 $dataid = $data->id;
977 } else if ($dataid != $data->id) {
978 $fields = NULL;
979 }
b572ce19 980
3d45b8e5 981 if (empty($fields)) {
9c00b5d7 982 $fieldrecords = $DB->get_records('data_fields', array('dataid'=>$data->id));
3d45b8e5 983 foreach ($fieldrecords as $fieldrecord) {
984 $fields[]= data_get_field($fieldrecord, $data);
985 }
81e956b9 986 $isteacher = has_capability('mod/data:managetemplates', $context);
3d45b8e5 987 }
b572ce19 988
64452eb4 989 if (empty($records)) {
990 return;
991 }
b572ce19 992
668fc89a 993 foreach ($records as $record) { // Might be just one for the single template
b572ce19 994
b8b554ac 995 // Replacing tags
3d4b223a 996 $patterns = array();
997 $replacement = array();
b572ce19 998
b8b554ac 999 // Then we generate strings to replace for normal tags
3d45b8e5 1000 foreach ($fields as $field) {
f2584d0e 1001 $patterns[]='[['.$field->field->name.']]';
d118d06a 1002 $replacement[] = highlight($search, $field->display_browse_field($record->id, $template));
3d4b223a 1003 }
b572ce19 1004
b8b554ac 1005 // Replacing special tags (##Edit##, ##Delete##, ##More##)
e357c206 1006 $patterns[]='##edit##';
1007 $patterns[]='##delete##';
046dd7dc 1008 if (has_capability('mod/data:manageentries', $context) or data_isowner($record->id)) {
64452eb4 1009 $replacement[] = '<a href="'.$CFG->wwwroot.'/mod/data/edit.php?d='
0d905d9f 1010 .$data->id.'&amp;rid='.$record->id.'&amp;sesskey='.sesskey().'"><img src="'.$CFG->pixpath.'/t/edit.gif" class="iconsmall" alt="'.get_string('edit').'" title="'.get_string('edit').'" /></a>';
3d4b223a 1011 $replacement[] = '<a href="'.$CFG->wwwroot.'/mod/data/view.php?d='
0d905d9f 1012 .$data->id.'&amp;delete='.$record->id.'&amp;sesskey='.sesskey().'"><img src="'.$CFG->pixpath.'/t/delete.gif" class="iconsmall" alt="'.get_string('delete').'" title="'.get_string('delete').'" /></a>';
046dd7dc 1013 } else {
3d4b223a 1014 $replacement[] = '';
eeeb4f2a 1015 $replacement[] = '';
3d4b223a 1016 }
d53e5129 1017
1018 $moreurl = $CFG->wwwroot . '/mod/data/view.php?d=' . $data->id . '&amp;rid=' . $record->id;
32d799c6 1019 if ($search) {
1020 $moreurl .= '&amp;filter=1';
1021 }
e357c206 1022 $patterns[]='##more##';
d53e5129 1023 $replacement[] = '<a href="' . $moreurl . '"><img src="' . $CFG->pixpath . '/i/search.gif" class="iconsmall" alt="' . get_string('more', 'data') . '" title="' . get_string('more', 'data') . '" /></a>';
1024
e357c206 1025 $patterns[]='##moreurl##';
d53e5129 1026 $replacement[] = $moreurl;
473dd288 1027
e357c206 1028 $patterns[]='##user##';
64452eb4 1029 $replacement[] = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$record->userid.
1030 '&amp;course='.$data->course.'">'.fullname($record).'</a>';
8185aeb6 1031
1032 $patterns[]='##export##';
1033
1034 if (($template == 'singletemplate' || $template == 'listtemplate')
1035 && ((has_capability('mod/data:exportentry', $context)
1036 || (data_isowner($record->id) && has_capability('mod/data:exportownentry', $context))))) {
0d06b6fd 1037 $button = new portfolio_add_button();
276378e6 1038 $button->set_callback_options('data_portfolio_caller', array('id' => $cm->id, 'recordid' => $record->id));
6be1dcae 1039 list($formats, $files) = data_portfolio_caller::formats($fields, $record);
276378e6 1040 $button->set_formats($formats);
0d06b6fd 1041 $replacement[] = $button->to_html(PORTFOLIO_ADD_ICON_LINK);
8185aeb6 1042 } else {
1043 $replacement[] = '';
1044 }
8429163d 1045
c95034f2 1046 $patterns[] = '##timeadded##';
8429163d 1047 $replacement[] = userdate($record->timecreated);
c95034f2 1048
1049 $patterns[] = '##timemodified##';
35e129c1 1050 $replacement [] = userdate($record->timemodified);
473dd288 1051
e357c206 1052 $patterns[]='##approve##';
b572ce19 1053 if (has_capability('mod/data:approve', $context) && ($data->approval) && (!$record->approved)){
b4c8d1ea 1054 $replacement[] = '<span class="approve"><a href="'.$CFG->wwwroot.'/mod/data/view.php?d='.$data->id.'&amp;approve='.$record->id.'&amp;sesskey='.sesskey().'"><img src="'.$CFG->pixpath.'/i/approve.gif" class="icon" alt="'.get_string('approve').'" /></a></span>';
473dd288 1055 } else {
6e0119dd 1056 $replacement[] = '';
1057 }
6403e679 1058
e357c206 1059 $patterns[]='##comments##';
4d3d87f0 1060 if (($template == 'listtemplate') && ($data->comments)) {
9c00b5d7 1061 $comments = $DB->count_records('data_comments', array('recordid'=>$record->id));
53dc0dfb 1062 $replacement[] = '<a href="view.php?rid='.$record->id.'#comments">'.get_string('commentsn','data', $comments).'</a>';
4d3d87f0 1063 } else {
1064 $replacement[] = '';
1065 }
6e0119dd 1066
b8b554ac 1067 // actual replacement of the tags
f2584d0e 1068 $newtext = str_ireplace($patterns, $replacement, $data->{$template});
5023c3ab 1069
b8b554ac 1070 // no more html formatting and filtering - see MDL-6635
aa3b20e9 1071 if ($return) {
1072 return $newtext;
1073 } else {
1074 echo $newtext;
b572ce19 1075
aa3b20e9 1076 // hack alert - return is always false in singletemplate anyway ;-)
1077 /**********************************
1078 * Printing Ratings Form *
1079 *********************************/
1080 if ($template == 'singletemplate') { //prints ratings options
1081 data_print_ratings($data, $record);
1082 }
b572ce19 1083
aa3b20e9 1084 /**********************************
1085 * Printing Ratings Form *
1086 *********************************/
1087 if (($template == 'singletemplate') && ($data->comments)) { //prints ratings options
b572ce19 1088
aa3b20e9 1089 data_print_comments($data, $record, $page);
1090 }
4d3d87f0 1091 }
3d4b223a 1092 }
1093}
1094
a593aeee 1095
3d4b223a 1096/************************************************************************
1097 * function that takes in the current data, number of items per page, *
1098 * a search string and prints a preference box in view.php *
7900ecb0 1099 * *
1100 * This preference box prints a searchable advanced search template if *
86638489 1101 * a) A template is defined *
1102 * b) The advanced search checkbox is checked. *
1103 * *
3d4b223a 1104 * input @param object $data *
1105 * @param int $perpage *
1106 * @param string $search *
1107 * output null *
1108 ************************************************************************/
7900ecb0 1109function data_print_preference_form($data, $perpage, $search, $sort='', $order='ASC', $search_array = '', $advanced = 0, $mode= ''){
9c00b5d7 1110 global $CFG, $DB;
8429163d 1111
7900ecb0 1112 $cm = get_coursemodule_from_instance('data', $data->id);
1113 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1114 echo '<br /><div class="datapreferences">';
b7dc2256 1115 echo '<form id="options" action="view.php" method="get">';
7900ecb0 1116 echo '<div>';
473dd288 1117 echo '<input type="hidden" name="d" value="'.$data->id.'" />';
7900ecb0 1118 if ($mode =='asearch') {
1119 $advanced = 1;
1120 echo '<input type="hidden" name="mode" value="list" />';
1121 }
a032a460 1122 echo '<label for="pref_perpage">'.get_string('pagesize','data').'</label> ';
76a2fd82 1123 $pagesizes = array(2=>2,3=>3,4=>4,5=>5,6=>6,7=>7,8=>8,9=>9,10=>10,15=>15,
6e0119dd 1124 20=>20,30=>30,40=>40,50=>50,100=>100,200=>200,300=>300,400=>400,500=>500,1000=>1000);
76a2fd82 1125 choose_from_menu($pagesizes, 'perpage', $perpage, '', '', '0', false, false, 0, 'pref_perpage');
7900ecb0 1126 echo '<div id="reg_search" style="display: ';
1127 if ($advanced) {
1128 echo 'none';
1129 }
1130 else {
1131 echo 'inline';
1132 }
1133 echo ';" >&nbsp;&nbsp;&nbsp;<label for="pref_search">'.get_string('search').'</label> <input type="text" size="16" name="search" id= "pref_search" value="'.s($search).'" /></div>';
a032a460 1134 echo '&nbsp;&nbsp;&nbsp;<label for="pref_sortby">'.get_string('sortby').'</label> ';
b8b554ac 1135 // foreach field, print the option
3239b010 1136 echo '<select name="sort" id="pref_sortby">';
9c00b5d7 1137 if ($fields = $DB->get_records('data_fields', array('dataid'=>$data->id), 'name')) {
3239b010 1138 echo '<optgroup label="'.get_string('fields', 'data').'">';
1139 foreach ($fields as $field) {
1140 if ($field->id == $sort) {
1141 echo '<option value="'.$field->id.'" selected="selected">'.$field->name.'</option>';
1142 } else {
1143 echo '<option value="'.$field->id.'">'.$field->name.'</option>';
1144 }
1145 }
1146 echo '</optgroup>';
714bec74 1147 }
3239b010 1148 $options = array();
1149 $options[DATA_TIMEADDED] = get_string('timeadded', 'data');
1150 $options[DATA_TIMEMODIFIED] = get_string('timemodified', 'data');
1151 $options[DATA_FIRSTNAME] = get_string('authorfirstname', 'data');
1152 $options[DATA_LASTNAME] = get_string('authorlastname', 'data');
bb5740f4 1153 if ($data->approval and has_capability('mod/data:approve', $context)) {
1154 $options[DATA_APPROVED] = get_string('approved', 'data');
1155 }
3239b010 1156 echo '<optgroup label="'.get_string('other', 'data').'">';
714bec74 1157 foreach ($options as $key => $name) {
1158 if ($key == $sort) {
1159 echo '<option value="'.$key.'" selected="selected">'.$name.'</option>';
cf3e199b 1160 } else {
714bec74 1161 echo '<option value="'.$key.'">'.$name.'</option>';
cf3e199b 1162 }
1163 }
3239b010 1164 echo '</optgroup>';
cf3e199b 1165 echo '</select>';
a032a460 1166 echo '<label for="pref_order" class="accesshide">'.get_string('order').'</label>';
1167 echo '<select id="pref_order" name="order">';
c8505cac 1168 if ($order == 'ASC') {
af25f45e 1169 echo '<option value="ASC" selected="selected">'.get_string('ascending','data').'</option>';
cf3e199b 1170 } else {
1171 echo '<option value="ASC">'.get_string('ascending','data').'</option>';
1172 }
c8505cac 1173 if ($order == 'DESC') {
af25f45e 1174 echo '<option value="DESC" selected="selected">'.get_string('descending','data').'</option>';
cf3e199b 1175 } else {
1176 echo '<option value="DESC">'.get_string('descending','data').'</option>';
1177 }
af25f45e 1178 echo '</select>';
86638489 1179
7900ecb0 1180 if ($advanced) {
1181 $checked = ' checked="checked" ';
1182 }
1183 else {
1184 $checked = '';
1185 }
1186 print '
8429163d 1187
7900ecb0 1188 <script type="text/javascript">
1189 //<![CDATA[
1190 <!-- Start
1191 // javascript for hiding/displaying advanced search form
1192
1193 function showHideAdvSearch(checked) {
1194 var divs = document.getElementsByTagName(\'div\');
1195 for(i=0;i<divs.length;i++) {
1196 if(divs[i].id.match(\'data_adv_form\')) {
1197 if(checked) {
1198 divs[i].style.display = \'inline\';
1199 }
1200 else {
1201 divs[i].style.display = \'none\';
1202 }
1203 }
1204 else if (divs[i].id.match(\'reg_search\')) {
1205 if (!checked) {
1206 divs[i].style.display = \'inline\';
1207 }
1208 else {
1209 divs[i].style.display = \'none\';
1210 }
1211 }
1212 }
1213 }
1214 // End -->
1215 //]]>
1216 </script>';
de8ff581 1217 echo '&nbsp;<input type="hidden" name="advanced" value="0" />';
d53e5129 1218 echo '&nbsp;<input type="hidden" name="filter" value="1" />';
714bec74 1219 echo '&nbsp;<input type="checkbox" id="advancedcheckbox" name="advanced" value="1" '.$checked.' onchange="showHideAdvSearch(this.checked);" /><label for="advancedcheckbox">'.get_string('advancedsearch', 'data').'</label>';
7900ecb0 1220 echo '&nbsp;<input type="submit" value="'.get_string('savesettings','data').'" />';
8429163d 1221
7900ecb0 1222 echo '<br />';
86638489 1223 echo '<div class="dataadvancedsearch" id="data_adv_form" style="display: ';
8429163d 1224
7900ecb0 1225 if ($advanced) {
1226 echo 'inline';
1227 }
1228 else {
1229 echo 'none';
1230 }
86638489 1231 echo ';margin-left:auto;margin-right:auto;" >';
7900ecb0 1232 echo '<table class="boxaligncenter">';
8429163d 1233
7900ecb0 1234 // print ASC or DESC
1235 echo '<tr><td colspan="2">&nbsp;</td></tr>';
1236 $i = 0;
1237
1238 // Determine if we are printing all fields for advanced search, or the template for advanced search
1239 // If a template is not defined, use the deafault template and display all fields.
1240 if(empty($data->asearchtemplate)) {
1241 data_generate_default_template($data, 'asearchtemplate');
1242 }
1243
1244 static $fields = NULL;
1245 static $isteacher;
1246 static $dataid = NULL;
b572ce19 1247
7900ecb0 1248 if (empty($dataid)) {
1249 $dataid = $data->id;
1250 } else if ($dataid != $data->id) {
1251 $fields = NULL;
1252 }
1253
1254 if (empty($fields)) {
9c00b5d7 1255 $fieldrecords = $DB->get_records('data_fields', array('dataid'=>$data->id));
7900ecb0 1256 foreach ($fieldrecords as $fieldrecord) {
1257 $fields[]= data_get_field($fieldrecord, $data);
1258 }
b572ce19 1259
7900ecb0 1260 $isteacher = has_capability('mod/data:managetemplates', $context);
1261 }
1262
b8b554ac 1263 // Replacing tags
7900ecb0 1264 $patterns = array();
1265 $replacement = array();
1266
b8b554ac 1267 // Then we generate strings to replace for normal tags
7900ecb0 1268 foreach ($fields as $field) {
98f67312 1269 $fieldname = $field->field->name;
1270 $fieldname = preg_quote($fieldname, '/');
1271 $patterns[] = "/\[\[$fieldname\]\]/i";
714bec74 1272 $searchfield = data_get_field_from_id($field->field->id, $data);
7900ecb0 1273 if (!empty($search_array[$field->field->id]->data)) {
1274 $replacement[] = $searchfield->display_search_field($search_array[$field->field->id]->data);
1275 } else {
1276 $replacement[] = $searchfield->display_search_field();
1277 }
1278 }
714bec74 1279 $fn = !empty($search_array[DATA_FIRSTNAME]->data) ? $search_array[DATA_FIRSTNAME]->data : '';
1280 $ln = !empty($search_array[DATA_LASTNAME]->data) ? $search_array[DATA_LASTNAME]->data : '';
1281 $patterns[] = '/##firstname##/';
bc16bd57 1282 $replacement[] = '<input type="text" size="16" name="u_fn" value="'.$fn.'" />';
714bec74 1283 $patterns[] = '/##lastname##/';
bc16bd57 1284 $replacement[] = '<input type="text" size="16" name="u_ln" value="'.$ln.'" />';
714bec74 1285
668fc89a 1286 // actual replacement of the tags
7900ecb0 1287 $newtext = preg_replace($patterns, $replacement, $data->asearchtemplate);
b572ce19 1288
055f2185 1289 $options = new object();
7900ecb0 1290 $options->para=false;
1291 $options->noclean=true;
1292 echo '<tr><td>';
1293 echo format_text($newtext, FORMAT_HTML, $options);
1294 echo '</td></tr>';
b572ce19 1295
eeeb4f2a 1296 echo '<tr><td colspan="4" style="text-align: center;"><br/><input type="submit" value="'.get_string('savesettings','data').'" /><input type="submit" name="resetadv" value="'.get_string('resetsettings','data').'" /></td></tr>';
7900ecb0 1297 echo '</table>';
c8505cac 1298 echo '</div>';
7900ecb0 1299 echo '</div>';
1300 echo '</form>';
b8b554ac 1301 echo '</div>';
3d4b223a 1302}
5f5bcda8 1303
4d3d87f0 1304function data_print_ratings($data, $record) {
9c00b5d7 1305 global $USER, $DB;
3d45b8e5 1306
c088d603 1307 $cm = get_coursemodule_from_instance('data', $data->id);
dabfd0ed 1308 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
b572ce19 1309
7900ecb0 1310 if ($data->assessed and !empty($USER->id) and (has_capability('mod/data:rate', $context) or has_capability('mod/data:viewrating', $context) or data_isowner($record->id))) {
3b827a7e 1311 if ($ratingsscale = make_grades_menu($data->scale)) {
1312 $ratingsmenuused = false;
b572ce19 1313
91f3f616 1314 echo '<div class="ratings" style="text-align:center">';
b7dc2256 1315 echo '<form id="form" method="post" action="rate.php">';
04366d79 1316 echo '<input type="hidden" name="dataid" value="'.$data->id.'" />';
b572ce19 1317
3b827a7e 1318 if (has_capability('mod/data:rate', $context) and !data_isowner($record->id)) {
1319 data_print_ratings_mean($record->id, $ratingsscale, has_capability('mod/data:viewrating', $context));
1320 echo '&nbsp;';
1321 data_print_rating_menu($record->id, $USER->id, $ratingsscale);
1322 $ratingsmenuused = true;
b572ce19 1323
3b827a7e 1324 } else {
1325 data_print_ratings_mean($record->id, $ratingsscale, true);
1326 }
b572ce19 1327
3b827a7e 1328 if ($data->scale < 0) {
9c00b5d7 1329 if ($scale = $DB->get_record('scale', array('id'=>abs($data->scale)))) {
3b827a7e 1330 print_scale_menu_helpbutton($data->course, $scale );
4d3d87f0 1331 }
4d3d87f0 1332 }
3b827a7e 1333
1334 if ($ratingsmenuused) {
1335 echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
1336 echo '<input type="submit" value="'.get_string('sendinratings', 'data').'" />';
1337 }
1338 echo '</form>';
1339 echo '</div>';
4d3d87f0 1340 }
1341 }
1342}
1343
1344function data_print_ratings_mean($recordid, $scale, $link=true) {
b8b554ac 1345// Print the multiple ratings on a post given to the current user by others.
1346// Scale is an array of ratings
4d3d87f0 1347 static $strrate;
b572ce19 1348
4d3d87f0 1349 $mean = data_get_ratings_mean($recordid, $scale);
b572ce19 1350
4d3d87f0 1351 if ($mean !== "") {
b572ce19 1352
4d3d87f0 1353 if (empty($strratings)) {
e51d9eb4 1354 $strratings = get_string("ratings", "data");
4d3d87f0 1355 }
b572ce19 1356
4d3d87f0 1357 echo "$strratings: ";
1358 if ($link) {
1359 link_to_popup_window ("/mod/data/report.php?id=$recordid", "ratings", $mean, 400, 600);
1360 } else {
1361 echo "$mean ";
1362 }
1363 }
1364}
1365
1366
1367function data_get_ratings_mean($recordid, $scale, $ratings=NULL) {
b8b554ac 1368// Return the mean rating of a post given to the current user by others.
1369// Scale is an array of possible ratings in the scale
1370// Ratings is an optional simple array of actual ratings (just integers)
9c00b5d7 1371 global $DB;
4d3d87f0 1372
1373 if (!$ratings) {
1374 $ratings = array();
9c00b5d7 1375 if ($rates = $DB->get_records("data_ratings", array("recordid"=>$recordid))) {
4d3d87f0 1376 foreach ($rates as $rate) {
1377 $ratings[] = $rate->rating;
1378 }
1379 }
1380 }
b572ce19 1381
4d3d87f0 1382 $count = count($ratings);
b572ce19 1383
4d3d87f0 1384 if ($count == 0) {
1385 return "";
b572ce19 1386
4d3d87f0 1387 } else if ($count == 1) {
1388 return $scale[$ratings[0]];
b572ce19 1389
4d3d87f0 1390 } else {
1391 $total = 0;
1392 foreach ($ratings as $rating) {
1393 $total += $rating;
1394 }
1395 $mean = round( ((float)$total/(float)$count) + 0.001); // Little fudge factor so that 0.5 goes UP
b572ce19 1396
4d3d87f0 1397 if (isset($scale[$mean])) {
1398 return $scale[$mean]." ($count)";
1399 } else {
1400 return "$mean ($count)"; // Should never happen, hopefully
1401 }
1402 }
1403}
1404
1405
1406function data_print_rating_menu($recordid, $userid, $scale) {
b8b554ac 1407// Print the menu of ratings as part of a larger form.
1408// If the post has already been - set that value.
1409// Scale is an array of ratings
9c00b5d7 1410 global $DB;
4d3d87f0 1411
1412 static $strrate;
1413
9c00b5d7 1414 if (!$rating = $DB->get_record("data_ratings", array("userid"=>$userid, "recordid"=>$recordid))) {
04366d79 1415 $rating->rating = -999;
4d3d87f0 1416 }
b572ce19 1417
4d3d87f0 1418 if (empty($strrate)) {
e51d9eb4 1419 $strrate = get_string("rate", "data");
4d3d87f0 1420 }
b572ce19 1421
04366d79 1422 choose_from_menu($scale, $recordid, $rating->rating, "$strrate...", '', -999);
4d3d87f0 1423}
1424
8429163d 1425/**
1426 * Returns a list of ratings for a particular post - sorted.
1427 */
4d3d87f0 1428function data_get_ratings($recordid, $sort="u.firstname ASC") {
8429163d 1429 global $DB;
4d3d87f0 1430
9c00b5d7 1431 return $DB->get_records_sql("SELECT u.*, r.rating
1432 FROM {data_ratings} r, {user} u
1433 WHERE r.recordid = ? AND r.userid = u.id
1434 ORDER BY $sort", array($recordid));
4d3d87f0 1435}
1436
b8b554ac 1437// prints all comments + a text box for adding additional comment
40b6dd01 1438function data_print_comments($data, $record, $page=0, $mform=false) {
9c00b5d7 1439 global $CFG, $DB;
3f9672d3 1440
2949cac7 1441 $cm = get_coursemodule_from_instance('data', $data->id);
1442 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1443 $cancomment = has_capability('mod/data:comment', $context);
64452eb4 1444 echo '<a name="comments"></a>';
1445
9c00b5d7 1446 if ($comments = $DB->get_records('data_comments', array('recordid'=>$record->id))) {
4d3d87f0 1447 foreach ($comments as $comment) {
52373fe7 1448 data_print_comment($data, $comment, $page);
4d3d87f0 1449 }
40b6dd01 1450 echo '<br />';
1451 }
b572ce19 1452
2949cac7 1453 if (!isloggedin() or isguest() or !$cancomment) {
40b6dd01 1454 return;
4d3d87f0 1455 }
b572ce19 1456
40b6dd01 1457 $editor = optional_param('addcomment', 0, PARAM_BOOL);
b572ce19 1458
40b6dd01 1459 if (!$mform and !$editor) {
91f3f616 1460 echo '<div class="newcomment" style="text-align:center">';
6b49eb8b 1461 echo '<a href="view.php?d='.$data->id.'&amp;rid='.$record->id.'&amp;mode=single&amp;addcomment=1">'.get_string('addcomment', 'data').'</a>';
40b6dd01 1462 echo '</div>';
1463 } else {
1464 if (!$mform) {
1465 require_once('comment_form.php');
1d284fbd 1466 $mform = new mod_data_comment_form('comment.php');
beac4717 1467 $mform->set_data(array('mode'=>'add', 'page'=>$page, 'rid'=>$record->id));
40b6dd01 1468 }
91f3f616 1469 echo '<div class="newcomment" style="text-align:center">';
40b6dd01 1470 $mform->display();
1471 echo '</div>';
7ebb0d48 1472 }
4d3d87f0 1473}
1474
b8b554ac 1475// prints a single comment entry
52373fe7 1476function data_print_comment($data, $comment, $page=0) {
9c00b5d7 1477 global $USER, $CFG, $DB;
6403e679 1478
c088d603 1479 $cm = get_coursemodule_from_instance('data', $data->id);
dabfd0ed 1480 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
b572ce19 1481
dabfd0ed 1482 $stredit = get_string('edit');
4d3d87f0 1483 $strdelete = get_string('delete');
1484
9c00b5d7 1485 $user = $DB->get_record('user', array('id'=>$comment->userid));
4d3d87f0 1486
236d839f 1487 echo '<table cellspacing="0" align="center" width="50%" class="datacomment forumpost">';
b572ce19 1488
4d3d87f0 1489 echo '<tr class="header"><td class="picture left">';
65bcf17b 1490 print_user_picture($user, $data->course, $user->picture);
4d3d87f0 1491 echo '</td>';
b572ce19 1492
2232755c 1493 echo '<td class="topic starter" align="left"><div class="author">';
bdeae2b9 1494 $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context));
1495 $by = new object();
2232755c 1496 $by->name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.
3d45b8e5 1497 $user->id.'&amp;course='.$data->course.'">'.$fullname.'</a>';
2232755c 1498 $by->date = userdate($comment->modified);
1499 print_string('bynameondate', 'data', $by);
4d3d87f0 1500 echo '</div></td></tr>';
b572ce19 1501
4d3d87f0 1502 echo '<tr><td class="left side">';
055f2185 1503 if ($groups = groups_get_all_groups($data->course, $comment->userid, $cm->groupingid)) {
f262874b 1504 print_group_picture($groups, $data->course, false, false, true);
4d3d87f0 1505 } else {
1506 echo '&nbsp;';
1507 }
1508
b8b554ac 1509// Actual content
b572ce19 1510
310639ff 1511 echo '</td><td class="content" align="left">'."\n";
b572ce19 1512
4d3d87f0 1513 // Print whole message
40b6dd01 1514 echo format_text($comment->content, $comment->format);
4d3d87f0 1515
b8b554ac 1516// Commands
b572ce19 1517
4d3d87f0 1518 echo '<div class="commands">';
0468976c 1519 if (data_isowner($comment->recordid) or has_capability('mod/data:managecomments', $context)) {
52373fe7 1520 echo '<a href="'.$CFG->wwwroot.'/mod/data/comment.php?rid='.$comment->recordid.'&amp;mode=edit&amp;commentid='.$comment->id.'&amp;page='.$page.'">'.$stredit.'</a>';
1521 echo '| <a href="'.$CFG->wwwroot.'/mod/data/comment.php?rid='.$comment->recordid.'&amp;mode=delete&amp;commentid='.$comment->id.'&amp;page='.$page.'">'.$strdelete.'</a>';
4d3d87f0 1522 }
1523
1524 echo '</div>';
b572ce19 1525
236d839f 1526 echo '</td></tr></table>'."\n\n";
4d3d87f0 1527}
4c03f920 1528
1529
1530// For Participantion Reports
1531function data_get_view_actions() {
1532 return array('view');
1533}
1534
1535function data_get_post_actions() {
1536 return array('add','update','record delete');
1537}
1538
0997e51a 1539function data_fieldname_exists($name, $dataid, $fieldid=0) {
9c00b5d7 1540 global $CFG, $DB;
0997e51a 1541
9c00b5d7 1542 $LIKE = $DB->sql_ilike();
6403e679 1543 if ($fieldid) {
9c00b5d7 1544 return $DB->record_exists_sql("SELECT * FROM {data_fields} df
1545 WHERE df.name $LIKE ? AND df.dataid = ?
1546 AND ((df.id < ?) OR (df.id > ?))", array($name, $dataid, $fieldid, $fieldid));
0997e51a 1547 } else {
9c00b5d7 1548 return $DB->record_exists_sql("SELECT * FROM {data_fields} df
1549 WHERE df.name $LIKE ? AND df.dataid = ?", array($name, $dataid));
0997e51a 1550 }
1551}
1552
1553function data_convert_arrays_to_strings(&$fieldinput) {
1554 foreach ($fieldinput as $key => $val) {
1555 if (is_array($val)) {
1556 $str = '';
1557 foreach ($val as $inner) {
1558 $str .= $inner . ',';
1559 }
1560 $str = substr($str, 0, -1);
b572ce19 1561
0997e51a 1562 $fieldinput->$key = $str;
1563 }
1564 }
1565}
1566
901dd2fb 1567
7f258664 1568/**
1569 * Converts a database (module instance) to use the Roles System
1570 * @param $data - a data object with the same attributes as a record
1571 * from the data database table
1572 * @param $datamodid - the id of the data module, from the modules table
1573 * @param $teacherroles - array of roles that have moodle/legacy:teacher
1574 * @param $studentroles - array of roles that have moodle/legacy:student
1575 * @param $guestroles - array of roles that have moodle/legacy:guest
1576 * @param $cmid - the course_module id for this data instance
1577 * @return boolean - data module was converted or not
1578 */
1579function data_convert_to_roles($data, $teacherroles=array(), $studentroles=array(), $cmid=NULL) {
9c00b5d7 1580 global $CFG, $DB;
6403e679 1581
7f258664 1582 if (!isset($data->participants) && !isset($data->assesspublic)
1583 && !isset($data->groupmode)) {
1584 // We assume that this database has already been converted to use the
1585 // Roles System. above fields get dropped the data module has been
1586 // upgraded to use Roles.
1587 return false;
1588 }
b572ce19 1589
7f258664 1590 if (empty($cmid)) {
1591 // We were not given the course_module id. Try to find it.
741c4d0b 1592 if (!$cm = get_coursemodule_from_instance('data', $data->id)) {
1593 notify('Could not get the course module for the data');
7f258664 1594 return false;
1595 } else {
1596 $cmid = $cm->id;
1597 }
1598 }
1599 $context = get_context_instance(CONTEXT_MODULE, $cmid);
6403e679 1600
b572ce19 1601
7f258664 1602 // $data->participants:
1603 // 1 - Only teachers can add entries
1604 // 3 - Teachers and students can add entries
1605 switch ($data->participants) {
1606 case 1:
1607 foreach ($studentroles as $studentrole) {
1608 assign_capability('mod/data:writeentry', CAP_PREVENT, $studentrole->id, $context->id);
1609 }
1610 foreach ($teacherroles as $teacherrole) {
1611 assign_capability('mod/data:writeentry', CAP_ALLOW, $teacherrole->id, $context->id);
1612 }
1613 break;
1614 case 3:
1615 foreach ($studentroles as $studentrole) {
1616 assign_capability('mod/data:writeentry', CAP_ALLOW, $studentrole->id, $context->id);
1617 }
1618 foreach ($teacherroles as $teacherrole) {
1619 assign_capability('mod/data:writeentry', CAP_ALLOW, $teacherrole->id, $context->id);
1620 }
1621 break;
1622 }
6403e679 1623
7f258664 1624 // $data->assessed:
1625 // 2 - Only teachers can rate posts
1626 // 1 - Everyone can rate posts
1627 // 0 - No one can rate posts
1628 switch ($data->assessed) {
1629 case 0:
1630 foreach ($studentroles as $studentrole) {
1631 assign_capability('mod/data:rate', CAP_PREVENT, $studentrole->id, $context->id);
1632 }
1633 foreach ($teacherroles as $teacherrole) {
1634 assign_capability('mod/data:rate', CAP_PREVENT, $teacherrole->id, $context->id);
1635 }
1636 break;
1637 case 1:
1638 foreach ($studentroles as $studentrole) {
1639 assign_capability('mod/data:rate', CAP_ALLOW, $studentrole->id, $context->id);
1640 }
1641 foreach ($teacherroles as $teacherrole) {
1642 assign_capability('mod/data:rate', CAP_ALLOW, $teacherrole->id, $context->id);
1643 }
1644 break;
1645 case 2:
1646 foreach ($studentroles as $studentrole) {
1647 assign_capability('mod/data:rate', CAP_PREVENT, $studentrole->id, $context->id);
1648 }
1649 foreach ($teacherroles as $teacherrole) {
1650 assign_capability('mod/data:rate', CAP_ALLOW, $teacherrole->id, $context->id);
1651 }
1652 break;
1653 }
6403e679 1654
7f258664 1655 // $data->assesspublic:
1656 // 0 - Students can only see their own ratings
1657 // 1 - Students can see everyone's ratings
1658 switch ($data->assesspublic) {
1659 case 0:
1660 foreach ($studentroles as $studentrole) {
1661 assign_capability('mod/data:viewrating', CAP_PREVENT, $studentrole->id, $context->id);
1662 }
1663 foreach ($teacherroles as $teacherrole) {
1664 assign_capability('mod/data:viewrating', CAP_ALLOW, $teacherrole->id, $context->id);
1665 }
1666 break;
1667 case 1:
1668 foreach ($studentroles as $studentrole) {
1669 assign_capability('mod/data:viewrating', CAP_ALLOW, $studentrole->id, $context->id);
1670 }
1671 foreach ($teacherroles as $teacherrole) {
1672 assign_capability('mod/data:viewrating', CAP_ALLOW, $teacherrole->id, $context->id);
1673 }
1674 break;
1675 }
1676
1677 if (empty($cm)) {
9c00b5d7 1678 $cm = $DB->get_record('course_modules', array('id'=>$cmid));
7f258664 1679 }
6403e679 1680
7f258664 1681 switch ($cm->groupmode) {
055f2185 1682 case NOGROUPS:
7f258664 1683 break;
055f2185 1684 case SEPARATEGROUPS:
7f258664 1685 foreach ($studentroles as $studentrole) {
1686 assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $studentrole->id, $context->id);
1687 }
1688 foreach ($teacherroles as $teacherrole) {
1689 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $teacherrole->id, $context->id);
1690 }
1691 break;
055f2185 1692 case VISIBLEGROUPS:
7f258664 1693 foreach ($studentroles as $studentrole) {
1694 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $studentrole->id, $context->id);
1695 }
1696 foreach ($teacherroles as $teacherrole) {
1697 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $teacherrole->id, $context->id);
1698 }
1699 break;
1700 }
1701 return true;
1702}
1703
6403e679 1704/*
8303eb84 1705 * Returns the best name to show for a preset
1706 */
1707function data_preset_name($shortname, $path) {
1708
668fc89a 1709 // We are looking inside the preset itself as a first choice, but also in normal data directory
30d76014 1710 $string = get_string('modulename', 'datapreset_'.$shortname);
8303eb84 1711
1712 if (substr($string, 0, 1) == '[') {
1713 return $shortname;
1714 } else {
1715 return $string;
1716 }
1717}
1718
6403e679 1719/*
8303eb84 1720 * Returns an array of all the available presets
1721 */
1722function data_get_available_presets($context) {
1723 global $CFG, $USER;
b572ce19 1724
8303eb84 1725 $presets = array();
b572ce19 1726
8303eb84 1727 if ($dirs = get_list_of_plugins('mod/data/preset')) {
1728 foreach ($dirs as $dir) {
1729 $fulldir = $CFG->dirroot.'/mod/data/preset/'.$dir;
b572ce19 1730
8303eb84 1731 if (is_directory_a_preset($fulldir)) {
1732 $preset = new object;
1733 $preset->path = $fulldir;
1734 $preset->userid = 0;
1735 $preset->shortname = $dir;
1736 $preset->name = data_preset_name($dir, $fulldir);
1737 if (file_exists($fulldir.'/screenshot.jpg')) {
1738 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.jpg';
1739 } else if (file_exists($fulldir.'/screenshot.png')) {
1740 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.png';
1741 } else if (file_exists($fulldir.'/screenshot.gif')) {
1742 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.gif';
1743 }
1744 $presets[] = $preset;
1745 }
1746 }
1747 }
1748
1749 if ($userids = get_list_of_plugins('data/preset', '', $CFG->dataroot)) {
1750 foreach ($userids as $userid) {
1751 $fulldir = $CFG->dataroot.'/data/preset/'.$userid;
b572ce19 1752
8303eb84 1753 if ($userid == 0 || $USER->id == $userid || has_capability('mod/data:viewalluserpresets', $context)) {
b572ce19 1754
8303eb84 1755 if ($dirs = get_list_of_plugins('data/preset/'.$userid, '', $CFG->dataroot)) {
1756 foreach ($dirs as $dir) {
1757 $fulldir = $CFG->dataroot.'/data/preset/'.$userid.'/'.$dir;
b572ce19 1758
8303eb84 1759 if (is_directory_a_preset($fulldir)) {
1760 $preset = new object;
1761 $preset->path = $fulldir;
1762 $preset->userid = $userid;
1763 $preset->shortname = $dir;
1764 $preset->name = data_preset_name($dir, $fulldir);
1765 if (file_exists($fulldir.'/screenshot.jpg')) {
1766 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.jpg';
1767 } else if (file_exists($fulldir.'/screenshot.png')) {
1768 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.png';
1769 } else if (file_exists($fulldir.'/screenshot.gif')) {
1770 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.gif';
1771 }
1772 $presets[] = $preset;
1773 }
1774 }
1775 }
1776 }
1777 }
1778 }
b572ce19 1779
8303eb84 1780 return $presets;
1781}
1782
1783
1784function data_print_header($course, $cm, $data, $currenttab='') {
b572ce19 1785
8303eb84 1786 global $CFG, $displaynoticegood, $displaynoticebad;
b572ce19 1787
38e179a4 1788 $navigation = build_navigation('', $cm);
ad7767be 1789 print_header_simple($data->name, '', $navigation,
6403e679 1790 '', '', true, update_module_button($cm->id, $course->id, get_string('modulename', 'data')),
8303eb84 1791 navmenu($course, $cm));
b572ce19 1792
8303eb84 1793 print_heading(format_string($data->name));
1794
b8b554ac 1795// Groups needed for Add entry tab
055f2185 1796 $currentgroup = groups_get_activity_group($cm);
5d59cbe9 1797 $groupmode = groups_get_activity_groupmode($cm);
b572ce19 1798
668fc89a 1799 // Print the tabs
b572ce19 1800
8303eb84 1801 if ($currenttab) {
138e480e 1802 include('tabs.php');
8303eb84 1803 }
b572ce19 1804
b8b554ac 1805 // Print any notices
b572ce19 1806
8303eb84 1807 if (!empty($displaynoticegood)) {
1808 notify($displaynoticegood, 'notifysuccess'); // good (usually green)
1809 } else if (!empty($displaynoticebad)) {
1810 notify($displaynoticebad); // bad (usuually red)
1811 }
1812}
7f258664 1813
04366d79 1814function data_user_can_add_entry($data, $currentgroup, $groupmode) {
cca1547e 1815 global $USER;
b572ce19 1816
cca1547e 1817 if (!$cm = get_coursemodule_from_instance('data', $data->id)) {
29c1bb15 1818 print_error('invalidcoursemodule');
cca1547e 1819 }
1820 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
b572ce19 1821
cca1547e 1822 if (!has_capability('mod/data:writeentry', $context) and !has_capability('mod/data:manageentries',$context)) {
1823 return false;
1824 }
b572ce19 1825
04366d79 1826 if (!$groupmode or has_capability('moodle/site:accessallgroups', $context)) {
1827 return true;
1828 }
1829
cca1547e 1830 if ($currentgroup) {
2c386f82 1831 return groups_is_member($currentgroup);
cca1547e 1832 } else {
1833 //else it might be group 0 in visible mode
1834 if ($groupmode == VISIBLEGROUPS){
cca1547e 1835 return true;
04366d79 1836 } else {
1837 return false;
cca1547e 1838 }
1839 }
1840}
1841
50194545 1842
1843function is_directory_a_preset($directory) {
1844 $directory = rtrim($directory, '/\\') . '/';
2dc6be3f 1845 $status = file_exists($directory.'singletemplate.html') &&
1846 file_exists($directory.'listtemplate.html') &&
1847 file_exists($directory.'listtemplateheader.html') &&
1848 file_exists($directory.'listtemplatefooter.html') &&
1849 file_exists($directory.'addtemplate.html') &&
1850 file_exists($directory.'rsstemplate.html') &&
1851 file_exists($directory.'rsstitletemplate.html') &&
1852 file_exists($directory.'csstemplate.css') &&
1853 file_exists($directory.'jstemplate.js') &&
1854 file_exists($directory.'preset.xml');
b572ce19 1855
2dc6be3f 1856 return $status;
50194545 1857}
1858
1859
1860function clean_preset($folder) {
2dc6be3f 1861 $status = @unlink($folder.'/singletemplate.html') &&
1862 @unlink($folder.'/listtemplate.html') &&
1863 @unlink($folder.'/listtemplateheader.html') &&
1864 @unlink($folder.'/listtemplatefooter.html') &&
1865 @unlink($folder.'/addtemplate.html') &&
1866 @unlink($folder.'/rsstemplate.html') &&
1867 @unlink($folder.'/rsstitletemplate.html') &&
1868 @unlink($folder.'/csstemplate.css') &&
1869 @unlink($folder.'/jstemplate.js') &&
1870 @unlink($folder.'/preset.xml');
1871
1872 // optional
1873 @unlink($folder.'/asearchtemplate.html');
b572ce19 1874
2dc6be3f 1875 return $status;
50194545 1876}
1877
1878
50194545 1879class PresetImporter {
1880 function PresetImporter($course, $cm, $data, $userid, $shortname) {
1881 global $CFG;
1882 $this->course = $course;
1883 $this->cm = $cm;
1884 $this->data = $data;
1885 $this->userid = $userid;
1886 $this->shortname = $shortname;
1887 $this->folder = data_preset_path($course, $userid, $shortname);
1888 }
1889
1890 function get_settings() {
9c00b5d7 1891 global $CFG, $DB;
50194545 1892
1893 if (!is_directory_a_preset($this->folder)) {
674b6ace 1894 print_error('invalidpreset', 'data', '', $this->userid.'/'.$this->shortname);
50194545 1895 }
1896
1897 /* Grab XML */
1898 $presetxml = file_get_contents($this->folder.'/preset.xml');
143c1eb9 1899 $parsedxml = xmlize($presetxml, 0);
50194545 1900
eaa30818 1901 $allowed_settings = array('intro', 'comments', 'requiredentries', 'requiredentriestoview',
1902 'maxentries', 'rssarticles', 'approval', 'defaultsortdir', 'defaultsort');
1903
50194545 1904 /* First, do settings. Put in user friendly array. */
1905 $settingsarray = $parsedxml['preset']['#']['settings'][0]['#'];
1906 $settings = new StdClass();
1907
1908 foreach ($settingsarray as $setting => $value) {
02007b01 1909 if (!is_array($value)) {
1910 continue;
1911 }
eaa30818 1912 if (!in_array($setting, $allowed_settings)) {
1913 // unsupported setting
1914 continue;
1915 }
50194545 1916 $settings->$setting = $value[0]['#'];
1917 }
1918
1919 /* Now work out fields to user friendly array */
1920 $fieldsarray = $parsedxml['preset']['#']['field'];
1921 $fields = array();
1922 foreach ($fieldsarray as $field) {
02007b01 1923 if (!is_array($field)) {
1924 continue;
1925 }
50194545 1926 $f = new StdClass();
1927 foreach ($field['#'] as $param => $value) {
02007b01 1928 if (!is_array($value)) {
1929 continue;
1930 }
9c00b5d7 1931 $f->$param = $value[0]['#'];
50194545 1932 }
1933 $f->dataid = $this->data->id;
1934 $f->type = clean_param($f->type, PARAM_ALPHA);
1935 $fields[] = $f;
1936 }
50194545 1937 /* Now add the HTML templates to the settings array so we can update d */
1938 $settings->singletemplate = file_get_contents($this->folder."/singletemplate.html");
1939 $settings->listtemplate = file_get_contents($this->folder."/listtemplate.html");
1940 $settings->listtemplateheader = file_get_contents($this->folder."/listtemplateheader.html");
1941 $settings->listtemplatefooter = file_get_contents($this->folder."/listtemplatefooter.html");
1942 $settings->addtemplate = file_get_contents($this->folder."/addtemplate.html");
1943 $settings->rsstemplate = file_get_contents($this->folder."/rsstemplate.html");
1944 $settings->rsstitletemplate = file_get_contents($this->folder."/rsstitletemplate.html");
1945 $settings->csstemplate = file_get_contents($this->folder."/csstemplate.css");
1946 $settings->jstemplate = file_get_contents($this->folder."/jstemplate.js");
1947
2dc6be3f 1948 //optional
1949 if (file_exists($this->folder."/asearchtemplate.html")) {
1950 $settings->asearchtemplate = file_get_contents($this->folder."/asearchtemplate.html");
1951 } else {
668fc89a 1952 $settings->asearchtemplate = NULL;
2dc6be3f 1953 }
1954
50194545 1955 $settings->instance = $this->data->id;
1956
1957 /* Now we look at the current structure (if any) to work out whether we need to clear db
1958 or save the data */
9c00b5d7 1959 if (!$currentfields = $DB->get_records('data_fields', array('dataid'=>$this->data->id))) {
eaa30818 1960 $currentfields = array();
1961 }
50194545 1962
1963 return array($settings, $fields, $currentfields);
1964 }
1965
1966 function import_options() {
1967 if (!confirm_sesskey()) {
29c1bb15 1968 print_error('invalidsesskey');
50194545 1969 }
b572ce19 1970
50194545 1971 $strblank = get_string('blank', 'data');
50194545 1972 $strcontinue = get_string('continue');
1973 $strwarning = get_string('mappingwarning', 'data');
1974 $strfieldmappings = get_string('fieldmappings', 'data');
1975 $strnew = get_string('new');
b572ce19 1976
50194545 1977 $sesskey = sesskey();
b572ce19 1978
50194545 1979 list($settings, $newfields, $currentfields) = $this->get_settings();
b572ce19 1980
8528bf26 1981 echo '<div class="presetmapping"><form action="preset.php" method="post">';
1982 echo '<div>';
50194545 1983 echo '<input type="hidden" name="action" value="finishimport" />';
1984 echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
1985 echo '<input type="hidden" name="d" value="'.$this->data->id.'" />';
1986 echo '<input type="hidden" name="fullname" value="'.$this->userid.'/'.$this->shortname.'" />';
b572ce19 1987
50194545 1988 if (!empty($currentfields) && !empty($newfields)) {
1989 echo "<h3>$strfieldmappings ";
f92d7ac9 1990 helpbutton('fieldmappings', $strfieldmappings, 'data');
50194545 1991 echo '</h3><table>';
b572ce19 1992
50194545 1993 foreach ($newfields as $nid => $newfield) {
1994 echo "<tr><td><label for=\"id_$newfield->name\">$newfield->name</label></td>";
1995 echo '<td><select name="field_'.$nid.'" id="id_'.$newfield->name.'">';
b572ce19 1996
50194545 1997 $selected = false;
1998 foreach ($currentfields as $cid => $currentfield) {
1999 if ($currentfield->type == $newfield->type) {
2000 if ($currentfield->name == $newfield->name) {
2001 echo '<option value="'.$cid.'" selected="selected">'.$currentfield->name.'</option>';
2002 $selected=true;
2003 }
2004 else {
02af98b5 2005 echo '<option value="'.$cid.'">'.$currentfield->name.'</option>';
50194545 2006 }
2007 }
2008 }
b572ce19 2009
50194545 2010 if ($selected)
2011 echo '<option value="-1">-</option>';
2012 else
2013 echo '<option value="-1" selected="selected">-</option>';
2014 echo '</select></td></tr>';
2015 }
2016 echo '</table>';
2017 echo "<p>$strwarning</p>";
b572ce19 2018
8528bf26 2019 } else if (empty($newfields)) {
29c1bb15 2020 print_error('nodefinedfields', 'data');
50194545 2021 }
b572ce19 2022
66aa084c 2023 echo '<div class="overwritesettings"><label for="overwritesettings">'.get_string('overwritesettings', 'data');
8528bf26 2024 echo '<input id="overwritesettings" name="overwritesettings" type="checkbox" /></label></div>';
b572ce19 2025
8528bf26 2026 echo '<input class="button" type="submit" value="'.$strcontinue.'" /></div></form></div>';
b572ce19 2027
50194545 2028 }
2029
2030 function import() {
9c00b5d7 2031 global $CFG, $DB;
50194545 2032
2033 list($settings, $newfields, $currentfields) = $this->get_settings();
2034 $preservedfields = array();
b572ce19 2035
8528bf26 2036 $overwritesettings = optional_param('overwritesettings', 0, PARAM_BOOL);
b572ce19 2037
50194545 2038 /* Maps fields and makes new ones */
2039 if (!empty($newfields)) {
2040 /* We require an injective mapping, and need to know what to protect */
2041 foreach ($newfields as $nid => $newfield) {
2042 $cid = optional_param("field_$nid", -1, PARAM_INT);
2043 if ($cid == -1) continue;
b572ce19 2044
29c1bb15 2045 if (array_key_exists($cid, $preservedfields)){
2046 print_error('notinjectivemap', 'data');
8429163d 2047 }
50194545 2048 else $preservedfields[$cid] = true;
2049 }
b572ce19 2050
50194545 2051 foreach ($newfields as $nid => $newfield) {
2052 $cid = optional_param("field_$nid", -1, PARAM_INT);
b572ce19 2053
50194545 2054 /* A mapping. Just need to change field params. Data kept. */
2055 if ($cid != -1 and isset($currentfields[$cid])) {
2056 $fieldobject = data_get_field_from_id($currentfields[$cid]->id, $this->data);
2057 foreach ($newfield as $param => $value) {
2058 if ($param != "id") {
2059 $fieldobject->field->$param = $value;
2060 }
2061 }
2062 unset($fieldobject->field->similarfield);
2063 $fieldobject->update_field();
2064 unset($fieldobject);
2065 }
2066 /* Make a new field */
2067 else {
2068 include_once("field/$newfield->type/field.class.php");
b572ce19 2069
50194545 2070 if (!isset($newfield->description)) {
2071 $newfield->description = '';
2072 }
2073 $classname = 'data_field_'.$newfield->type;
2074 $fieldclass = new $classname($newfield, $this->data);
2075 $fieldclass->insert_field();
2076 unset($fieldclass);
2077 }
2078 }
2079 }
2080
2081 /* Get rid of all old unused data */
2082 if (!empty($preservedfields)) {
2083 foreach ($currentfields as $cid => $currentfield) {
2084 if (!array_key_exists($cid, $preservedfields)) {
2085 /* Data not used anymore so wipe! */
2086 print "Deleting field $currentfield->name<br />";
b572ce19 2087
50194545 2088 $id = $currentfield->id;
2089 //Why delete existing data records and related comments/ratings??
2090/*
9c00b5d7 2091 if ($content = $DB->get_records('data_content', array('fieldid'=>$id))) {
50194545 2092 foreach ($content as $item) {
9c00b5d7 2093 $DB->delete_records('data_ratings', array('recordid'=>$item->recordid));
2094 $DB->delete_records('data_comments', array('recordid'=>$item->recordid));
2095 $DB->delete_records('data_records', array('id'=>$item->recordid));
50194545 2096 }
2097 }*/
9c00b5d7 2098 $DB->delete_records('data_content', array('fieldid'=>$id));
2099 $DB->delete_records('data_fields', array('id'=>$id));
50194545 2100 }
2101 }
2102 }
2103
b8b554ac 2104 // handle special settings here
eaa30818 2105 if (!empty($settings->defaultsort)) {
2106 if (is_numeric($settings->defaultsort)) {
668fc89a 2107 // old broken value
eaa30818 2108 $settings->defaultsort = 0;
2109 } else {
9c00b5d7 2110 $settings->defaultsort = (int)$DB->get_field('data_fields', 'id', array('dataid'=>$this->data->id, 'name'=>$settings->defaultsort));
eaa30818 2111 }
2112 } else {
2113 $settings->defaultsort = 0;
2114 }
2115
2116 // do we want to overwrite all current database settings?
8528bf26 2117 if ($overwritesettings) {
eaa30818 2118 // all supported settings
8528bf26 2119 $overwrite = array_keys((array)$settings);
2120 } else {
eaa30818 2121 // only templates and sorting
8528bf26 2122 $overwrite = array('singletemplate', 'listtemplate', 'listtemplateheader', 'listtemplatefooter',
2123 'addtemplate', 'rsstemplate', 'rsstitletemplate', 'csstemplate', 'jstemplate',
eaa30818 2124 'asearchtemplate', 'defaultsortdir', 'defaultsort');
8528bf26 2125 }
2126
eaa30818 2127 // now overwrite current data settings
13534ef7 2128 foreach ($this->data as $prop=>$unused) {
8528bf26 2129 if (in_array($prop, $overwrite)) {
db0f2a44 2130 $this->data->$prop = $settings->$prop;
13534ef7
ML
2131 }
2132 }
db0f2a44 2133
9c00b5d7 2134 data_update_instance($this->data);
50194545 2135
eaa30818 2136 if (strstr($this->folder, '/temp/')) {
2137 // Removes the temporary files
8429163d 2138 clean_preset($this->folder);
eaa30818 2139 }
b572ce19 2140
50194545 2141 return true;
2142 }
2143}
2144
2145function data_preset_path($course, $userid, $shortname) {
2146 global $USER, $CFG;
b572ce19 2147
50194545 2148 $context = get_context_instance(CONTEXT_COURSE, $course->id);
b572ce19 2149
50194545 2150 $userid = (int)$userid;
b572ce19 2151
50194545 2152 if ($userid > 0 && ($userid == $USER->id || has_capability('mod/data:viewalluserpresets', $context))) {
2153 return $CFG->dataroot.'/data/preset/'.$userid.'/'.$shortname;
2154 } else if ($userid == 0) {
2155 return $CFG->dirroot.'/mod/data/preset/'.$shortname;
2156 } else if ($userid < 0) {
2157 return $CFG->dataroot.'/temp/data/'.-$userid.'/'.$shortname;
2158 }
b572ce19 2159
50194545 2160 return 'Does it disturb you that this code will never run?';
2161}
0b5a80a1 2162
2163/**
2164 * Implementation of the function for printing the form elements that control
2165 * whether the course reset functionality affects the data.
2166 * @param $mform form passed by reference
2167 */
2168function data_reset_course_form_definition(&$mform) {
2169 $mform->addElement('header', 'dataheader', get_string('modulenameplural', 'data'));
2170 $mform->addElement('checkbox', 'reset_data', get_string('deleteallentries','data'));
2171
2172 $mform->addElement('checkbox', 'reset_data_notenrolled', get_string('deletenotenrolled', 'data'));
2173 $mform->disabledIf('reset_data_notenrolled', 'reset_data', 'checked');
2174
2175 $mform->addElement('checkbox', 'reset_data_ratings', get_string('deleteallratings'));
2176 $mform->disabledIf('reset_data_ratings', 'reset_data', 'checked');
2177
2178 $mform->addElement('checkbox', 'reset_data_comments', get_string('deleteallcomments'));
2179 $mform->disabledIf('reset_data_comments', 'reset_data', 'checked');
2180}
2181
2182/**
2183 * Course reset form defaults.
2184 */
2185function data_reset_course_form_defaults($course) {
2186 return array('reset_data'=>0, 'reset_data_ratings'=>1, 'reset_data_comments'=>1, 'reset_data_notenrolled'=>0);
2187}
2188
2189/**
2190 * Removes all grades from gradebook
2191 * @param int $courseid
2192 * @param string optional type
2193 */
2194function data_reset_gradebook($courseid, $type='') {
9c00b5d7 2195 global $CFG, $DB;
0b5a80a1 2196
2197 $sql = "SELECT d.*, cm.idnumber as cmidnumber, d.course as courseid
9c00b5d7 2198 FROM {data} d, {course_modules} cm, {modules} m
2199 WHERE m.name='data' AND m.id=cm.module AND cm.instance=d.id AND d.course=?";
0b5a80a1 2200
9c00b5d7 2201 if ($datas = $DB->get_records_sql($sql, array($courseid))) {
0b5a80a1 2202 foreach ($datas as $data) {
2203 data_grade_item_update($data, 'reset');
2204 }
2205 }
2206}
2207
2208/**
2209 * Actual implementation of the rest coures functionality, delete all the
2210 * data responses for course $data->courseid.
2211 * @param $data the data submitted from the reset course.
2212 * @return array status array
2213 */
2214function data_reset_userdata($data) {
9c00b5d7 2215 global $CFG, $DB;
0b5a80a1 2216 require_once($CFG->libdir.'/filelib.php');
b572ce19 2217
0b5a80a1 2218 $componentstr = get_string('modulenameplural', 'data');
2219 $status = array();
b572ce19 2220
0b5a80a1 2221 $allrecordssql = "SELECT r.id
9c00b5d7 2222 FROM {data_records} r
2223 INNER JOIN {data} d ON r.dataid = d.id
2224 WHERE d.course = ?";
0b5a80a1 2225
2226 $alldatassql = "SELECT d.id
9c00b5d7 2227 FROM {data} d
2228 WHERE d.course=?";
0b5a80a1 2229
2230 // delete entries if requested
2231 if (!empty($data->reset_data)) {
9c00b5d7 2232 $DB->delete_records_select('data_ratings', "recordid IN ($allrecordssql)", array($data->courseid));
2233 $DB->delete_records_select('data_comments', "recordid IN ($allrecordssql)", array($data->courseid));
2234 $DB->delete_records_select('data_content', "recordid IN ($allrecordssql)", array($data->courseid));
2235 $DB->delete_records_select('data_records', "dataid IN ($alldatassql)", array($data->courseid));
0b5a80a1 2236
9c00b5d7 2237 if ($datas = $DB->get_records_sql($alldatassql, array($data->courseid))) {
0b5a80a1 2238 foreach ($datas as $dataid=>$unused) {
2239 fulldelete("$CFG->dataroot/$data->courseid/moddata/data/$dataid");
2240 }
2241 }
b572ce19 2242
0b5a80a1 2243 if (empty($data->reset_gradebook_grades)) {
2244 // remove all grades from gradebook
2245 data_reset_gradebook($data->courseid);
2246 }
2247 $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallentries', 'data'), 'error'=>false);
2248 }
2249
2250 // remove entries by users not enrolled into course
2251 if (!empty($data->reset_data_notenrolled)) {
2252 $recordssql = "SELECT r.id, r.userid, r.dataid, u.id AS userexists, u.deleted AS userdeleted
9c00b5d7 2253 FROM {data_records} r
2254 JOIN {data} d ON r.dataid = d.id
2255 LEFT JOIN {user} u ON r.userid = u.id
2256 WHERE d.course = ? AND r.userid > 0";
0b5a80a1 2257
2258 $course_context = get_context_instance(CONTEXT_COURSE, $data->courseid);
2259 $notenrolled = array();
2260 $fields = array();
9c00b5d7 2261 if ($rs = $DB->get_recordset_sql($recordssql, array($data->courseid))) {
2262 foreach ($rs as $record) {
0b5a80a1 2263 if (array_key_exists($record->userid, $notenrolled) or !$record->userexists or $record->userdeleted
2264 or !has_capability('moodle/course:view', $course_context , $record->userid)) {
9c00b5d7 2265 $DB->delete_records('data_ratings', array('recordid'=>$record->id));
2266 $DB->delete_records('data_comments', array('recordid'=>$record->id));
2267 $DB->delete_records('data_content', array('recordid'=>$record->id));
2268 $DB->delete_records('data_records', array('id'=>$record->id));
0b5a80a1 2269 // HACK: this is ugly - the recordid should be before the fieldid!
2270 if (!array_key_exists($record->dataid, $fields)) {
9c00b5d7 2271 if ($fs = $DB->get_records('data_fields', array('dataid'=>$record->dataid))) {
0b5a80a1 2272 $fields[$record->dataid] = array_keys($fs);
2273 } else {
2274 $fields[$record->dataid] = array();
2275 }
2276 }
2277 foreach($fields[$record->dataid] as $fieldid) {
2278 fulldelete("$CFG->dataroot/$data->courseid/moddata/data/$record->dataid/$fieldid/$record->id");
2279 }
2280 $notenrolled[$record->userid] = true;
2281 }
2282 }
9c00b5d7 2283 $rs->close();
0b5a80a1 2284 $status[] = array('component'=>$componentstr, 'item'=>get_string('deletenotenrolled', 'data'), 'error'=>false);
2285 }
2286 }
2287
2288 // remove all ratings
2289 if (!empty($data->reset_data_ratings)) {
9c00b5d7 2290 $DB->delete_records_select('data_ratings', "recordid IN ($allrecordssql)", array($data->courseid));
0b5a80a1 2291
2292 if (empty($data->reset_gradebook_grades)) {
2293 // remove all grades from gradebook
2294 data_reset_gradebook($data->courseid);
2295 }
b572ce19 2296
0b5a80a1 2297 $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallratings'), 'error'=>false);
2298 }
2299
2300 // remove all comments
2301 if (!empty($data->reset_data_comments)) {
9c00b5d7 2302 $DB->delete_records_select('data_comments', "recordid IN ($allrecordssql)", array($data->courseid));
0b5a80a1 2303 $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallcomments'), 'error'=>false);
2304 }
2305
b8b554ac 2306 // updating dates - shift may be negative too
0b5a80a1 2307 if ($data->timeshift) {
2308 shift_course_mod_dates('data', array('timeavailablefrom', 'timeavailableto', 'timeviewfrom', 'timeviewto'), $data->timeshift, $data->courseid);
2309 $status[] = array('component'=>$componentstr, 'item'=>get_string('datechanged'), 'error'=>false);
2310 }
b572ce19 2311
0b5a80a1 2312 return $status;
2313}
f432bebf 2314
2315/**
2316 * Returns all other caps used in module
2317 */
2318function data_get_extra_capabilities() {
2319 return array('moodle/site:accessallgroups', 'moodle/site:viewfullnames');
2320}
2321
18a2a0cb 2322/**
2323 * @param string $feature FEATURE_xx constant for requested feature
2324 * @return mixed True if module supports feature, null if doesn't know
2325 */
2326function data_supports($feature) {
2327 switch($feature) {
42f103be 2328 case FEATURE_GROUPS: return true;
2329 case FEATURE_GROUPINGS: return true;
2330 case FEATURE_GROUPMEMBERSONLY: return true;
2331 case FEATURE_MODEDIT_INTRO_EDITOR: return true;
18a2a0cb 2332 case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
42f103be 2333 case FEATURE_GRADE_HAS_GRADE: return true;
2334 case FEATURE_GRADE_OUTCOMES: return true;
2335
18a2a0cb 2336 default: return null;
42f103be 2337 }
18a2a0cb 2338}
1bf8c6b2 2339function data_export_csv($export, $delimiter_name, $dataname, $count, $return=false) {
ecd06483 2340 global $CFG;
2341 require_once($CFG->libdir . '/csvlib.class.php');
20988152 2342 $delimiter = csv_import_reader::get_delimiter($delimiter_name);
2343 $filename = clean_filename("${dataname}-${count}_record");
2344 if ($count > 1) {
2345 $filename .= 's';
2346 }
2347 $filename .= clean_filename('-' . gmdate("Ymd_Hi"));
2348 $filename .= clean_filename("-${delimiter_name}_separated");
2349 $filename .= '.csv';
1bf8c6b2 2350 if (empty($return)) {
ecd06483 2351 header("Content-Type: application/download\n");
2352 header("Content-Disposition: attachment; filename=$filename");
2353 header('Expires: 0');
2354 header('Cache-Control: must-revalidate,post-check=0,pre-check=0');
2355 header('Pragma: public');
2356 }
20988152 2357 $encdelim = '&#' . ord($delimiter) . ';';
ecd06483 2358 $returnstr = '';
20988152 2359 foreach($export as $row) {
2360 foreach($row as $key => $column) {
2361 $row[$key] = str_replace($delimiter, $encdelim, $column);
2362 }
ecd06483 2363 $returnstr .= implode($delimiter, $row) . "\n";
2364 }
1bf8c6b2 2365 if (empty($return)) {
ecd06483 2366 echo $returnstr;
2367 return;
20988152 2368 }
1bf8c6b2 2369 return $returnstr;
20988152 2370}
2371
2372
1bf8c6b2 2373function data_export_xls($export, $dataname, $count) {
20988152 2374 global $CFG;
2375 require_once("$CFG->libdir/excellib.class.php");
2376 $filename = clean_filename("${dataname}-${count}_record");
2377 if ($count > 1) {
2378 $filename .= 's';
2379 }
2380 $filename .= clean_filename('-' . gmdate("Ymd_Hi"));
2381 $filename .= '.xls';
ecd06483 2382
2383 $filearg = '-';
ecd06483 2384 $workbook = new MoodleExcelWorkbook($filearg);
1bf8c6b2 2385 $workbook->send($filename);
20988152 2386 $worksheet = array();
2387 $worksheet[0] =& $workbook->add_worksheet('');
2388 $rowno = 0;
2389 foreach ($export as $row) {
2390 $colno = 0;
2391 foreach($row as $col) {
2392 $worksheet[0]->write($rowno, $colno, $col);
2393 $colno++;
2394 }
2395 $rowno++;
2396 }
2397 $workbook->close();
ecd06483 2398 return $filename;
20988152 2399}
2400
2401
1bf8c6b2 2402function data_export_ods($export, $dataname, $count) {
20988152 2403 global $CFG;
2404 require_once("$CFG->libdir/odslib.class.php");
2405 $filename = clean_filename("${dataname}-${count}_record");
2406 if ($count > 1) {
2407 $filename .= 's';
2408 }
2409 $filename .= clean_filename('-' . gmdate("Ymd_Hi"));
2410 $filename .= '.ods';
ecd06483 2411 $filearg = '-';
1bf8c6b2 2412 $workbook = new MoodleODSWorkbook($filearg);
2413 $workbook->send($filename);
20988152 2414 $worksheet = array();
2415 $worksheet[0] =& $workbook->add_worksheet('');
2416 $rowno = 0;
2417 foreach ($export as $row) {
2418 $colno = 0;
2419 foreach($row as $col) {
2420 $worksheet[0]->write($rowno, $colno, $col);
2421 $colno++;
2422 }
2423 $rowno++;
2424 }
2425 $workbook->close();
ecd06483 2426 return $filename;
2427}
2428
2429function data_get_exportdata($dataid, $fields, $selectedfields) {
2430 global $DB;
2431
2432 $exportdata = array();
2433
2434 // populate the header in first row of export
2435 foreach($fields as $key => $field) {
2436 if (!in_array($field->field->id, $selectedfields)) {
2437 // ignore values we aren't exporting
2438 unset($fields[$key]);
2439 } else {
2440 $exportdata[0][] = $field->field->name;
2441 }
2442 }
2443
2444 $datarecords = $DB->get_records('data_records', array('dataid'=>$dataid));
2445 ksort($datarecords);
2446 $line = 1;
2447 foreach($datarecords as $record) {
2448 // get content indexed by fieldid
2449 if( $content = $DB->get_records('data_content', array('recordid'=>$record->id), 'fieldid', 'fieldid, content, content1, content2, content3, content4') ) {
2450 foreach($fields as $field) {
2451 $contents = '';
2452 if(isset($content[$field->field->id])) {
2453 $contents = $field->export_text_value($content[$field->field->id]);
2454 }
2455 $exportdata[$line][] = $contents;
2456 }
2457 }
2458 $line++;
2459 }
2460 $line--;
2461 return $exportdata;
2462}
2463
8429163d 2464/**
2465 * Lists all browsable file areas
2466 */
2467function data_get_file_areas($course, $cm, $context) {
2468 $areas = array();
2469 if (has_capability('moodle/course:managefiles', $context)) {
2470 $areas['data_intro'] = get_string('areaintro', 'data');
2471 }
2472 return $areas;
2473}
2474
2475/**
2476 * Serves the data attachments. Implements needed access control ;-)
2477 */
2478function data_pluginfile($course, $cminfo, $context, $filearea, $args) {
2479 global $CFG, $DB;
2480
2481 if (!$cminfo->uservisible) {
2482 return false;
2483 }
2484
2485 if ($filearea === 'data_intro') {
2486 // all users may access it
2487 $relativepath = '/'.implode('/', $args);
2488 $fullpath = $context->id.'data_intro0'.$relativepath;
2489
2490 $fs = get_file_storage();
2491 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
2492 return false;
2493 }
2494
2495 $lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400;
2496
2497 // finally send the file
2498 send_stored_file($file, $lifetime, 0);
2499
2500 } else if ($filearea === 'data_content') {
2501 $contentid = (int)array_shift($args);
2502
2503 if (!$content = $DB->get_record('data_content', array('id'=>$contentid))) {
2504 return false;
2505 }
2506
2507 if (!$field = $DB->get_record('data_fields', array('id'=>$content->fieldid))) {
2508 return false;
2509 }
2510
2511 if (!$record = $DB->get_record('data_records', array('id'=>$content->recordid))) {
2512 return false;
2513 }
2514
2515 if (!$data = $DB->get_record('data', array('id'=>$field->dataid))) {
2516 return false;
2517 }
2518
2519 //check if approved
2520 if (!$record->approved and !data_isowner($record) and !has_capability('mod/data:approve', $context)) {
2521 return false;
2522 }
2523
2524 // group access
2525 if ($record->groupid) {
2526 $groupmode = groups_get_activity_groupmode($cminfo, $course);
2527 if ($groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) {
2528 if (!groups_is_member($record->groupid)) {
2529 return false;
2530 }
2531 }
2532 }
2533
2534 $fieldobj = data_get_field($field, $data, $cminfo);
2535
2536 $relativepath = '/'.implode('/', $args);
2537 $fullpath = $context->id.'data_content'.$content->id.$relativepath;
2538
2539 if (!$fieldobj->file_ok($relativepath)) {
2540 return false;
2541 }
2542
2543 $fs = get_file_storage();
2544 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
2545 return false;
2546 }
2547
2548 // finally send the file
2549 send_stored_file($file, 0, 0, true); // download MUST be forced - security!
2550 }
2551
2552 return false;
2553}
2554
ecd06483 2555class data_portfolio_caller extends portfolio_module_caller_base {
2556
0d06b6fd 2557 protected $recordid;
2558 protected $exporttype;
2559 protected $delimiter_name;
2560
ecd06483 2561 private $data;
2562 private $selectedfields;
ecd06483 2563 private $fields;
2564 private $fieldtypes;
84a44985 2565 private $exportdata;
8185aeb6 2566 private $singlerecord;
276378e6 2567 private $singlefield;
ecd06483 2568
0d06b6fd 2569 public static function expected_callbackargs() {
2570 return array(
2571 'id' => true,
2572 'recordid' => false,
2573 'delimiter_name' => false,
2574 'exporttype' => false,
2575 );
2576 }
2577
ecd06483 2578 public function __construct($callbackargs) {
0d06b6fd 2579 parent::__construct($callbackargs);
2580 if (empty($this->exporttype)) {
2581 $this->exporttype = 'csv';
2582 }
2583 $this->selectedfields = array();
2584 foreach ($callbackargs as $key => $value) {
2585 if (strpos($key, 'field_') === 0) {
2586 $this->selectedfields[] = substr($key, 6);
2587 }
2588 }
2589 }
2590
2591 public function load_data() {
ecd06483 2592 global $DB;
0d06b6fd 2593 if (!$this->cm = get_coursemodule_from_id('data', $this->id)) {
34035201 2594 throw new portfolio_caller_exception('invalidid', 'data');
ecd06483 2595 }
2596 $this->data = $DB->get_record('data', array('id' => $this->cm->instance));
ecd06483 2597 $fieldrecords = $DB->get_records('data_fields', array('dataid'=>$this->cm->instance), 'id');
2598 // populate objets for this databases fields
2599 $this->fields = array();
2600 foreach ($fieldrecords as $fieldrecord) {
2601 $tmp = data_get_field($fieldrecord, $this->data);
2602 $this->fields[] = $tmp;
2603 $this->fieldtypes[] = $tmp->type;
2604 }
8185aeb6 2605
0d06b6fd 2606 if ($this->recordid) {
8185aeb6 2607 //user has selected to export one single entry rather than the whole thing
2608 // which is completely different
0d06b6fd 2609 $this->singlerecord = $DB->get_record('data_records', array('id' => $this->recordid));
8185aeb6 2610 $this->singlerecord->content = $DB->get_records('data_content', array('recordid' => $this->singlerecord->id));
2611 $this->exporttype = 'single';
6be1dcae 2612
2613 list($formats, $files) = self::formats($this->fields, $this->singlerecord);
276378e6 2614 $this->supportedformats = $formats;
6be1dcae 2615 if (count($files) == 1 && count($this->fields) == 1) {
2616 $this->singlefile = $files[0];
2617 $this->exporttype = 'singlefile';
2618 } else if (count($files) > 0) {
2619 $this->multifiles = $files;
2620 }
8185aeb6 2621 } else {
2622 // all records as csv or whatever
8185aeb6 2623 $this->exportdata = data_get_exportdata($this->cm->instance, $this->fields, $this->selectedfields);
2624 }
2625 }
2626
2627 public function has_export_config() {
313f21ce 2628 // @todo penny later when we suport exporting to more than just csv, we may need to ask the user here
8185aeb6 2629 // if we have not already passed it
2630 return false;
ecd06483 2631 }
2632
2633 public function expected_time() {
8185aeb6 2634 if ($this->exporttype == 'single') {
2635 return PORTFOLIO_TIME_LOW;
2636 }
d8606b20 2637 return portfolio_expected_time_db(count($this->exportdata));
ecd06483 2638 }
2639
2640 public function get_sha1() {
276378e6 2641 if ($this->exporttype == 'singlefile') {
2642 return $this->singlefile->get_contenthash();
2643 }
8185aeb6 2644 $loopdata = $this->exportdata;
2645 if ($this->exporttype == 'single') {
2646 $loopdata = $this->singlerecord;
2647 }
ecd06483 2648 $str = '';
8185aeb6 2649 foreach ($loopdata as $data) {
2650 if (is_array($data) || is_object($data)) {
2651 $testkey = array_pop(array_keys($data));
2652 if (is_array($data[$testkey]) || is_object($data[$testkey])) {
2653 foreach ($data as $d) {
2654 $str .= implode(',', (array)$d);
2655 }
2656 } else {
2657 $str .= implode(',', (array)$data);
2658 }
2659 } else {
2660 $str .= $data;
2661 }
ecd06483 2662 }
2663 return sha1($str . ',' . $this->exporttype);
2664 }
2665
d67bfc32 2666 public function prepare_package() {
ecd06483 2667 global $DB;
84a44985 2668 $count = count($this->exportdata);
1bf8c6b2 2669 $content = '';
2670 $filename = '';
ecd06483 2671 switch ($this->exporttype) {
276378e6 2672 case 'singlefile':
2673 return $this->get('exporter')->copy_existing_file($this->singlefile);
8185aeb6 2674 case 'single':
2675 $content = $this->exportsingle();
2676 $filename = clean_filename($this->cm->name . '-entry.html');
2677 break;
ecd06483 2678 case 'csv':
0d06b6fd 2679 $content = data_export_csv($this->exportdata, $this->delimiter_name, $this->cm->name, $count, true);
1bf8c6b2 2680 $filename = clean_filename($this->cm->name . '.csv');
ecd06483 2681 break;
2682 case 'xls':
34035201 2683 throw new portfolio_caller_exception('notimplemented', 'portfolio', '', 'xls');
1bf8c6b2 2684 $content = data_export_xls($this->exportdata, $this->cm->name, $count, true);
ecd06483 2685 break;
2686 case 'ods':
34035201 2687 throw new portfolio_caller_exception('notimplemented', 'portfolio', '', 'ods');
1bf8c6b2 2688 $content = data_export_ods($this->exportdata, $this->cm->name, $count, true);
ecd06483 2689 break;
8185aeb6 2690 default:
34035201 2691 throw new portfolio_caller_exception('notimplemented', 'portfolio', '', $this->exporttype);
8185aeb6 2692 break;
ecd06483 2693 }
6be1dcae 2694 return $this->exporter->write_new_file(
2695 $content,
2696 $filename,
2697 ($this->exporter->get('format') instanceof PORTFOLIO_FORMAT_RICH) // if we have associate files, this is a 'manifest'
2698 );
ecd06483 2699 }
2700
2701 public function check_permissions() {
07028cd9 2702 return has_capability('mod/data:exportallentries', get_context_instance(CONTEXT_MODULE, $this->cm->id));
ecd06483 2703 }
2704
2705 public static function display_name() {
2706 return get_string('modulename', 'data');
2707 }
2708
2709 public function __wakeup() {
2710 global $CFG;
2711 if (empty($CFG)) {
2712 return true; // too early yet
2713 }
2714 foreach ($this->fieldtypes as $key => $field) {
2715 require_once($CFG->dirroot . '/mod/data/field/' . $field .'/field.class.php');
2716 $this->fields[$key] = unserialize(serialize($this->fields[$key]));
2717 }
2718 }
8185aeb6 2719
2720 private function exportsingle() {
276378e6 2721 global $DB;
8185aeb6 2722 // Replacing tags
2723 $patterns = array();
2724 $replacement = array();
276378e6 2725 $context = get_context_instance(CONTEXT_MODULE, $this->cm->id);
8185aeb6 2726
2727 // Then we generate strings to replace for normal tags
6be1dcae 2728 $format = $this->get('exporter')->get('format');
8185aeb6 2729 foreach ($this->fields as $field) {
2730 $patterns[]='[['.$field->field->name.']]';
6be1dcae 2731 if (is_callable(array($field, 'get_file'))) {
2732 // TODO this used to be:
2733 // if ($field instanceof data_field_file) {
2734 // - see MDL-16493
276378e6 2735 if (!$file = $field->get_file($this->singlerecord->id)) {
6be1dcae 2736 $replacement[] = '';
276378e6 2737 continue; // probably left empty
2738 }
6be1dcae 2739 $replacement[] = $format->file_output($file);
276378e6 2740 $this->get('exporter')->copy_existing_file($file);
8185aeb6 2741 } else {
2742 $replacement[] = $field->display_browse_field($this->singlerecord->id, 'singletemplate');
2743 }
2744 }
2745
2746 // Replacing special tags (##Edit##, ##Delete##, ##More##)
2747 $patterns[]='##edit##';
2748 $patterns[]='##delete##';
2749 $patterns[]='##export##';
2750 $patterns[]='##more##';
2751 $patterns[]='##moreurl##';
2752 $patterns[]='##user##';
2753 $patterns[]='##approve##';
2754 $patterns[]='##comments##';
2755 $patterns[] = '##timeadded##';
2756 $patterns[] = '##timemodified##';
2757 $replacement[] = '';
2758 $replacement[] = '';
2759 $replacement[] = '';
2760 $replacement[] = '';
2761 $replacement[] = '';
2762 $replacement[] = '';
2763 $replacement[] = '';
2764 $replacement[] = '';
2765 $replacement[] = userdate($this->singlerecord->timecreated);
2766 $replacement[] = userdate($this->singlerecord->timemodified);
2767
2768 // actual replacement of the tags
2769 return str_ireplace($patterns, $replacement, $this->data->singletemplate);
2770 }
6be1dcae 2771
2772 public static function formats($fields, $record) {
2773 $formats = array(PORTFOLIO_FORMAT_PLAINHTML);
2774 $includedfiles = array();
2775 foreach ($fields as $singlefield) {
2776 if (is_callable(array($singlefield, 'get_file'))) {
2777 $includedfiles[] = $singlefield->get_file($record->id);
2778 }
2779 }
2780 if (count($includedfiles) == 1 && count($fields) == 1) {
2781 $formats= array(portfolio_format_from_file($includedfiles[0]));
2782 } else if (count($includedfiles) > 0) {
62e71954 2783 $formats = array(PORTFOLIO_FORMAT_FILE, PORTFOLIO_FORMAT_RICHHTML);
6be1dcae 2784 }
2785 return array($formats, $includedfiles);
2786 }
20988152 2787}
8303eb84 2788?>