Fix a possible race condition in the PaintWeb DML code.
[moodle/mihaisucan.git] / mod / data / lib.php
blob47ed7b7fd98ea350ace61aacb98176b29b7d85cf
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 ///////////////////////////////////////////////////////////////////////////
25 // Some constants
26 define ('DATA_MAX_ENTRIES', 50);
27 define ('DATA_PERPAGE_SINGLE', 1);
28 define ('DATA_FIRSTNAME', -1);
29 define ('DATA_LASTNAME', -2);
30 define ('DATA_APPROVED', -3);
31 define ('DATA_TIMEADDED', 0);
32 define ('DATA_TIMEMODIFIED', -4);
34 define ('DATA_CAP_EXPORT', 'mod/data:viewalluserpresets');
35 // Users having assigned the default role "Non-editing teacher" can export database records
36 // Using the mod/data capability "viewalluserpresets" for Moodle 1.9.x, so no change in the role system is required.
37 // In Moodle >= 2, new roles may be introduced and used instead.
39 class data_field_base { // Base class for Database Field Types (see field/*/field.class.php)
41 var $type = 'unknown'; // Subclasses must override the type with their name
42 var $data = NULL; // The database object that this field belongs to
43 var $field = NULL; // The field object itself, if we know it
45 var $iconwidth = 16; // Width of the icon for this fieldtype
46 var $iconheight = 16; // Width of the icon for this fieldtype
49 // Constructor function
50 function data_field_base($field=0, $data=0) { // Field or data or both, each can be id or object
51 if (empty($field) && empty($data)) {
52 error('Programmer error: You must specify field and/or data when defining field class. ');
54 if (!empty($field)) {
55 if (is_object($field)) {
56 $this->field = $field; // Programmer knows what they are doing, we hope
57 } else if (!$this->field = get_record('data_fields','id',$field)) {
58 error('Bad field ID encountered: '.$field);
60 if (empty($data)) {
61 if (!$this->data = get_record('data','id',$this->field->dataid)) {
62 error('Bad data ID encountered in field data');
66 if (empty($this->data)) { // We need to define this properly
67 if (!empty($data)) {
68 if (is_object($data)) {
69 $this->data = $data; // Programmer knows what they are doing, we hope
70 } else if (!$this->data = get_record('data','id',$data)) {
71 error('Bad data ID encountered: '.$data);
73 } else { // No way to define it!
74 error('Data id or object must be provided to field class');
77 if (empty($this->field)) { // We need to define some default values
78 $this->define_default_field();
83 // This field just sets up a default field object
84 function define_default_field() {
85 if (empty($this->data->id)) {
86 notify('Programmer error: dataid not defined in field class');
88 $this->field = new object;
89 $this->field->id = 0;
90 $this->field->dataid = $this->data->id;
91 $this->field->type = $this->type;
92 $this->field->param1 = '';
93 $this->field->param2 = '';
94 $this->field->param3 = '';
95 $this->field->name = '';
96 $this->field->description = '';
97 return true;
100 // Set up the field object according to data in an object. Now is the time to clean it!
101 function define_field($data) {
102 $this->field->type = $this->type;
103 $this->field->dataid = $this->data->id;
105 $this->field->name = trim($data->name);
106 $this->field->description = trim($data->description);
108 if (isset($data->param1)) {
109 $this->field->param1 = trim($data->param1);
111 if (isset($data->param2)) {
112 $this->field->param2 = trim($data->param2);
114 if (isset($data->param3)) {
115 $this->field->param3 = trim($data->param3);
117 if (isset($data->param4)) {
118 $this->field->param4 = trim($data->param4);
120 if (isset($data->param5)) {
121 $this->field->param5 = trim($data->param5);
124 return true;
127 // Insert a new field in the database
128 // We assume the field object is already defined as $this->field
129 function insert_field() {
130 if (empty($this->field)) {
131 notify('Programmer error: Field has not been defined yet! See define_field()');
132 return false;
135 if (!$this->field->id = insert_record('data_fields',$this->field)){
136 notify('Insertion of new field failed!');
137 return false;
139 return true;
143 // Update a field in the database
144 function update_field() {
145 if (!update_record('data_fields', $this->field)) {
146 notify('updating of new field failed!');
147 return false;
149 return true;
152 // Delete a field completely
153 function delete_field() {
154 if (!empty($this->field->id)) {
155 delete_records('data_fields', 'id', $this->field->id);
156 $this->delete_content();
158 return true;
161 // Print the relevant form element in the ADD template for this field
162 function display_add_field($recordid=0){
163 if ($recordid){
164 $content = get_field('data_content', 'content', 'fieldid', $this->field->id, 'recordid', $recordid);
165 } else {
166 $content = '';
169 // beware get_field returns false for new, empty records MDL-18567
170 if ($content===false) {
171 $content='';
174 $str = '<div title="'.s($this->field->description).'">';
175 $str .= '<input style="width:300px;" type="text" name="field_'.$this->field->id.'" id="field_'.$this->field->id.'" value="'.s($content).'" />';
176 $str .= '</div>';
178 return $str;
181 // Print the relevant form element to define the attributes for this field
182 // viewable by teachers only.
183 function display_edit_field() {
184 global $CFG;
186 if (empty($this->field)) { // No field has been defined yet, try and make one
187 $this->define_default_field();
189 print_simple_box_start('center','80%');
191 echo '<form id="editfield" action="'.$CFG->wwwroot.'/mod/data/field.php" method="post">'."\n";
192 echo '<input type="hidden" name="d" value="'.$this->data->id.'" />'."\n";
193 if (empty($this->field->id)) {
194 echo '<input type="hidden" name="mode" value="add" />'."\n";
195 $savebutton = get_string('add');
196 } else {
197 echo '<input type="hidden" name="fid" value="'.$this->field->id.'" />'."\n";
198 echo '<input type="hidden" name="mode" value="update" />'."\n";
199 $savebutton = get_string('savechanges');
201 echo '<input type="hidden" name="type" value="'.$this->type.'" />'."\n";
202 echo '<input name="sesskey" value="'.sesskey().'" type="hidden" />'."\n";
204 print_heading($this->name());
206 require_once($CFG->dirroot.'/mod/data/field/'.$this->type.'/mod.html');
208 echo '<div class="mdl-align">';
209 echo '<input type="submit" value="'.$savebutton.'" />'."\n";
210 echo '<input type="submit" name="cancel" value="'.get_string('cancel').'" />'."\n";
211 echo '</div>';
213 echo '</form>';
215 print_simple_box_end();
218 // Display the content of the field in browse mode
219 function display_browse_field($recordid, $template) {
220 if ($content = get_record('data_content','fieldid', $this->field->id, 'recordid', $recordid)) {
221 if (isset($content->content)) {
222 $options = new object();
223 if ($this->field->param1 == '1') { // We are autolinking this field, so disable linking within us
224 //$content->content = '<span class="nolink">'.$content->content.'</span>';
225 //$content->content1 = FORMAT_HTML;
226 $options->filter=false;
228 $options->para = false;
229 $str = format_text($content->content, $content->content1, $options);
230 } else {
231 $str = '';
233 return $str;
235 return false;
238 // Update the content of one data field in the data_content table
239 function update_content($recordid, $value, $name='') {
240 $content = new object();
241 $content->fieldid = $this->field->id;
242 $content->recordid = $recordid;
243 $content->content = clean_param($value, PARAM_NOTAGS);
245 if ($oldcontent = get_record('data_content','fieldid', $this->field->id, 'recordid', $recordid)) {
246 $content->id = $oldcontent->id;
247 return update_record('data_content', $content);
248 } else {
249 return insert_record('data_content', $content);
253 // Delete all content associated with the field
254 function delete_content($recordid=0) {
256 $this->delete_content_files($recordid);
258 if ($recordid) {
259 return delete_records('data_content', 'fieldid', $this->field->id, 'recordid', $recordid);
260 } else {
261 return delete_records('data_content', 'fieldid', $this->field->id);
265 // Deletes any files associated with this field
266 function delete_content_files($recordid='') {
267 global $CFG;
269 require_once($CFG->libdir.'/filelib.php');
271 $dir = $CFG->dataroot.'/'.$this->data->course.'/'.$CFG->moddata.'/data/'.$this->data->id.'/'.$this->field->id;
272 if ($recordid) {
273 $dir .= '/'.$recordid;
276 return fulldelete($dir);
280 // Check if a field from an add form is empty
281 function notemptyfield($value, $name) {
282 return !empty($value);
285 // Just in case a field needs to print something before the whole form
286 function print_before_form() {
289 // Just in case a field needs to print something after the whole form
290 function print_after_form() {
294 // Returns the sortable field for the content. By default, it's just content
295 // but for some plugins, it could be content 1 - content4
296 function get_sort_field() {
297 return 'content';
300 // Returns the SQL needed to refer to the column. Some fields may need to CAST() etc.
301 function get_sort_sql($fieldname) {
302 return $fieldname;
305 // Returns the name/type of the field
306 function name() {
307 return get_string('name'.$this->type, 'data');
310 // Prints the respective type icon
311 function image() {
312 global $CFG;
314 $str = '<a href="field.php?d='.$this->data->id.'&amp;fid='.$this->field->id.'&amp;mode=display&amp;sesskey='.sesskey().'">';
315 $str .= '<img src="'.$CFG->modpixpath.'/data/field/'.$this->type.'/icon.gif" ';
316 $str .= 'height="'.$this->iconheight.'" width="'.$this->iconwidth.'" alt="'.$this->type.'" title="'.$this->type.'" /></a>';
317 return $str;
320 // Per default, it is assumed that fields support text exporting. Override this (return false) on fields not supporting text exporting.
321 function text_export_supported() {
322 return true;
325 // Per default, return the record's text value only from the "content" field. Override this in fields class if necesarry.
326 function export_text_value($record) {
327 if ($this->text_export_supported()) {
328 return $record->content;
336 /* Given a template and a dataid, generate a default case template
337 * input @param template - addtemplate, singletemplate, listtempalte, rsstemplate
338 * @param dataid
339 * output null
341 function data_generate_default_template(&$data, $template, $recordid=0, $form=false, $update=true) {
343 if (!$data && !$template) {
344 return false;
346 if ($template == 'csstemplate' or $template == 'jstemplate' ) {
347 return '';
350 // get all the fields for that database
351 if ($fields = get_records('data_fields', 'dataid', $data->id, 'id')) {
353 $str = '<div class="defaulttemplate">';
354 $str .= '<table cellpadding="5">';
356 foreach ($fields as $field) {
358 $str .= '<tr><td valign="top" align="right">';
359 // Yu: commenting this out, the id was wrong and will fix later
360 //if ($template == 'addtemplate') {
361 //$str .= '<label';
362 //if (!in_array($field->type, array('picture', 'checkbox', 'date', 'latlong', 'radiobutton'))) {
363 // $str .= ' for="[['.$field->name.'#id]]"';
365 //$str .= '>'.$field->name.'</label>';
367 //} else {
368 $str .= $field->name.': ';
370 $str .= '</td>';
372 $str .='<td>';
373 if ($form) { // Print forms instead of data
374 $fieldobj = data_get_field($field, $data);
375 $str .= $fieldobj->display_add_field($recordid);
377 } else { // Just print the tag
378 $str .= '[['.$field->name.']]';
380 $str .= '</td></tr>';
383 if ($template == 'listtemplate') {
384 $str .= '<tr><td align="center" colspan="2">##edit## ##more## ##delete## ##approve##</td></tr>';
385 } else if ($template == 'singletemplate') {
386 $str .= '<tr><td align="center" colspan="2">##edit## ##delete## ##approve##</td></tr>';
387 } else if ($template == 'asearchtemplate') {
388 $str .= '<tr><td valign="top" align="right">'.get_string('authorfirstname', 'data').': </td><td>##firstname##</td></tr>';
389 $str .= '<tr><td valign="top" align="right">'.get_string('authorlastname', 'data').': </td><td>##lastname##</td></tr>';
392 $str .= '</table>';
393 $str .= '</div>';
395 if ($template == 'listtemplate'){
396 $str .= '<hr />';
399 if ($update) {
400 $newdata = new object();
401 $newdata->id = $data->id;
402 $newdata->{$template} = addslashes($str);
403 if (!update_record('data', $newdata)) {
404 notify('Error updating template');
405 } else {
406 $data->{$template} = $str;
410 return $str;
415 /***********************************************************************
416 * Search for a field name and replaces it with another one in all the *
417 * form templates. Set $newfieldname as '' if you want to delete the *
418 * field from the form. *
419 ***********************************************************************/
420 function data_replace_field_in_templates($data, $searchfieldname, $newfieldname) {
421 if (!empty($newfieldname)) {
422 $prestring = '[[';
423 $poststring = ']]';
424 $idpart = '#id';
426 } else {
427 $prestring = '';
428 $poststring = '';
429 $idpart = '';
432 $newdata = new object();
433 $newdata->id = $data->id;
434 $newdata->singletemplate = addslashes(str_ireplace('[['.$searchfieldname.']]',
435 $prestring.$newfieldname.$poststring, $data->singletemplate));
437 $newdata->listtemplate = addslashes(str_ireplace('[['.$searchfieldname.']]',
438 $prestring.$newfieldname.$poststring, $data->listtemplate));
440 $newdata->addtemplate = addslashes(str_ireplace('[['.$searchfieldname.']]',
441 $prestring.$newfieldname.$poststring, $data->addtemplate));
443 $newdata->addtemplate = addslashes(str_ireplace('[['.$searchfieldname.'#id]]',
444 $prestring.$newfieldname.$idpart.$poststring, $data->addtemplate));
446 $newdata->rsstemplate = addslashes(str_ireplace('[['.$searchfieldname.']]',
447 $prestring.$newfieldname.$poststring, $data->rsstemplate));
449 return update_record('data', $newdata);
453 /********************************************************
454 * Appends a new field at the end of the form template. *
455 ********************************************************/
456 function data_append_new_field_to_templates($data, $newfieldname) {
458 $newdata = new object();
459 $newdata->id = $data->id;
460 $change = false;
462 if (!empty($data->singletemplate)) {
463 $newdata->singletemplate = addslashes($data->singletemplate.' [[' . $newfieldname .']]');
464 $change = true;
466 if (!empty($data->addtemplate)) {
467 $newdata->addtemplate = addslashes($data->addtemplate.' [[' . $newfieldname . ']]');
468 $change = true;
470 if (!empty($data->rsstemplate)) {
471 $newdata->rsstemplate = addslashes($data->singletemplate.' [[' . $newfieldname . ']]');
472 $change = true;
474 if ($change) {
475 update_record('data', $newdata);
480 /************************************************************************
481 * given a field name *
482 * this function creates an instance of the particular subfield class *
483 ************************************************************************/
484 function data_get_field_from_name($name, $data){
485 $field = get_record('data_fields', 'name', $name, 'dataid', $data->id);
486 if ($field) {
487 return data_get_field($field, $data);
488 } else {
489 return false;
493 /************************************************************************
494 * given a field id *
495 * this function creates an instance of the particular subfield class *
496 ************************************************************************/
497 function data_get_field_from_id($fieldid, $data) {
498 $field = get_record('data_fields', 'id', $fieldid, 'dataid', $data->id);
499 if ($field) {
500 return data_get_field($field, $data);
501 } else {
502 return false;
506 /************************************************************************
507 * given a field id *
508 * this function creates an instance of the particular subfield class *
509 ************************************************************************/
510 function data_get_field_new($type, $data) {
511 global $CFG;
512 require_once($CFG->dirroot.'/mod/data/field/'.$type.'/field.class.php');
513 $newfield = 'data_field_'.$type;
514 $newfield = new $newfield(0, $data);
515 return $newfield;
518 /************************************************************************
519 * returns a subclass field object given a record of the field, used to *
520 * invoke plugin methods *
521 * input: $param $field - record from db *
522 ************************************************************************/
523 function data_get_field($field, $data) {
524 global $CFG;
525 if ($field) {
526 require_once('field/'.$field->type.'/field.class.php');
527 $newfield = 'data_field_'.$field->type;
528 $newfield = new $newfield($field, $data);
529 return $newfield;
534 /***************************************************************************
535 * given record id, returns true if the record belongs to the current user *
536 * input @param $rid - record id *
537 * output bool *
538 ***************************************************************************/
539 function data_isowner($rid){
540 global $USER;
541 if (empty($USER->id)) {
542 return false;
545 if ($record = get_record('data_records','id',$rid)) {
546 return ($record->userid == $USER->id);
549 return false;
552 /***********************************************************************
553 * has a user reached the max number of entries? *
554 * input object $data *
555 * output bool *
556 ***********************************************************************/
557 function data_atmaxentries($data) {
558 if (!$data->maxentries) {
559 return false;
560 } else {
561 return (data_numentries($data) >= $data->maxentries);
565 /**********************************************************************
566 * returns the number of entries already made by this user *
567 * input @param object $data *
568 * uses global $CFG, $USER *
569 * output int *
570 **********************************************************************/
571 function data_numentries($data) {
572 global $USER;
573 global $CFG;
574 $sql = 'SELECT COUNT(*) FROM '.$CFG->prefix.'data_records WHERE dataid='.$data->id.' AND userid='.$USER->id;
575 return count_records_sql($sql);
578 /****************************************************************
579 * function that takes in a dataid and adds a record *
580 * this is used everytime an add template is submitted *
581 * input @param int $dataid, $groupid *
582 * output bool *
583 ****************************************************************/
584 function data_add_record($data, $groupid=0) {
585 global $USER;
586 $cm = get_coursemodule_from_instance('data', $data->id);
587 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
588 $record = new object();
589 $record->userid = $USER->id;
590 $record->dataid = $data->id;
591 $record->groupid = $groupid;
592 $record->timecreated = $record->timemodified = time();
593 if (has_capability('mod/data:approve', $context)) {
594 $record->approved = 1;
595 } else {
596 $record->approved = 0;
598 return insert_record('data_records',$record);
601 /*******************************************************************
602 * check the multple existence any tag in a template *
603 * input @param string *
604 * output true-valid, false-invalid *
605 * check to see if there are 2 or more of the same tag being used. *
606 * input @param int $dataid, *
607 * @param string $template *
608 * output bool *
609 *******************************************************************/
610 function data_tags_check($dataid, $template) {
611 // first get all the possible tags
612 $fields = get_records('data_fields','dataid',$dataid);
613 // then we generate strings to replace
614 $tagsok = true; // let's be optimistic
615 foreach ($fields as $field) {
616 $pattern="/\[\[".$field->name."\]\]/i";
617 if (preg_match_all($pattern, $template, $dummy)>1) {
618 $tagsok = false;
619 notify ('[['.$field->name.']] - '.get_string('multipletags','data'));
622 // else return true
623 return $tagsok;
626 /************************************************************************
627 * Adds an instance of a data *
628 ************************************************************************/
629 function data_add_instance($data) {
630 global $CFG;
631 if (empty($data->assessed)) {
632 $data->assessed = 0;
635 $data->timemodified = time();
636 if (! $data->id = insert_record('data', $data)) {
637 return false;
640 $data = stripslashes_recursive($data);
641 data_grade_item_update($data);
642 return $data->id;
645 /************************************************************************
646 * updates an instance of a data *
647 ************************************************************************/
648 function data_update_instance($data) {
649 global $CFG;
650 $data->timemodified = time();
651 $data->id = $data->instance;
653 if (empty($data->assessed)) {
654 $data->assessed = 0;
656 if (empty($data->notification)) {
657 $data->notification = 0;
659 if (! update_record('data', $data)) {
660 return false;
663 $data = stripslashes_recursive($data);
664 data_grade_item_update($data);
665 return true;
668 /************************************************************************
669 * deletes an instance of a data *
670 ************************************************************************/
671 function data_delete_instance($id) { // takes the dataid
673 global $CFG;
674 if (! $data = get_record('data', 'id', $id)) {
675 return false;
678 // Delete all the associated information
679 // get all the records in this data
680 $sql = 'SELECT c.* FROM '.$CFG->prefix.'data_records r LEFT JOIN '.
681 $CFG->prefix.'data_content c ON c.recordid = r.id WHERE r.dataid = '.$id;
683 if ($contents = get_records_sql($sql)) {
684 foreach($contents as $content) {
685 $field = get_record('data_fields','id',$content->fieldid);
686 if ($g = data_get_field($field, $data)) {
687 $g->delete_content_files($id, $content->recordid, $content->content);
689 //delete the content itself
690 delete_records('data_content','id', $content->id);
694 // delete all the records and fields
695 delete_records('data_records', 'dataid', $id);
696 delete_records('data_fields','dataid',$id);
698 // Delete the instance itself
699 $result = delete_records('data', 'id', $id);
700 data_grade_item_delete($data);
701 return $result;
704 /************************************************************************
705 * returns a summary of data activity of this user *
706 ************************************************************************/
707 function data_user_outline($course, $user, $mod, $data) {
708 global $CFG;
709 require_once("$CFG->libdir/gradelib.php");
711 $grades = grade_get_grades($course->id, 'mod', 'data', $data->id, $user->id);
712 if (empty($grades->items[0]->grades)) {
713 $grade = false;
714 } else {
715 $grade = reset($grades->items[0]->grades);
718 if ($countrecords = count_records('data_records', 'dataid', $data->id, 'userid', $user->id)) {
719 $result = new object();
720 $result->info = get_string('numrecords', 'data', $countrecords);
721 $lastrecord = get_record_sql('SELECT id,timemodified FROM '.$CFG->prefix.'data_records
722 WHERE dataid = '.$data->id.' AND userid = '.$user->id.'
723 ORDER BY timemodified DESC', true);
724 $result->time = $lastrecord->timemodified;
725 if ($grade) {
726 $result->info .= ', ' . get_string('grade') . ': ' . $grade->str_long_grade;
728 return $result;
729 } else if ($grade) {
730 $result = new object();
731 $result->info = get_string('grade') . ': ' . $grade->str_long_grade;
732 $result->time = $grade->dategraded;
733 return $result;
735 return NULL;
738 /************************************************************************
739 * Prints all the records uploaded by this user *
740 ************************************************************************/
741 function data_user_complete($course, $user, $mod, $data) {
742 global $CFG;
743 require_once("$CFG->libdir/gradelib.php");
745 $grades = grade_get_grades($course->id, 'mod', 'data', $data->id, $user->id);
746 if (!empty($grades->items[0]->grades)) {
747 $grade = reset($grades->items[0]->grades);
748 echo '<p>'.get_string('grade').': '.$grade->str_long_grade.'</p>';
749 if ($grade->str_feedback) {
750 echo '<p>'.get_string('feedback').': '.$grade->str_feedback.'</p>';
753 if ($records = get_records_select('data_records', 'dataid = '.$data->id.' AND userid = '.$user->id,
754 'timemodified DESC')) {
755 data_print_template('singletemplate', $records, $data);
760 * Return grade for given user or all users.
762 * @param int $dataid id of data
763 * @param int $userid optional user id, 0 means all users
764 * @return array array of grades, false if none
766 function data_get_user_grades($data, $userid=0) {
767 global $CFG;
768 $user = $userid ? "AND u.id = $userid" : "";
769 $sql = "SELECT u.id, u.id AS userid, avg(drt.rating) AS rawgrade
770 FROM {$CFG->prefix}user u, {$CFG->prefix}data_records dr,
771 {$CFG->prefix}data_ratings drt
772 WHERE u.id = dr.userid AND dr.id = drt.recordid
773 AND drt.userid != u.id AND dr.dataid = $data->id
774 $user
775 GROUP BY u.id";
776 return get_records_sql($sql);
780 * Update grades by firing grade_updated event
782 * @param object $data null means all databases
783 * @param int $userid specific user only, 0 mean all
785 function data_update_grades($data=null, $userid=0, $nullifnone=true) {
786 global $CFG;
787 if (!function_exists('grade_update')) { //workaround for buggy PHP versions
788 require_once($CFG->libdir.'/gradelib.php');
791 if ($data != null) {
792 if ($grades = data_get_user_grades($data, $userid)) {
793 data_grade_item_update($data, $grades);
794 } else if ($userid and $nullifnone) {
795 $grade = new object();
796 $grade->userid = $userid;
797 $grade->rawgrade = NULL;
798 data_grade_item_update($data, $grade);
799 } else {
800 data_grade_item_update($data);
802 } else {
803 $sql = "SELECT d.*, cm.idnumber as cmidnumber
804 FROM {$CFG->prefix}data d, {$CFG->prefix}course_modules cm, {$CFG->prefix}modules m
805 WHERE m.name='data' AND m.id=cm.module AND cm.instance=d.id";
806 if ($rs = get_recordset_sql($sql)) {
807 while ($data = rs_fetch_next_record($rs)) {
808 if ($data->assessed) {
809 data_update_grades($data, 0, false);
810 } else {
811 data_grade_item_update($data);
814 rs_close($rs);
820 * Update/create grade item for given data
822 * @param object $data object with extra cmidnumber
823 * @param mixed optional array/object of grade(s); 'reset' means reset grades in gradebook
824 * @return object grade_item
826 function data_grade_item_update($data, $grades=NULL) {
827 global $CFG;
828 if (!function_exists('grade_update')) { //workaround for buggy PHP versions
829 require_once($CFG->libdir.'/gradelib.php');
831 $params = array('itemname'=>$data->name, 'idnumber'=>$data->cmidnumber);
832 if (!$data->assessed or $data->scale == 0) {
833 $params['gradetype'] = GRADE_TYPE_NONE;
834 } else if ($data->scale > 0) {
835 $params['gradetype'] = GRADE_TYPE_VALUE;
836 $params['grademax'] = $data->scale;
837 $params['grademin'] = 0;
838 } else if ($data->scale < 0) {
839 $params['gradetype'] = GRADE_TYPE_SCALE;
840 $params['scaleid'] = -$data->scale;
842 if ($grades === 'reset') {
843 $params['reset'] = true;
844 $grades = NULL;
847 return grade_update('mod/data', $data->course, 'mod', 'data', $data->id, 0, $grades, $params);
851 * Delete grade item for given data
853 * @param object $data object
854 * @return object grade_item
856 function data_grade_item_delete($data) {
857 global $CFG;
858 require_once($CFG->libdir.'/gradelib.php');
859 return grade_update('mod/data', $data->course, 'mod', 'data', $data->id, 0, NULL, array('deleted'=>1));
862 /************************************************************************
863 * returns a list of participants of this database *
864 ************************************************************************/
865 function data_get_participants($dataid) {
866 // Returns the users with data in one data
867 // (users with records in data_records, data_comments and data_ratings)
868 global $CFG;
869 $records = get_records_sql("SELECT DISTINCT u.id, u.id
870 FROM {$CFG->prefix}user u,
871 {$CFG->prefix}data_records r
872 WHERE r.dataid = '$dataid'
873 AND u.id = r.userid");
874 $comments = get_records_sql("SELECT DISTINCT u.id, u.id
875 FROM {$CFG->prefix}user u,
876 {$CFG->prefix}data_records r,
877 {$CFG->prefix}data_comments c
878 WHERE r.dataid = '$dataid'
879 AND u.id = r.userid
880 AND r.id = c.recordid");
881 $ratings = get_records_sql("SELECT DISTINCT u.id, u.id
882 FROM {$CFG->prefix}user u,
883 {$CFG->prefix}data_records r,
884 {$CFG->prefix}data_ratings a
885 WHERE r.dataid = '$dataid'
886 AND u.id = r.userid
887 AND r.id = a.recordid");
888 $participants = array();
889 if ($records) {
890 foreach ($records as $record) {
891 $participants[$record->id] = $record;
894 if ($comments) {
895 foreach ($comments as $comment) {
896 $participants[$comment->id] = $comment;
899 if ($ratings) {
900 foreach ($ratings as $rating) {
901 $participants[$rating->id] = $rating;
904 return $participants;
907 // junk functions
908 /************************************************************************
909 * takes a list of records, the current data, a search string, *
910 * and mode to display prints the translated template *
911 * input @param array $records *
912 * @param object $data *
913 * @param string $search *
914 * @param string $template *
915 * output null *
916 ************************************************************************/
917 function data_print_template($template, $records, $data, $search='', $page=0, $return=false) {
918 global $CFG;
919 $cm = get_coursemodule_from_instance('data', $data->id);
920 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
921 static $fields = NULL;
922 static $isteacher;
923 static $dataid = NULL;
924 if (empty($dataid)) {
925 $dataid = $data->id;
926 } else if ($dataid != $data->id) {
927 $fields = NULL;
929 if (empty($fields)) {
930 $fieldrecords = get_records('data_fields','dataid', $data->id);
931 foreach ($fieldrecords as $fieldrecord) {
932 $fields[]= data_get_field($fieldrecord, $data);
934 $isteacher = has_capability('mod/data:managetemplates', $context);
936 if (empty($records)) {
937 return;
939 foreach ($records as $record) { // Might be just one for the single template
940 // Replacing tags
941 $patterns = array();
942 $replacement = array();
943 // Then we generate strings to replace for normal tags
944 foreach ($fields as $field) {
945 $patterns[]='[['.$field->field->name.']]';
946 $replacement[] = highlight($search, $field->display_browse_field($record->id, $template));
948 // Replacing special tags (##Edit##, ##Delete##, ##More##)
949 $patterns[]='##edit##';
950 $patterns[]='##delete##';
951 if (has_capability('mod/data:manageentries', $context) or data_isowner($record->id)) {
952 $replacement[] = '<a href="'.$CFG->wwwroot.'/mod/data/edit.php?d='
953 .$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>';
954 $replacement[] = '<a href="'.$CFG->wwwroot.'/mod/data/view.php?d='
955 .$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>';
956 } else {
957 $replacement[] = '';
958 $replacement[] = '';
961 $moreurl = $CFG->wwwroot . '/mod/data/view.php?d=' . $data->id . '&amp;rid=' . $record->id;
962 if ($search) {
963 $moreurl .= '&amp;filter=1';
965 $patterns[]='##more##';
966 $replacement[] = '<a href="' . $moreurl . '"><img src="' . $CFG->pixpath . '/i/search.gif" class="iconsmall" alt="' . get_string('more', 'data') . '" title="' . get_string('more', 'data') . '" /></a>';
968 $patterns[]='##moreurl##';
969 $replacement[] = $moreurl;
971 $patterns[]='##user##';
972 $replacement[] = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$record->userid.
973 '&amp;course='.$data->course.'">'.fullname($record).'</a>';
975 $patterns[] = '##timeadded##';
976 $replacement[] = userdate($record->timecreated);
978 $patterns[] = '##timemodified##';
979 $replacement [] = userdate($record->timemodified);
981 $patterns[]='##approve##';
982 if (has_capability('mod/data:approve', $context) && ($data->approval) && (!$record->approved)) {
983 $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>';
984 } else {
985 $replacement[] = '';
988 $patterns[]='##comments##';
989 if (($template == 'listtemplate') && ($data->comments)) {
990 $comments = count_records('data_comments','recordid',$record->id);
991 $replacement[] = '<a href="view.php?rid='.$record->id.'#comments">'.get_string('commentsn','data', $comments).'</a>';
992 } else {
993 $replacement[] = '';
996 // actual replacement of the tags
997 $newtext = str_ireplace($patterns, $replacement, $data->{$template});
999 // no more html formatting and filtering - see MDL-6635
1000 if ($return) {
1001 return $newtext;
1002 } else {
1003 echo $newtext;
1004 // hack alert - return is always false in singletemplate anyway ;-)
1005 /**********************************
1006 * Printing Ratings Form *
1007 *********************************/
1008 if ($template == 'singletemplate') { //prints ratings options
1009 data_print_ratings($data, $record);
1011 /**********************************
1012 * Printing Ratings Form *
1013 *********************************/
1014 if (($template == 'singletemplate') && ($data->comments)) { //prints ratings options
1015 data_print_comments($data, $record, $page);
1022 /************************************************************************
1023 * function that takes in the current data, number of items per page, *
1024 * a search string and prints a preference box in view.php *
1026 * This preference box prints a searchable advanced search template if *
1027 * a) A template is defined *
1028 * b) The advanced search checkbox is checked. *
1030 * input @param object $data *
1031 * @param int $perpage *
1032 * @param string $search *
1033 * output null *
1034 ************************************************************************/
1035 function data_print_preference_form($data, $perpage, $search, $sort='', $order='ASC', $search_array = '', $advanced = 0, $mode= '') {
1036 global $CFG;
1037 $cm = get_coursemodule_from_instance('data', $data->id);
1038 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1039 echo '<br /><div class="datapreferences">';
1040 echo '<form id="options" action="view.php" method="get">';
1041 echo '<div>';
1042 echo '<input type="hidden" name="d" value="'.$data->id.'" />';
1043 if ($mode =='asearch') {
1044 $advanced = 1;
1045 echo '<input type="hidden" name="mode" value="list" />';
1047 echo '<label for="pref_perpage">'.get_string('pagesize','data').'</label> ';
1048 $pagesizes = array(2=>2,3=>3,4=>4,5=>5,6=>6,7=>7,8=>8,9=>9,10=>10,15=>15,
1049 20=>20,30=>30,40=>40,50=>50,100=>100,200=>200,300=>300,400=>400,500=>500,1000=>1000);
1050 choose_from_menu($pagesizes, 'perpage', $perpage, '', '', '0', false, false, 0, 'pref_perpage');
1051 echo '<div id="reg_search" style="display: ';
1052 if ($advanced) {
1053 echo 'none';
1055 else {
1056 echo 'inline';
1058 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>';
1059 echo '&nbsp;&nbsp;&nbsp;<label for="pref_sortby">'.get_string('sortby').'</label> ';
1060 // foreach field, print the option
1061 echo '<select name="sort" id="pref_sortby">';
1062 if ($fields = get_records('data_fields','dataid',$data->id, 'name')) {
1063 echo '<optgroup label="'.get_string('fields', 'data').'">';
1064 foreach ($fields as $field) {
1065 if ($field->id == $sort) {
1066 echo '<option value="'.$field->id.'" selected="selected">'.$field->name.'</option>';
1067 } else {
1068 echo '<option value="'.$field->id.'">'.$field->name.'</option>';
1071 echo '</optgroup>';
1073 $options = array();
1074 $options[DATA_TIMEADDED] = get_string('timeadded', 'data');
1075 $options[DATA_TIMEMODIFIED] = get_string('timemodified', 'data');
1076 $options[DATA_FIRSTNAME] = get_string('authorfirstname', 'data');
1077 $options[DATA_LASTNAME] = get_string('authorlastname', 'data');
1078 if ($data->approval and has_capability('mod/data:approve', $context)) {
1079 $options[DATA_APPROVED] = get_string('approved', 'data');
1081 echo '<optgroup label="'.get_string('other', 'data').'">';
1082 foreach ($options as $key => $name) {
1083 if ($key == $sort) {
1084 echo '<option value="'.$key.'" selected="selected">'.$name.'</option>';
1085 } else {
1086 echo '<option value="'.$key.'">'.$name.'</option>';
1089 echo '</optgroup>';
1090 echo '</select>';
1091 echo '<label for="pref_order" class="accesshide">'.get_string('order').'</label>';
1092 echo '<select id="pref_order" name="order">';
1093 if ($order == 'ASC') {
1094 echo '<option value="ASC" selected="selected">'.get_string('ascending','data').'</option>';
1095 } else {
1096 echo '<option value="ASC">'.get_string('ascending','data').'</option>';
1098 if ($order == 'DESC') {
1099 echo '<option value="DESC" selected="selected">'.get_string('descending','data').'</option>';
1100 } else {
1101 echo '<option value="DESC">'.get_string('descending','data').'</option>';
1103 echo '</select>';
1105 if ($advanced) {
1106 $checked = ' checked="checked" ';
1108 else {
1109 $checked = '';
1111 print '
1112 <script type="text/javascript">
1113 //<![CDATA[
1114 <!-- Start
1115 // javascript for hiding/displaying advanced search form
1117 function showHideAdvSearch(checked) {
1118 var divs = document.getElementsByTagName(\'div\');
1119 for(i=0;i<divs.length;i++) {
1120 if(divs[i].id.match(\'data_adv_form\')) {
1121 if(checked) {
1122 divs[i].style.display = \'inline\';
1124 else {
1125 divs[i].style.display = \'none\';
1128 else if (divs[i].id.match(\'reg_search\')) {
1129 if (!checked) {
1130 divs[i].style.display = \'inline\';
1132 else {
1133 divs[i].style.display = \'none\';
1138 // End -->
1139 //]]>
1140 </script>';
1141 echo '&nbsp;<input type="hidden" name="advanced" value="0" />';
1142 echo '&nbsp;<input type="hidden" name="filter" value="1" />';
1143 echo '&nbsp;<input type="checkbox" id="advancedcheckbox" name="advanced" value="1" '.$checked.' onchange="showHideAdvSearch(this.checked);" /><label for="advancedcheckbox">'.get_string('advancedsearch', 'data').'</label>';
1144 echo '&nbsp;<input type="submit" value="'.get_string('savesettings','data').'" />';
1145 echo '<br />';
1146 echo '<div class="dataadvancedsearch" id="data_adv_form" style="display: ';
1147 if ($advanced) {
1148 echo 'inline';
1150 else {
1151 echo 'none';
1153 echo ';margin-left:auto;margin-right:auto;" >';
1154 echo '<table class="boxaligncenter">';
1155 // print ASC or DESC
1156 echo '<tr><td colspan="2">&nbsp;</td></tr>';
1157 $i = 0;
1159 // Determine if we are printing all fields for advanced search, or the template for advanced search
1160 // If a template is not defined, use the deafault template and display all fields.
1161 if(empty($data->asearchtemplate)) {
1162 data_generate_default_template($data, 'asearchtemplate');
1165 static $fields = NULL;
1166 static $isteacher;
1167 static $dataid = NULL;
1168 if (empty($dataid)) {
1169 $dataid = $data->id;
1170 } else if ($dataid != $data->id) {
1171 $fields = NULL;
1174 if (empty($fields)) {
1175 $fieldrecords = get_records('data_fields','dataid', $data->id);
1176 foreach ($fieldrecords as $fieldrecord) {
1177 $fields[]= data_get_field($fieldrecord, $data);
1179 $isteacher = has_capability('mod/data:managetemplates', $context);
1182 // Replacing tags
1183 $patterns = array();
1184 $replacement = array();
1186 // Then we generate strings to replace for normal tags
1187 foreach ($fields as $field) {
1188 $fieldname = $field->field->name;
1189 $fieldname = preg_quote($fieldname, '/');
1190 $patterns[] = "/\[\[$fieldname\]\]/i";
1191 $searchfield = data_get_field_from_id($field->field->id, $data);
1192 if (!empty($search_array[$field->field->id]->data)) {
1193 $replacement[] = $searchfield->display_search_field($search_array[$field->field->id]->data);
1194 } else {
1195 $replacement[] = $searchfield->display_search_field();
1198 $fn = !empty($search_array[DATA_FIRSTNAME]->data) ? $search_array[DATA_FIRSTNAME]->data : '';
1199 $ln = !empty($search_array[DATA_LASTNAME]->data) ? $search_array[DATA_LASTNAME]->data : '';
1200 $patterns[] = '/##firstname##/';
1201 $replacement[] = '<input type="text" size="16" name="u_fn" value="'.$fn.'" />';
1202 $patterns[] = '/##lastname##/';
1203 $replacement[] = '<input type="text" size="16" name="u_ln" value="'.$ln.'" />';
1205 // actual replacement of the tags
1206 $newtext = preg_replace($patterns, $replacement, $data->asearchtemplate);
1207 $options = new object();
1208 $options->para=false;
1209 $options->noclean=true;
1210 echo '<tr><td>';
1211 echo format_text($newtext, FORMAT_HTML, $options);
1212 echo '</td></tr>';
1213 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>';
1214 echo '</table>';
1215 echo '</div>';
1216 echo '</div>';
1217 echo '</form>';
1218 echo '</div>';
1221 function data_print_ratings($data, $record) {
1222 global $USER;
1224 $cm = get_coursemodule_from_instance('data', $data->id);
1225 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1226 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))) {
1227 if ($ratingsscale = make_grades_menu($data->scale)) {
1228 $ratingsmenuused = false;
1229 echo '<div class="ratings" style="text-align:center">';
1230 echo '<form id="form" method="post" action="rate.php">';
1231 echo '<input type="hidden" name="dataid" value="'.$data->id.'" />';
1232 if (has_capability('mod/data:rate', $context) and !data_isowner($record->id)) {
1233 data_print_ratings_mean($record->id, $ratingsscale, has_capability('mod/data:viewrating', $context));
1234 echo '&nbsp;';
1235 data_print_rating_menu($record->id, $USER->id, $ratingsscale);
1236 $ratingsmenuused = true;
1237 } else {
1238 data_print_ratings_mean($record->id, $ratingsscale, true);
1240 if ($data->scale < 0) {
1241 if ($scale = get_record('scale', 'id', abs($data->scale))) {
1242 print_scale_menu_helpbutton($data->course, $scale );
1246 if ($ratingsmenuused) {
1247 echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
1248 echo '<input type="submit" value="'.get_string('sendinratings', 'data').'" />';
1250 echo '</form>';
1251 echo '</div>';
1256 function data_print_ratings_mean($recordid, $scale, $link=true) {
1257 // Print the multiple ratings on a post given to the current user by others.
1258 // Scale is an array of ratings
1260 static $strrate;
1261 $mean = data_get_ratings_mean($recordid, $scale);
1262 if ($mean !== "") {
1263 if (empty($strratings)) {
1264 $strratings = get_string("ratings", "data");
1266 echo "$strratings: ";
1267 if ($link) {
1268 link_to_popup_window ("/mod/data/report.php?id=$recordid", "ratings", $mean, 400, 600);
1269 } else {
1270 echo "$mean ";
1276 function data_get_ratings_mean($recordid, $scale, $ratings=NULL) {
1277 // Return the mean rating of a post given to the current user by others.
1278 // Scale is an array of possible ratings in the scale
1279 // Ratings is an optional simple array of actual ratings (just integers)
1280 if (!$ratings) {
1281 $ratings = array();
1282 if ($rates = get_records("data_ratings", "recordid", $recordid)) {
1283 foreach ($rates as $rate) {
1284 $ratings[] = $rate->rating;
1288 $count = count($ratings);
1289 if ($count == 0) {
1290 return "";
1291 } else if ($count == 1) {
1292 return $scale[$ratings[0]];
1293 } else {
1294 $total = 0;
1295 foreach ($ratings as $rating) {
1296 $total += $rating;
1298 $mean = round( ((float)$total/(float)$count) + 0.001); // Little fudge factor so that 0.5 goes UP
1299 if (isset($scale[$mean])) {
1300 return $scale[$mean]." ($count)";
1301 } else {
1302 return "$mean ($count)"; // Should never happen, hopefully
1308 function data_print_rating_menu($recordid, $userid, $scale) {
1309 // Print the menu of ratings as part of a larger form.
1310 // If the post has already been - set that value.
1311 // Scale is an array of ratings
1312 static $strrate;
1313 if (!$rating = get_record("data_ratings", "userid", $userid, "recordid", $recordid)) {
1314 $rating->rating = -999;
1316 if (empty($strrate)) {
1317 $strrate = get_string("rate", "data");
1319 choose_from_menu($scale, $recordid, $rating->rating, "$strrate...", '', -999);
1323 function data_get_ratings($recordid, $sort="u.firstname ASC") {
1324 // Returns a list of ratings for a particular post - sorted.
1325 global $CFG;
1326 return get_records_sql("SELECT u.*, r.rating
1327 FROM {$CFG->prefix}data_ratings r,
1328 {$CFG->prefix}user u
1329 WHERE r.recordid = $recordid
1330 AND r.userid = u.id
1331 ORDER BY $sort");
1335 // prints all comments + a text box for adding additional comment
1336 function data_print_comments($data, $record, $page=0, $mform=false) {
1337 global $CFG;
1338 $cm = get_coursemodule_from_instance('data', $data->id);
1339 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1340 $cancomment = has_capability('mod/data:comment', $context);
1341 echo '<a name="comments"></a>';
1342 if ($comments = get_records('data_comments','recordid',$record->id)) {
1343 foreach ($comments as $comment) {
1344 data_print_comment($data, $comment, $page);
1346 echo '<br />';
1348 if (!isloggedin() or isguest() or !$cancomment) {
1349 return;
1351 $editor = optional_param('addcomment', 0, PARAM_BOOL);
1352 if (!$mform and !$editor) {
1353 echo '<div class="newcomment" style="text-align:center">';
1354 echo '<a href="view.php?d='.$data->id.'&amp;rid='.$record->id.'&amp;mode=single&amp;addcomment=1">'.get_string('addcomment', 'data').'</a>';
1355 echo '</div>';
1356 } else {
1357 if (!$mform) {
1358 require_once('comment_form.php');
1359 $mform = new mod_data_comment_form('comment.php');
1360 $mform->set_data(array('mode'=>'add', 'page'=>$page, 'rid'=>$record->id));
1362 echo '<div class="newcomment" style="text-align:center">';
1363 $mform->display();
1364 echo '</div>';
1368 // prints a single comment entry
1369 function data_print_comment($data, $comment, $page=0) {
1370 global $USER, $CFG;
1371 $cm = get_coursemodule_from_instance('data', $data->id);
1372 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1373 $stredit = get_string('edit');
1374 $strdelete = get_string('delete');
1375 $user = get_record('user','id',$comment->userid);
1376 echo '<table cellspacing="0" align="center" width="50%" class="datacomment forumpost">';
1377 echo '<tr class="header"><td class="picture left">';
1378 print_user_picture($user, $data->course, $user->picture);
1379 echo '</td>';
1380 echo '<td class="topic starter" align="left"><div class="author">';
1381 $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context));
1382 $by = new object();
1383 $by->name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.
1384 $user->id.'&amp;course='.$data->course.'">'.$fullname.'</a>';
1385 $by->date = userdate($comment->modified);
1386 print_string('bynameondate', 'data', $by);
1387 echo '</div></td></tr>';
1388 echo '<tr><td class="left side">';
1389 if ($groups = groups_get_all_groups($data->course, $comment->userid, $cm->groupingid)) {
1390 print_group_picture($groups, $data->course, false, false, true);
1391 } else {
1392 echo '&nbsp;';
1395 // Actual content
1396 echo '</td><td class="content" align="left">'."\n";
1397 // Print whole message
1398 echo format_text($comment->content, $comment->format);
1400 // Commands
1401 echo '<div class="commands">';
1402 if (data_isowner($comment->recordid) or has_capability('mod/data:managecomments', $context)) {
1403 echo '<a href="'.$CFG->wwwroot.'/mod/data/comment.php?rid='.$comment->recordid.'&amp;mode=edit&amp;commentid='.$comment->id.'&amp;page='.$page.'">'.$stredit.'</a>';
1404 echo '| <a href="'.$CFG->wwwroot.'/mod/data/comment.php?rid='.$comment->recordid.'&amp;mode=delete&amp;commentid='.$comment->id.'&amp;page='.$page.'">'.$strdelete.'</a>';
1407 echo '</div>';
1408 echo '</td></tr></table>'."\n\n";
1412 // For Participantion Reports
1413 function data_get_view_actions() {
1414 return array('view');
1417 function data_get_post_actions() {
1418 return array('add','update','record delete');
1421 function data_fieldname_exists($name, $dataid, $fieldid=0) {
1422 global $CFG;
1423 $LIKE = sql_ilike();
1424 if ($fieldid) {
1425 return record_exists_sql("SELECT * from {$CFG->prefix}data_fields df
1426 WHERE df.name $LIKE '$name' AND df.dataid = $dataid
1427 AND ((df.id < $fieldid) OR (df.id > $fieldid))");
1428 } else {
1429 return record_exists_sql("SELECT * from {$CFG->prefix}data_fields df
1430 WHERE df.name $LIKE '$name' AND df.dataid = $dataid");
1434 function data_convert_arrays_to_strings(&$fieldinput) {
1435 foreach ($fieldinput as $key => $val) {
1436 if (is_array($val)) {
1437 $str = '';
1438 foreach ($val as $inner) {
1439 $str .= $inner . ',';
1441 $str = substr($str, 0, -1);
1442 $fieldinput->$key = $str;
1449 * Converts a database (module instance) to use the Roles System
1450 * @param $data - a data object with the same attributes as a record
1451 * from the data database table
1452 * @param $datamodid - the id of the data module, from the modules table
1453 * @param $teacherroles - array of roles that have moodle/legacy:teacher
1454 * @param $studentroles - array of roles that have moodle/legacy:student
1455 * @param $guestroles - array of roles that have moodle/legacy:guest
1456 * @param $cmid - the course_module id for this data instance
1457 * @return boolean - data module was converted or not
1459 function data_convert_to_roles($data, $teacherroles=array(), $studentroles=array(), $cmid=NULL) {
1460 global $CFG;
1461 if (!isset($data->participants) && !isset($data->assesspublic)
1462 && !isset($data->groupmode)) {
1463 // We assume that this database has already been converted to use the
1464 // Roles System. above fields get dropped the data module has been
1465 // upgraded to use Roles.
1466 return false;
1468 if (empty($cmid)) {
1469 // We were not given the course_module id. Try to find it.
1470 if (!$cm = get_coursemodule_from_instance('data', $data->id)) {
1471 notify('Could not get the course module for the data');
1472 return false;
1473 } else {
1474 $cmid = $cm->id;
1477 $context = get_context_instance(CONTEXT_MODULE, $cmid);
1479 // $data->participants:
1480 // 1 - Only teachers can add entries
1481 // 3 - Teachers and students can add entries
1482 switch ($data->participants) {
1483 case 1:
1484 foreach ($studentroles as $studentrole) {
1485 assign_capability('mod/data:writeentry', CAP_PREVENT, $studentrole->id, $context->id);
1487 foreach ($teacherroles as $teacherrole) {
1488 assign_capability('mod/data:writeentry', CAP_ALLOW, $teacherrole->id, $context->id);
1490 break;
1491 case 3:
1492 foreach ($studentroles as $studentrole) {
1493 assign_capability('mod/data:writeentry', CAP_ALLOW, $studentrole->id, $context->id);
1495 foreach ($teacherroles as $teacherrole) {
1496 assign_capability('mod/data:writeentry', CAP_ALLOW, $teacherrole->id, $context->id);
1498 break;
1501 // $data->assessed:
1502 // 2 - Only teachers can rate posts
1503 // 1 - Everyone can rate posts
1504 // 0 - No one can rate posts
1505 switch ($data->assessed) {
1506 case 0:
1507 foreach ($studentroles as $studentrole) {
1508 assign_capability('mod/data:rate', CAP_PREVENT, $studentrole->id, $context->id);
1510 foreach ($teacherroles as $teacherrole) {
1511 assign_capability('mod/data:rate', CAP_PREVENT, $teacherrole->id, $context->id);
1513 break;
1514 case 1:
1515 foreach ($studentroles as $studentrole) {
1516 assign_capability('mod/data:rate', CAP_ALLOW, $studentrole->id, $context->id);
1518 foreach ($teacherroles as $teacherrole) {
1519 assign_capability('mod/data:rate', CAP_ALLOW, $teacherrole->id, $context->id);
1521 break;
1522 case 2:
1523 foreach ($studentroles as $studentrole) {
1524 assign_capability('mod/data:rate', CAP_PREVENT, $studentrole->id, $context->id);
1526 foreach ($teacherroles as $teacherrole) {
1527 assign_capability('mod/data:rate', CAP_ALLOW, $teacherrole->id, $context->id);
1529 break;
1532 // $data->assesspublic:
1533 // 0 - Students can only see their own ratings
1534 // 1 - Students can see everyone's ratings
1535 switch ($data->assesspublic) {
1536 case 0:
1537 foreach ($studentroles as $studentrole) {
1538 assign_capability('mod/data:viewrating', CAP_PREVENT, $studentrole->id, $context->id);
1540 foreach ($teacherroles as $teacherrole) {
1541 assign_capability('mod/data:viewrating', CAP_ALLOW, $teacherrole->id, $context->id);
1543 break;
1544 case 1:
1545 foreach ($studentroles as $studentrole) {
1546 assign_capability('mod/data:viewrating', CAP_ALLOW, $studentrole->id, $context->id);
1548 foreach ($teacherroles as $teacherrole) {
1549 assign_capability('mod/data:viewrating', CAP_ALLOW, $teacherrole->id, $context->id);
1551 break;
1554 if (empty($cm)) {
1555 $cm = get_record('course_modules', 'id', $cmid);
1558 switch ($cm->groupmode) {
1559 case NOGROUPS:
1560 break;
1561 case SEPARATEGROUPS:
1562 foreach ($studentroles as $studentrole) {
1563 assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $studentrole->id, $context->id);
1565 foreach ($teacherroles as $teacherrole) {
1566 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $teacherrole->id, $context->id);
1568 break;
1569 case VISIBLEGROUPS:
1570 foreach ($studentroles as $studentrole) {
1571 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $studentrole->id, $context->id);
1573 foreach ($teacherroles as $teacherrole) {
1574 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $teacherrole->id, $context->id);
1576 break;
1578 return true;
1582 * Returns the best name to show for a preset
1584 function data_preset_name($shortname, $path) {
1586 // We are looking inside the preset itself as a first choice, but also in normal data directory
1587 $string = get_string('modulename', 'datapreset_'.$shortname);
1589 if (substr($string, 0, 1) == '[') {
1590 return $shortname;
1591 } else {
1592 return $string;
1597 * Returns an array of all the available presets
1599 function data_get_available_presets($context) {
1600 global $CFG, $USER;
1601 $presets = array();
1602 if ($dirs = get_list_of_plugins('mod/data/preset')) {
1603 foreach ($dirs as $dir) {
1604 $fulldir = $CFG->dirroot.'/mod/data/preset/'.$dir;
1605 if (is_directory_a_preset($fulldir)) {
1606 $preset = new object;
1607 $preset->path = $fulldir;
1608 $preset->userid = 0;
1609 $preset->shortname = $dir;
1610 $preset->name = data_preset_name($dir, $fulldir);
1611 if (file_exists($fulldir.'/screenshot.jpg')) {
1612 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.jpg';
1613 } else if (file_exists($fulldir.'/screenshot.png')) {
1614 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.png';
1615 } else if (file_exists($fulldir.'/screenshot.gif')) {
1616 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.gif';
1618 $presets[] = $preset;
1623 if ($userids = get_list_of_plugins('data/preset', '', $CFG->dataroot)) {
1624 foreach ($userids as $userid) {
1625 $fulldir = $CFG->dataroot.'/data/preset/'.$userid;
1626 if ($userid == 0 || $USER->id == $userid || has_capability('mod/data:viewalluserpresets', $context)) {
1627 if ($dirs = get_list_of_plugins('data/preset/'.$userid, '', $CFG->dataroot)) {
1628 foreach ($dirs as $dir) {
1629 $fulldir = $CFG->dataroot.'/data/preset/'.$userid.'/'.$dir;
1630 if (is_directory_a_preset($fulldir)) {
1631 $preset = new object;
1632 $preset->path = $fulldir;
1633 $preset->userid = $userid;
1634 $preset->shortname = $dir;
1635 $preset->name = data_preset_name($dir, $fulldir);
1636 if (file_exists($fulldir.'/screenshot.jpg')) {
1637 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.jpg';
1638 } else if (file_exists($fulldir.'/screenshot.png')) {
1639 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.png';
1640 } else if (file_exists($fulldir.'/screenshot.gif')) {
1641 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.gif';
1643 $presets[] = $preset;
1650 return $presets;
1654 function data_print_header($course, $cm, $data, $currenttab='') {
1655 global $CFG, $displaynoticegood, $displaynoticebad;
1656 $navigation = build_navigation('', $cm);
1657 print_header_simple($data->name, '', $navigation,
1658 '', '', true, update_module_button($cm->id, $course->id, get_string('modulename', 'data')),
1659 navmenu($course, $cm));
1660 print_heading(format_string($data->name));
1662 // Groups needed for Add entry tab
1663 $currentgroup = groups_get_activity_group($cm);
1664 $groupmode = groups_get_activity_groupmode($cm);
1665 // Print the tabs
1666 if ($currenttab) {
1667 include('tabs.php');
1669 // Print any notices
1670 if (!empty($displaynoticegood)) {
1671 notify($displaynoticegood, 'notifysuccess'); // good (usually green)
1672 } else if (!empty($displaynoticebad)) {
1673 notify($displaynoticebad); // bad (usuually red)
1677 function data_user_can_add_entry($data, $currentgroup, $groupmode) {
1678 global $USER;
1679 if (!$cm = get_coursemodule_from_instance('data', $data->id)) {
1680 error('Course Module ID was incorrect');
1682 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1683 if (!has_capability('mod/data:writeentry', $context) and !has_capability('mod/data:manageentries',$context)) {
1684 return false;
1686 if (!$groupmode or has_capability('moodle/site:accessallgroups', $context)) {
1687 return true;
1690 if ($currentgroup) {
1691 return groups_is_member($currentgroup);
1692 } else {
1693 //else it might be group 0 in visible mode
1694 if ($groupmode == VISIBLEGROUPS){
1695 return true;
1696 } else {
1697 return false;
1703 function is_directory_a_preset($directory) {
1704 $directory = rtrim($directory, '/\\') . '/';
1705 $status = file_exists($directory.'singletemplate.html') &&
1706 file_exists($directory.'listtemplate.html') &&
1707 file_exists($directory.'listtemplateheader.html') &&
1708 file_exists($directory.'listtemplatefooter.html') &&
1709 file_exists($directory.'addtemplate.html') &&
1710 file_exists($directory.'rsstemplate.html') &&
1711 file_exists($directory.'rsstitletemplate.html') &&
1712 file_exists($directory.'csstemplate.css') &&
1713 file_exists($directory.'jstemplate.js') &&
1714 file_exists($directory.'preset.xml');
1715 return $status;
1719 function clean_preset($folder) {
1720 $status = @unlink($folder.'/singletemplate.html') &&
1721 @unlink($folder.'/listtemplate.html') &&
1722 @unlink($folder.'/listtemplateheader.html') &&
1723 @unlink($folder.'/listtemplatefooter.html') &&
1724 @unlink($folder.'/addtemplate.html') &&
1725 @unlink($folder.'/rsstemplate.html') &&
1726 @unlink($folder.'/rsstitletemplate.html') &&
1727 @unlink($folder.'/csstemplate.css') &&
1728 @unlink($folder.'/jstemplate.js') &&
1729 @unlink($folder.'/preset.xml');
1731 // optional
1732 @unlink($folder.'/asearchtemplate.html');
1733 return $status;
1737 class PresetImporter {
1738 function PresetImporter($course, $cm, $data, $userid, $shortname) {
1739 global $CFG;
1740 $this->course = $course;
1741 $this->cm = $cm;
1742 $this->data = $data;
1743 $this->userid = $userid;
1744 $this->shortname = $shortname;
1745 $this->folder = data_preset_path($course, $userid, $shortname);
1748 function get_settings() {
1749 global $CFG;
1751 if (!is_directory_a_preset($this->folder)) {
1752 error("$this->userid/$this->shortname Not a preset");
1755 /* Grab XML */
1756 $presetxml = file_get_contents($this->folder.'/preset.xml');
1757 $parsedxml = xmlize($presetxml, 0);
1759 $allowed_settings = array('intro', 'comments', 'requiredentries', 'requiredentriestoview',
1760 'maxentries', 'rssarticles', 'approval', 'defaultsortdir', 'defaultsort');
1762 /* First, do settings. Put in user friendly array. */
1763 $settingsarray = $parsedxml['preset']['#']['settings'][0]['#'];
1764 $settings = new StdClass();
1766 foreach ($settingsarray as $setting => $value) {
1767 if (!is_array($value)) {
1768 continue;
1770 if (!in_array($setting, $allowed_settings)) {
1771 // unsupported setting
1772 continue;
1774 $settings->$setting = $value[0]['#'];
1777 /* Now work out fields to user friendly array */
1778 $fieldsarray = $parsedxml['preset']['#']['field'];
1779 $fields = array();
1780 foreach ($fieldsarray as $field) {
1781 if (!is_array($field)) {
1782 continue;
1784 $f = new StdClass();
1785 foreach ($field['#'] as $param => $value) {
1786 if (!is_array($value)) {
1787 continue;
1789 $f->$param = addslashes($value[0]['#']);
1791 $f->dataid = $this->data->id;
1792 $f->type = clean_param($f->type, PARAM_ALPHA);
1793 $fields[] = $f;
1795 /* Now add the HTML templates to the settings array so we can update d */
1796 $settings->singletemplate = file_get_contents($this->folder."/singletemplate.html");
1797 $settings->listtemplate = file_get_contents($this->folder."/listtemplate.html");
1798 $settings->listtemplateheader = file_get_contents($this->folder."/listtemplateheader.html");
1799 $settings->listtemplatefooter = file_get_contents($this->folder."/listtemplatefooter.html");
1800 $settings->addtemplate = file_get_contents($this->folder."/addtemplate.html");
1801 $settings->rsstemplate = file_get_contents($this->folder."/rsstemplate.html");
1802 $settings->rsstitletemplate = file_get_contents($this->folder."/rsstitletemplate.html");
1803 $settings->csstemplate = file_get_contents($this->folder."/csstemplate.css");
1804 $settings->jstemplate = file_get_contents($this->folder."/jstemplate.js");
1806 //optional
1807 if (file_exists($this->folder."/asearchtemplate.html")) {
1808 $settings->asearchtemplate = file_get_contents($this->folder."/asearchtemplate.html");
1809 } else {
1810 $settings->asearchtemplate = NULL;
1813 $settings->instance = $this->data->id;
1815 /* Now we look at the current structure (if any) to work out whether we need to clear db
1816 or save the data */
1817 if (!$currentfields = get_records('data_fields', 'dataid', $this->data->id)) {
1818 $currentfields = array();
1821 return array($settings, $fields, $currentfields);
1824 function import_options() {
1825 if (!confirm_sesskey()) {
1826 error("Sesskey Invalid");
1828 $strblank = get_string('blank', 'data');
1829 $strcontinue = get_string('continue');
1830 $strwarning = get_string('mappingwarning', 'data');
1831 $strfieldmappings = get_string('fieldmappings', 'data');
1832 $strnew = get_string('new');
1833 $sesskey = sesskey();
1834 list($settings, $newfields, $currentfields) = $this->get_settings();
1835 echo '<div class="presetmapping"><form action="preset.php" method="post">';
1836 echo '<div>';
1837 echo '<input type="hidden" name="action" value="finishimport" />';
1838 echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
1839 echo '<input type="hidden" name="d" value="'.$this->data->id.'" />';
1840 echo '<input type="hidden" name="fullname" value="'.$this->userid.'/'.$this->shortname.'" />';
1841 if (!empty($currentfields) && !empty($newfields)) {
1842 echo "<h3>$strfieldmappings ";
1843 helpbutton('fieldmappings', $strfieldmappings, 'data');
1844 echo '</h3><table>';
1845 foreach ($newfields as $nid => $newfield) {
1846 echo "<tr><td><label for=\"id_$newfield->name\">$newfield->name</label></td>";
1847 echo '<td><select name="field_'.$nid.'" id="id_'.$newfield->name.'">';
1848 $selected = false;
1849 foreach ($currentfields as $cid => $currentfield) {
1850 if ($currentfield->type == $newfield->type) {
1851 if ($currentfield->name == $newfield->name) {
1852 echo '<option value="'.$cid.'" selected="selected">'.$currentfield->name.'</option>';
1853 $selected=true;
1855 else {
1856 echo '<option value="'.$cid.'">'.$currentfield->name.'</option>';
1860 if ($selected)
1861 echo '<option value="-1">-</option>';
1862 else
1863 echo '<option value="-1" selected="selected">-</option>';
1864 echo '</select></td></tr>';
1866 echo '</table>';
1867 echo "<p>$strwarning</p>";
1868 } else if (empty($newfields)) {
1869 error("New preset has no defined fields!");
1871 echo '<div class="overwritesettings"><label for="overwritesettings">'.get_string('overwritesettings', 'data');
1872 echo '<input id="overwritesettings" name="overwritesettings" type="checkbox" /></label></div>';
1873 echo '<input class="button" type="submit" value="'.$strcontinue.'" /></div></form></div>';
1876 function import() {
1877 global $CFG;
1878 list($settings, $newfields, $currentfields) = $this->get_settings();
1879 $preservedfields = array();
1880 $overwritesettings = optional_param('overwritesettings', 0, PARAM_BOOL);
1881 /* Maps fields and makes new ones */
1882 if (!empty($newfields)) {
1883 /* We require an injective mapping, and need to know what to protect */
1884 foreach ($newfields as $nid => $newfield) {
1885 $cid = optional_param("field_$nid", -1, PARAM_INT);
1886 if ($cid == -1) continue;
1887 if (array_key_exists($cid, $preservedfields)) error("Not an injective map");
1888 else $preservedfields[$cid] = true;
1890 foreach ($newfields as $nid => $newfield) {
1891 $cid = optional_param("field_$nid", -1, PARAM_INT);
1892 /* A mapping. Just need to change field params. Data kept. */
1893 if ($cid != -1 and isset($currentfields[$cid])) {
1894 $fieldobject = data_get_field_from_id($currentfields[$cid]->id, $this->data);
1895 foreach ($newfield as $param => $value) {
1896 if ($param != "id") {
1897 $fieldobject->field->$param = $value;
1900 unset($fieldobject->field->similarfield);
1901 $fieldobject->update_field();
1902 unset($fieldobject);
1904 /* Make a new field */
1905 else {
1906 include_once("field/$newfield->type/field.class.php");
1907 if (!isset($newfield->description)) {
1908 $newfield->description = '';
1910 $classname = 'data_field_'.$newfield->type;
1911 $fieldclass = new $classname($newfield, $this->data);
1912 $fieldclass->insert_field();
1913 unset($fieldclass);
1918 /* Get rid of all old unused data */
1919 if (!empty($preservedfields)) {
1920 foreach ($currentfields as $cid => $currentfield) {
1921 if (!array_key_exists($cid, $preservedfields)) {
1922 /* Data not used anymore so wipe! */
1923 print "Deleting field $currentfield->name<br />";
1924 $id = $currentfield->id;
1925 //Why delete existing data records and related comments/ratings??
1927 if ($content = get_records('data_content', 'fieldid', $id)) {
1928 foreach ($content as $item) {
1929 delete_records('data_ratings', 'recordid', $item->recordid);
1930 delete_records('data_comments', 'recordid', $item->recordid);
1931 delete_records('data_records', 'id', $item->recordid);
1934 delete_records('data_content', 'fieldid', $id);
1935 delete_records('data_fields', 'id', $id);
1940 // handle special settings here
1941 if (!empty($settings->defaultsort)) {
1942 if (is_numeric($settings->defaultsort)) {
1943 // old broken value
1944 $settings->defaultsort = 0;
1945 } else {
1946 $settings->defaultsort = (int)get_field('data_fields', 'id', 'dataid', $this->data->id, 'name', addslashes($settings->defaultsort));
1948 } else {
1949 $settings->defaultsort = 0;
1952 // do we want to overwrite all current database settings?
1953 if ($overwritesettings) {
1954 // all supported settings
1955 $overwrite = array_keys((array)$settings);
1956 } else {
1957 // only templates and sorting
1958 $overwrite = array('singletemplate', 'listtemplate', 'listtemplateheader', 'listtemplatefooter',
1959 'addtemplate', 'rsstemplate', 'rsstitletemplate', 'csstemplate', 'jstemplate',
1960 'asearchtemplate', 'defaultsortdir', 'defaultsort');
1963 // now overwrite current data settings
1964 foreach ($this->data as $prop=>$unused) {
1965 if (in_array($prop, $overwrite)) {
1966 $this->data->$prop = $settings->$prop;
1970 data_update_instance(addslashes_object($this->data));
1971 if (strstr($this->folder, '/temp/')) {
1972 // Removes the temporary files
1973 clean_preset($this->folder);
1975 return true;
1979 function data_preset_path($course, $userid, $shortname) {
1980 global $USER, $CFG;
1981 $context = get_context_instance(CONTEXT_COURSE, $course->id);
1982 $userid = (int)$userid;
1983 if ($userid > 0 && ($userid == $USER->id || has_capability('mod/data:viewalluserpresets', $context))) {
1984 return $CFG->dataroot.'/data/preset/'.$userid.'/'.$shortname;
1985 } else if ($userid == 0) {
1986 return $CFG->dirroot.'/mod/data/preset/'.$shortname;
1987 } else if ($userid < 0) {
1988 return $CFG->dataroot.'/temp/data/'.-$userid.'/'.$shortname;
1990 return 'Does it disturb you that this code will never run?';
1994 * Implementation of the function for printing the form elements that control
1995 * whether the course reset functionality affects the data.
1996 * @param $mform form passed by reference
1998 function data_reset_course_form_definition(&$mform) {
1999 $mform->addElement('header', 'dataheader', get_string('modulenameplural', 'data'));
2000 $mform->addElement('checkbox', 'reset_data', get_string('deleteallentries','data'));
2002 $mform->addElement('checkbox', 'reset_data_notenrolled', get_string('deletenotenrolled', 'data'));
2003 $mform->disabledIf('reset_data_notenrolled', 'reset_data', 'checked');
2005 $mform->addElement('checkbox', 'reset_data_ratings', get_string('deleteallratings'));
2006 $mform->disabledIf('reset_data_ratings', 'reset_data', 'checked');
2008 $mform->addElement('checkbox', 'reset_data_comments', get_string('deleteallcomments'));
2009 $mform->disabledIf('reset_data_comments', 'reset_data', 'checked');
2013 * Course reset form defaults.
2015 function data_reset_course_form_defaults($course) {
2016 return array('reset_data'=>0, 'reset_data_ratings'=>1, 'reset_data_comments'=>1, 'reset_data_notenrolled'=>0);
2020 * Removes all grades from gradebook
2021 * @param int $courseid
2022 * @param string optional type
2024 function data_reset_gradebook($courseid, $type='') {
2025 global $CFG;
2026 $sql = "SELECT d.*, cm.idnumber as cmidnumber, d.course as courseid
2027 FROM {$CFG->prefix}data d, {$CFG->prefix}course_modules cm, {$CFG->prefix}modules m
2028 WHERE m.name='data' AND m.id=cm.module AND cm.instance=d.id AND d.course=$courseid";
2029 if ($datas = get_records_sql($sql)) {
2030 foreach ($datas as $data) {
2031 data_grade_item_update($data, 'reset');
2037 * Actual implementation of the rest coures functionality, delete all the
2038 * data responses for course $data->courseid.
2039 * @param $data the data submitted from the reset course.
2040 * @return array status array
2042 function data_reset_userdata($data) {
2043 global $CFG;
2044 require_once($CFG->libdir.'/filelib.php');
2045 $componentstr = get_string('modulenameplural', 'data');
2046 $status = array();
2047 $allrecordssql = "SELECT r.id
2048 FROM {$CFG->prefix}data_records r
2049 INNER JOIN {$CFG->prefix}data d ON r.dataid = d.id
2050 WHERE d.course = {$data->courseid}";
2051 $alldatassql = "SELECT d.id
2052 FROM {$CFG->prefix}data d
2053 WHERE d.course={$data->courseid}";
2054 // delete entries if requested
2055 if (!empty($data->reset_data)) {
2056 delete_records_select('data_ratings', "recordid IN ($allrecordssql)");
2057 delete_records_select('data_comments', "recordid IN ($allrecordssql)");
2058 delete_records_select('data_content', "recordid IN ($allrecordssql)");
2059 delete_records_select('data_records', "dataid IN ($alldatassql)");
2060 if ($datas = get_records_sql($alldatassql)) {
2061 foreach ($datas as $dataid=>$unused) {
2062 fulldelete("$CFG->dataroot/$data->courseid/moddata/data/$dataid");
2065 if (empty($data->reset_gradebook_grades)) {
2066 // remove all grades from gradebook
2067 data_reset_gradebook($data->courseid);
2069 $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallentries', 'data'), 'error'=>false);
2072 // remove entries by users not enrolled into course
2073 if (!empty($data->reset_data_notenrolled)) {
2074 $recordssql = "SELECT r.id, r.userid, r.dataid, u.id AS userexists, u.deleted AS userdeleted
2075 FROM {$CFG->prefix}data_records r
2076 INNER JOIN {$CFG->prefix}data d ON r.dataid = d.id
2077 LEFT OUTER JOIN {$CFG->prefix}user u ON r.userid = u.id
2078 WHERE d.course = {$data->courseid} AND r.userid > 0";
2079 $course_context = get_context_instance(CONTEXT_COURSE, $data->courseid);
2080 $notenrolled = array();
2081 $fields = array();
2082 if ($rs = get_recordset_sql($recordssql)) {
2083 while ($record = rs_fetch_next_record($rs)) {
2084 if (array_key_exists($record->userid, $notenrolled) or !$record->userexists or $record->userdeleted
2085 or !has_capability('moodle/course:view', $course_context , $record->userid)) {
2086 delete_records('data_ratings', 'recordid', $record->id);
2087 delete_records('data_comments', 'recordid', $record->id);
2088 delete_records('data_content', 'recordid', $record->id);
2089 delete_records('data_records', 'id', $record->id);
2090 // HACK: this is ugly - the recordid should be before the fieldid!
2091 if (!array_key_exists($record->dataid, $fields)) {
2092 if ($fs = get_records('data_fields', 'dataid', $record->dataid)) {
2093 $fields[$record->dataid] = array_keys($fs);
2094 } else {
2095 $fields[$record->dataid] = array();
2098 foreach($fields[$record->dataid] as $fieldid) {
2099 fulldelete("$CFG->dataroot/$data->courseid/moddata/data/$record->dataid/$fieldid/$record->id");
2101 $notenrolled[$record->userid] = true;
2104 rs_close($rs);
2105 $status[] = array('component'=>$componentstr, 'item'=>get_string('deletenotenrolled', 'data'), 'error'=>false);
2109 // remove all ratings
2110 if (!empty($data->reset_data_ratings)) {
2111 delete_records_select('data_ratings', "recordid IN ($allrecordssql)");
2112 if (empty($data->reset_gradebook_grades)) {
2113 // remove all grades from gradebook
2114 data_reset_gradebook($data->courseid);
2116 $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallratings'), 'error'=>false);
2119 // remove all comments
2120 if (!empty($data->reset_data_comments)) {
2121 delete_records_select('data_comments', "recordid IN ($allrecordssql)");
2122 $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallcomments'), 'error'=>false);
2125 // updating dates - shift may be negative too
2126 if ($data->timeshift) {
2127 shift_course_mod_dates('data', array('timeavailablefrom', 'timeavailableto', 'timeviewfrom', 'timeviewto'), $data->timeshift, $data->courseid);
2128 $status[] = array('component'=>$componentstr, 'item'=>get_string('datechanged'), 'error'=>false);
2130 return $status;
2134 * Returns all other caps used in module
2136 function data_get_extra_capabilities() {
2137 return array('moodle/site:accessallgroups', 'moodle/site:viewfullnames');