MDL-11517 reserved word MOD used in table alias in questions backup code
[moodle-pu.git] / mod / data / lib.php
blob0f5c6465d2959291f2306042b5cc51cab00671a0
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);
29 class data_field_base { /// Base class for Database Field Types (see field/*/field.class.php)
31 var $type = 'unknown'; /// Subclasses must override the type with their name
32 var $data = NULL; /// The database object that this field belongs to
33 var $field = NULL; /// The field object itself, if we know it
35 var $iconwidth = 16; /// Width of the icon for this fieldtype
36 var $iconheight = 16; /// Width of the icon for this fieldtype
39 /// Constructor function
40 function data_field_base($field=0, $data=0) { // Field or data or both, each can be id or object
42 if (empty($field) && empty($data)) {
43 error('Programmer error: You must specify field and/or data when defining field class. ');
46 if (!empty($field)) {
47 if (is_object($field)) {
48 $this->field = $field; // Programmer knows what they are doing, we hope
49 } else if (!$this->field = get_record('data_fields','id',$field)) {
50 error('Bad field ID encountered: '.$field);
52 if (empty($data)) {
53 if (!$this->data = get_record('data','id',$this->field->dataid)) {
54 error('Bad data ID encountered in field data');
59 if (empty($this->data)) { // We need to define this properly
60 if (!empty($data)) {
61 if (is_object($data)) {
62 $this->data = $data; // Programmer knows what they are doing, we hope
63 } else if (!$this->data = get_record('data','id',$data)) {
64 error('Bad data ID encountered: '.$data);
66 } else { // No way to define it!
67 error('Data id or object must be provided to field class');
71 if (empty($this->field)) { // We need to define some default values
72 $this->define_default_field();
77 /// This field just sets up a default field object
78 function define_default_field() {
79 if (empty($this->data->id)) {
80 notify('Programmer error: dataid not defined in field class');
82 $this->field = new object;
83 $this->field->id = 0;
84 $this->field->dataid = $this->data->id;
85 $this->field->type = $this->type;
86 $this->field->param1 = '';
87 $this->field->param2 = '';
88 $this->field->param3 = '';
89 $this->field->name = '';
90 $this->field->description = '';
92 return true;
95 /// Set up the field object according to data in an object. Now is the time to clean it!
96 function define_field($data) {
97 $this->field->type = $this->type;
98 $this->field->dataid = $this->data->id;
100 $this->field->name = trim($data->name);
101 $this->field->description = trim($data->description);
103 if (isset($data->param1)) {
104 $this->field->param1 = trim($data->param1);
106 if (isset($data->param2)) {
107 $this->field->param2 = trim($data->param2);
109 if (isset($data->param3)) {
110 $this->field->param3 = trim($data->param3);
112 if (isset($data->param4)) {
113 $this->field->param4 = trim($data->param4);
115 if (isset($data->param5)) {
116 $this->field->param5 = trim($data->param5);
119 return true;
122 /// Insert a new field in the database
123 /// We assume the field object is already defined as $this->field
124 function insert_field() {
125 if (empty($this->field)) {
126 notify('Programmer error: Field has not been defined yet! See define_field()');
127 return false;
130 if (!$this->field->id = insert_record('data_fields',$this->field)){
131 notify('Insertion of new field failed!');
132 return false;
134 return true;
138 /// Update a field in the database
139 function update_field() {
140 if (!update_record('data_fields', $this->field)) {
141 notify('updating of new field failed!');
142 return false;
144 return true;
147 /// Delete a field completely
148 function delete_field() {
149 if (!empty($this->field->id)) {
150 delete_records('data_fields', 'id', $this->field->id);
151 $this->delete_content();
153 return true;
156 /// Print the relevant form element in the ADD template for this field
157 function display_add_field($recordid=0){
158 if ($recordid){
159 $content = get_field('data_content', 'content', 'fieldid', $this->field->id, 'recordid', $recordid);
160 } else {
161 $content = '';
164 $str = '<div title="'.s($this->field->description).'">';
165 $str .= '<input style="width:300px;" type="text" name="field_'.$this->field->id.'" id="field_'.$this->field->id.'" value="'.s($content).'" />';
166 $str .= '</div>';
168 return $str;
171 /// Print the relevant form element to define the attributes for this field
172 /// viewable by teachers only.
173 function display_edit_field() {
174 global $CFG;
176 if (empty($this->field)) { // No field has been defined yet, try and make one
177 $this->define_default_field();
179 print_simple_box_start('center','80%');
181 echo '<form id="editfield" action="'.$CFG->wwwroot.'/mod/data/field.php" method="post">'."\n";
182 echo '<input type="hidden" name="d" value="'.$this->data->id.'" />'."\n";
183 if (empty($this->field->id)) {
184 echo '<input type="hidden" name="mode" value="add" />'."\n";
185 $savebutton = get_string('add');
186 } else {
187 echo '<input type="hidden" name="fid" value="'.$this->field->id.'" />'."\n";
188 echo '<input type="hidden" name="mode" value="update" />'."\n";
189 $savebutton = get_string('savechanges');
191 echo '<input type="hidden" name="type" value="'.$this->type.'" />'."\n";
192 echo '<input name="sesskey" value="'.sesskey().'" type="hidden" />'."\n";
194 print_heading($this->name());
196 require_once($CFG->dirroot.'/mod/data/field/'.$this->type.'/mod.html');
198 echo '<div align="center">';
199 echo '<input type="submit" value="'.$savebutton.'" />'."\n";
200 echo '<input type="submit" name="cancel" value="'.get_string('cancel').'" />'."\n";
201 echo '</div>';
203 echo '</form>';
205 print_simple_box_end();
208 /// Display the content of the field in browse mode
209 function display_browse_field($recordid, $template) {
210 if ($content = get_record('data_content','fieldid', $this->field->id, 'recordid', $recordid)) {
211 if (isset($content->content)) {
212 $options = new object();
213 if ($this->field->param1 == '1') { // We are autolinking this field, so disable linking within us
214 //$content->content = '<span class="nolink">'.$content->content.'</span>';
215 //$content->content1 = FORMAT_HTML;
216 $options->filter=false;
218 $options->para = false;
219 $str = format_text($content->content, $content->content1, $options);
220 } else {
221 $str = '';
223 return $str;
225 return false;
228 /// Update the content of one data field in the data_content table
229 function update_content($recordid, $value, $name=''){
230 $content = new object();
231 $content->fieldid = $this->field->id;
232 $content->recordid = $recordid;
233 $content->content = clean_param($value, PARAM_NOTAGS);
235 if ($oldcontent = get_record('data_content','fieldid', $this->field->id, 'recordid', $recordid)) {
236 $content->id = $oldcontent->id;
237 return update_record('data_content', $content);
238 } else {
239 return insert_record('data_content', $content);
243 /// Delete all content associated with the field
244 function delete_content($recordid=0) {
246 $this->delete_content_files($recordid);
248 if ($recordid) {
249 return delete_records('data_content', 'fieldid', $this->field->id, 'recordid', $recordid);
250 } else {
251 return delete_records('data_content', 'fieldid', $this->field->id);
255 /// Deletes any files associated with this field
256 function delete_content_files($recordid='') {
257 global $CFG;
259 require_once($CFG->libdir.'/filelib.php');
261 $dir = $CFG->dataroot.'/'.$this->data->course.'/'.$CFG->moddata.'/data/'.$this->data->id.'/'.$this->field->id;
262 if ($recordid) {
263 $dir .= '/'.$recordid;
266 return fulldelete($dir);
270 /// Check if a field from an add form is empty
271 function notemptyfield($value, $name) {
272 return !empty($value);
275 /// Just in case a field needs to print something before the whole form
276 function print_before_form() {
279 /// Just in case a field needs to print something after the whole form
280 function print_after_form() {
284 /// Returns the sortable field for the content. By default, it's just content
285 /// but for some plugins, it could be content 1 - content4
286 function get_sort_field() {
287 return 'content';
290 /// Returns the SQL needed to refer to the column. Some fields may need to CAST() etc.
291 function get_sort_sql($fieldname) {
292 return $fieldname;
295 /// Returns the name/type of the field
296 function name(){
297 return get_string('name'.$this->type, 'data');
300 /// Prints the respective type icon
301 function image() {
302 global $CFG;
304 $str = '<a href="field.php?d='.$this->data->id.'&amp;fid='.$this->field->id.'&amp;mode=display&amp;sesskey='.sesskey().'">';
305 $str .= '<img src="'.$CFG->modpixpath.'/data/field/'.$this->type.'/icon.gif" ';
306 $str .= 'height="'.$this->iconheight.'" width="'.$this->iconwidth.'" alt="'.$this->type.'" title="'.$this->type.'" /></a>';
307 return $str;
311 } //end of major class data_field_base
315 /*****************************************************************************
316 /* Given a template and a dataid, generate a default case template *
317 * input @param template - addtemplate, singletemplate, listtempalte, rsstemplate*
318 * @param dataid *
319 * output null *
320 *****************************************************************************/
321 function data_generate_default_template(&$data, $template, $recordid=0, $form=false, $update=true) {
323 if (!$data && !$template) {
324 return false;
326 if ($template == 'csstemplate' or $template == 'jstemplate' ) {
327 return '';
330 //get all the fields for that database
331 if ($fields = get_records('data_fields', 'dataid', $data->id, 'id')) {
333 $str = '<div class="defaulttemplate">';
334 $str .= '<table cellpadding="5">';
336 foreach ($fields as $field) {
338 $str .= '<tr><td valign="top" align="right">';
339 // Yu: commenting this out, the id was wrong and will fix later
340 //if ($template == 'addtemplate') {
341 //$str .= '<label';
342 //if (!in_array($field->type, array('picture', 'checkbox', 'date', 'latlong', 'radiobutton'))) {
343 // $str .= ' for="[['.$field->name.'#id]]"';
345 //$str .= '>'.$field->name.'</label>';
347 //} else {
348 $str .= $field->name.': ';
350 $str .= '</td>';
352 $str .='<td>';
353 if ($form) { /// Print forms instead of data
354 $fieldobj = data_get_field($field, $data);
355 $str .= $fieldobj->display_add_field($recordid);
357 } else { /// Just print the tag
358 $str .= '[['.$field->name.']]';
360 $str .= '</td></tr>';
363 if ($template == 'listtemplate') {
364 $str .= '<tr><td align="center" colspan="2">##edit## ##more## ##delete## ##approve##</td></tr>';
365 } else if ($template == 'singletemplate') {
366 $str .= '<tr><td align="center" colspan="2">##edit## ##delete## ##approve##</td></tr>';
369 $str .= '</table>';
370 $str .= '</div>';
372 if ($template == 'listtemplate'){
373 $str .= '<hr />';
376 if ($update) {
377 $newdata = new object();
378 $newdata->id = $data->id;
379 $newdata->{$template} = $str;
380 if (!update_record('data', $newdata)) {
381 notify('Error updating template');
382 } else {
383 $data->{$template} = $str;
387 return $str;
392 /***********************************************************************
393 * Search for a field name and replaces it with another one in all the *
394 * form templates. Set $newfieldname as '' if you want to delete the *
395 * field from the form. *
396 ***********************************************************************/
397 function data_replace_field_in_templates($data, $searchfieldname, $newfieldname) {
398 if (!empty($newfieldname)) {
399 $prestring = '[[';
400 $poststring = ']]';
401 $idpart = '#id';
403 } else {
404 $prestring = '';
405 $poststring = '';
406 $idpart = '';
409 $newdata = new object();
410 $newdata->id = $data->id;
411 $newdata->singletemplate = addslashes(str_ireplace('[['.$searchfieldname.']]',
412 $prestring.$newfieldname.$poststring, $data->singletemplate));
414 $newdata->listtemplate = addslashes(str_ireplace('[['.$searchfieldname.']]',
415 $prestring.$newfieldname.$poststring, $data->listtemplate));
417 $newdata->addtemplate = addslashes(str_ireplace('[['.$searchfieldname.']]',
418 $prestring.$newfieldname.$poststring, $data->addtemplate));
420 $newdata->addtemplate = addslashes(str_ireplace('[['.$searchfieldname.'#id]]',
421 $prestring.$newfieldname.$idpart.$poststring, $data->addtemplate));
423 $newdata->rsstemplate = addslashes(str_ireplace('[['.$searchfieldname.']]',
424 $prestring.$newfieldname.$poststring, $data->rsstemplate));
426 return update_record('data', $newdata);
430 /********************************************************
431 * Appends a new field at the end of the form template. *
432 ********************************************************/
433 function data_append_new_field_to_templates($data, $newfieldname) {
435 $newdata = new object();
436 $newdata->id = $data->id;
437 $change = false;
439 if (!empty($data->singletemplate)) {
440 $newdata->singletemplate = addslashes($data->singletemplate.' [[' . $newfieldname .']]');
441 $change = true;
443 if (!empty($data->addtemplate)) {
444 $newdata->addtemplate = addslashes($data->addtemplate.' [[' . $newfieldname . ']]');
445 $change = true;
447 if (!empty($data->rsstemplate)) {
448 $newdata->rsstemplate = addslashes($data->singletemplate.' [[' . $newfieldname . ']]');
449 $change = true;
451 if ($change) {
452 update_record('data', $newdata);
457 /************************************************************************
458 * given a field name *
459 * this function creates an instance of the particular subfield class *
460 ************************************************************************/
461 function data_get_field_from_name($name, $data){
462 $field = get_record('data_fields','name',$name);
464 if ($field) {
465 return data_get_field($field, $data);
466 } else {
467 return false;
471 /************************************************************************
472 * given a field id *
473 * this function creates an instance of the particular subfield class *
474 ************************************************************************/
475 function data_get_field_from_id($fieldid, $data){
476 $field = get_record('data_fields','id',$fieldid);
478 if ($field) {
479 return data_get_field($field, $data);
480 } else {
481 return false;
485 /************************************************************************
486 * given a field id *
487 * this function creates an instance of the particular subfield class *
488 ************************************************************************/
489 function data_get_field_new($type, $data) {
490 global $CFG;
492 require_once($CFG->dirroot.'/mod/data/field/'.$type.'/field.class.php');
493 $newfield = 'data_field_'.$type;
494 $newfield = new $newfield(0, $data);
495 return $newfield;
498 /************************************************************************
499 * returns a subclass field object given a record of the field, used to *
500 * invoke plugin methods *
501 * input: $param $field - record from db *
502 ************************************************************************/
503 function data_get_field($field, $data) {
504 global $CFG;
506 if ($field) {
507 require_once('field/'.$field->type.'/field.class.php');
508 $newfield = 'data_field_'.$field->type;
509 $newfield = new $newfield($field, $data);
510 return $newfield;
515 /***************************************************************************
516 * given record id, returns true if the record belongs to the current user *
517 * input @param $rid - record id *
518 * output bool *
519 ***************************************************************************/
520 function data_isowner($rid){
521 global $USER;
523 if (empty($USER->id)) {
524 return false;
527 if ($record = get_record('data_records','id',$rid)) {
528 return ($record->userid == $USER->id);
531 return false;
534 /***********************************************************************
535 * has a user reached the max number of entries? *
536 * input object $data *
537 * output bool *
538 ***********************************************************************/
539 function data_atmaxentries($data){
540 if (!$data->maxentries){
541 return false;
543 } else {
544 return (data_numentries($data) >= $data->maxentries);
548 /**********************************************************************
549 * returns the number of entries already made by this user *
550 * input @param object $data *
551 * uses global $CFG, $USER *
552 * output int *
553 **********************************************************************/
554 function data_numentries($data){
555 global $USER;
556 global $CFG;
557 $sql = 'SELECT COUNT(*) FROM '.$CFG->prefix.'data_records WHERE dataid='.$data->id.' AND userid='.$USER->id;
558 return count_records_sql($sql);
561 /****************************************************************
562 * function that takes in a dataid and adds a record *
563 * this is used everytime an add template is submitted *
564 * input @param int $dataid, $groupid *
565 * output bool *
566 ****************************************************************/
567 function data_add_record($data, $groupid=0){
568 global $USER;
570 $cm = get_coursemodule_from_instance('data', $data->id);
571 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
573 $record = new object();
574 $record->userid = $USER->id;
575 $record->dataid = $data->id;
576 $record->groupid = $groupid;
577 $record->timecreated = $record->timemodified = time();
578 if (has_capability('mod/data:approve', $context)) {
579 $record->approved = 1;
580 } else {
581 $record->approved = 0;
583 return insert_record('data_records',$record);
586 /*******************************************************************
587 * check the multple existence any tag in a template *
588 * input @param string *
589 * output true-valid, false-invalid *
590 * check to see if there are 2 or more of the same tag being used. *
591 * input @param int $dataid, *
592 * @param string $template *
593 * output bool *
594 *******************************************************************/
595 function data_tags_check($dataid, $template){
596 //first get all the possible tags
597 $fields = get_records('data_fields','dataid',$dataid);
598 ///then we generate strings to replace
599 $tagsok = true; //let's be optimistic
600 foreach ($fields as $field){
601 $pattern="/\[\[".$field->name."\]\]/i";
602 if (preg_match_all($pattern, $template, $dummy)>1){
603 $tagsok = false;
604 notify ('[['.$field->name.']] - '.get_string('multipletags','data'));
607 //else return true
608 return $tagsok;
611 /************************************************************************
612 * Adds an instance of a data *
613 ************************************************************************/
614 function data_add_instance($data) {
615 global $CFG;
617 if (empty($data->assessed)) {
618 $data->assessed = 0;
621 $data->timemodified = time();
623 if (! $data->id = insert_record('data', $data)) {
624 return false;
627 $data = stripslashes_recursive($data);
628 data_grade_item_update($data);
630 return $data->id;
633 /************************************************************************
634 * updates an instance of a data *
635 ************************************************************************/
636 function data_update_instance($data) {
637 global $CFG;
639 $data->timemodified = time();
640 $data->id = $data->instance;
642 if (empty($data->assessed)) {
643 $data->assessed = 0;
646 if (! update_record('data', $data)) {
647 return false;
650 $data = stripslashes_recursive($data);
651 data_grade_item_update($data);
653 return true;
657 /************************************************************************
658 * deletes an instance of a data *
659 ************************************************************************/
660 function data_delete_instance($id) { //takes the dataid
662 global $CFG;
664 if (! $data = get_record('data', 'id', $id)) {
665 return false;
668 /// Delete all the associated information
670 // get all the records in this data
671 $sql = 'SELECT c.* FROM '.$CFG->prefix.'data_records r LEFT JOIN '.
672 $CFG->prefix.'data_content c ON c.recordid = r.id WHERE r.dataid = '.$id;
674 if ($contents = get_records_sql($sql)){
676 foreach($contents as $content){
678 $field = get_record('data_fields','id',$content->fieldid);
679 if ($g = data_get_field($field, $data)){
680 $g->delete_content_files($id, $content->recordid, $content->content);
682 //delete the content itself
683 delete_records('data_content','id', $content->id);
687 // delete all the records and fields
688 delete_records('data_records', 'dataid', $id);
689 delete_records('data_fields','dataid',$id);
691 // Delete the instance itself
693 $result = delete_records('data', 'id', $id);
695 data_grade_item_delete($data);
697 return $result;
700 /************************************************************************
701 * returns a summary of data activity of this user *
702 ************************************************************************/
703 function data_user_outline($course, $user, $mod, $data) {
705 global $CFG;
707 if ($countrecords = count_records('data_records', 'dataid', $data->id, 'userid', $user->id)) {
708 $result = new object();
709 $result->info = get_string('numrecords', 'data', $countrecords);
710 $lastrecord = get_record_sql('SELECT id,timemodified FROM '.$CFG->prefix.'data_records
711 WHERE dataid = '.$data->id.' AND userid = '.$user->id.'
712 ORDER BY timemodified DESC', true);
713 $result->time = $lastrecord->timemodified;
714 return $result;
716 return NULL;
720 /************************************************************************
721 * Prints all the records uploaded by this user *
722 ************************************************************************/
723 function data_user_complete($course, $user, $mod, $data) {
725 if ($records = get_records_select('data_records', 'dataid = '.$data->id.' AND userid = '.$user->id,
726 'timemodified DESC')) {
728 data_print_template('singletemplate', $records, $data);
734 * Return grade for given user or all users.
736 * @param int $dataid id of data
737 * @param int $userid optional user id, 0 means all users
738 * @return array array of grades, false if none
740 function data_get_user_grades($data, $userid=0) {
741 global $CFG;
743 $user = $userid ? "AND u.id = $userid" : "";
745 $sql = "SELECT u.id, u.id AS userid, avg(drt.rating) AS rawgrade
746 FROM {$CFG->prefix}user u, {$CFG->prefix}data_records dr,
747 {$CFG->prefix}data_ratings drt
748 WHERE u.id = dr.userid AND dr.id = drt.recordid
749 AND drt.userid != u.id AND dr.dataid = $data->id
750 $user
751 GROUP BY u.id";
753 return get_records_sql($sql);
757 * Update grades by firing grade_updated event
759 * @param object $data null means all databases
760 * @param int $userid specific user only, 0 mean all
762 function data_update_grades($data=null, $userid=0, $nullifnone=true) {
763 global $CFG;
764 if (!function_exists('grade_update')) { //workaround for buggy PHP versions
765 require_once($CFG->libdir.'/gradelib.php');
768 if ($data != null) {
769 if ($grades = data_get_user_grades($data, $userid)) {
770 grade_update('mod/data', $data->course, 'mod', 'data', $data->id, 0, $grades);
772 } else if ($userid and $nullifnone) {
773 $grade = new object();
774 $grade->userid = $userid;
775 $grade->rawgrade = NULL;
776 grade_update('mod/data', $data->course, 'mod', 'data', $data->id, 0, $grade);
779 } else {
780 $sql = "SELECT d.*, cm.idnumber as cmidnumber
781 FROM {$CFG->prefix}data d, {$CFG->prefix}course_modules cm, {$CFG->prefix}modules m
782 WHERE m.name='data' AND m.id=cm.module AND cm.instance=d.id";
783 if ($rs = get_recordset_sql($sql)) {
784 if ($rs->RecordCount() > 0) {
785 while ($data = rs_fetch_next_record($rs)) {
786 data_grade_item_update($data);
787 if ($data->assessed) {
788 data_update_grades($data, 0, false);
792 rs_close($rs);
798 * Update/create grade item for given data
800 * @param object $data object with extra cmidnumber
801 * @return object grade_item
803 function data_grade_item_update($data) {
804 global $CFG;
805 if (!function_exists('grade_update')) { //workaround for buggy PHP versions
806 require_once($CFG->libdir.'/gradelib.php');
809 $params = array('itemname'=>$data->name, 'idnumber'=>$data->cmidnumber);
811 if (!$data->assessed or $data->scale == 0) {
812 $params['gradetype'] = GRADE_TYPE_NONE;
814 } else if ($data->scale > 0) {
815 $params['gradetype'] = GRADE_TYPE_VALUE;
816 $params['grademax'] = $data->scale;
817 $params['grademin'] = 0;
819 } else if ($data->scale < 0) {
820 $params['gradetype'] = GRADE_TYPE_SCALE;
821 $params['scaleid'] = -$data->scale;
824 return grade_update('mod/data', $data->course, 'mod', 'data', $data->id, 0, NULL, $params);
828 * Delete grade item for given data
830 * @param object $data object
831 * @return object grade_item
833 function data_grade_item_delete($data) {
834 global $CFG;
835 require_once($CFG->libdir.'/gradelib.php');
837 return grade_update('mod/data', $data->course, 'mod', 'data', $data->id, 0, NULL, array('deleted'=>1));
840 /************************************************************************
841 * returns a list of participants of this database *
842 ************************************************************************/
843 function data_get_participants($dataid) {
844 //Returns the users with data in one data
845 //(users with records in data_records, data_comments and data_ratings)
846 global $CFG;
848 $records = get_records_sql("SELECT DISTINCT u.id, u.id
849 FROM {$CFG->prefix}user u,
850 {$CFG->prefix}data_records r
851 WHERE r.dataid = '$dataid'
852 AND u.id = r.userid");
854 $comments = get_records_sql("SELECT DISTINCT u.id, u.id
855 FROM {$CFG->prefix}user u,
856 {$CFG->prefix}data_records r,
857 {$CFG->prefix}data_comments c
858 WHERE r.dataid = '$dataid'
859 AND u.id = r.userid
860 AND r.id = c.recordid");
862 $ratings = get_records_sql("SELECT DISTINCT u.id, u.id
863 FROM {$CFG->prefix}user u,
864 {$CFG->prefix}data_records r,
865 {$CFG->prefix}data_ratings a
866 WHERE r.dataid = '$dataid'
867 AND u.id = r.userid
868 AND r.id = a.recordid");
869 $participants = array();
871 if ($records){
872 foreach ($records as $record) {
873 $participants[$record->id] = $record;
876 if ($comments){
877 foreach ($comments as $comment) {
878 $participants[$comment->id] = $comment;
881 if ($ratings){
882 foreach ($ratings as $rating) {
883 $participants[$rating->id] = $rating;
887 return $participants;
890 function data_get_coursemodule_info($coursemodule) {
891 /// Given a course_module object, this function returns any
892 /// "extra" information that may be needed when printing
893 /// this activity in a course listing.
895 /// See get_array_of_activities() in course/lib.php
898 global $CFG;
900 $info = NULL;
902 return $info;
905 ///junk functions
906 /************************************************************************
907 * takes a list of records, the current data, a search string, *
908 * and mode to display prints the translated template *
909 * input @param array $records *
910 * @param object $data *
911 * @param string $search *
912 * @param string $template *
913 * output null *
914 ************************************************************************/
915 function data_print_template($template, $records, $data, $search='',$page=0, $return=false) {
916 global $CFG;
918 $cm = get_coursemodule_from_instance('data', $data->id);
919 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
921 static $fields = NULL;
922 static $isteacher;
923 static $dataid = NULL;
925 if (empty($dataid)) {
926 $dataid = $data->id;
927 } else if ($dataid != $data->id) {
928 $fields = NULL;
931 if (empty($fields)) {
932 $fieldrecords = get_records('data_fields','dataid', $data->id);
933 foreach ($fieldrecords as $fieldrecord) {
934 $fields[]= data_get_field($fieldrecord, $data);
936 $isteacher = has_capability('mod/data:managetemplates', $context);
939 if (empty($records)) {
940 return;
943 foreach ($records as $record) { /// Might be just one for the single template
945 /// Replacing tags
946 $patterns = array();
947 $replacement = array();
949 /// Then we generate strings to replace for normal tags
950 foreach ($fields as $field) {
951 $patterns[]='[['.$field->field->name.']]';
952 $replacement[] = highlight($search, $field->display_browse_field($record->id, $template));
955 /// Replacing special tags (##Edit##, ##Delete##, ##More##)
956 $patterns[]='##edit##';
957 $patterns[]='##delete##';
958 if (has_capability('mod/data:manageentries', $context) or data_isowner($record->id)) {
959 $replacement[] = '<a href="'.$CFG->wwwroot.'/mod/data/edit.php?d='
960 .$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>';
961 $replacement[] = '<a href="'.$CFG->wwwroot.'/mod/data/view.php?d='
962 .$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>';
963 } else {
964 $replacement[] = '';
965 $replacement[] = '';
967 $patterns[]='##more##';
968 $replacement[] = '<a href="'.$CFG->wwwroot.'/mod/data/view.php?d='.$data->id.'&amp;rid='.$record->id.'"><img src="'.$CFG->pixpath.'/i/search.gif" class="iconsmall" alt="'.get_string('more', 'data').'" title="'.get_string('more', 'data').'" /></a>';
970 $patterns[]='##moreurl##';
971 $replacement[] = $CFG->wwwroot.'/mod/data/view.php?d='.$data->id.'&amp;rid='.$record->id;
973 $patterns[]='##user##';
974 $replacement[] = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$record->userid.
975 '&amp;course='.$data->course.'">'.fullname($record).'</a>';
977 $patterns[]='##approve##';
978 if (has_capability('mod/data:approve', $context) && ($data->approval) && (!$record->approved)){
979 $replacement[] = '<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="iconsmall" alt="'.get_string('approve').'" /></a>';
980 } else {
981 $replacement[] = '';
984 $patterns[]='##comments##';
985 if (($template == 'listtemplate') && ($data->comments)) {
986 $comments = count_records('data_comments','recordid',$record->id);
987 $replacement[] = '<a href="view.php?rid='.$record->id.'#comments">'.get_string('commentsn','data', $comments).'</a>';
988 } else {
989 $replacement[] = '';
992 ///actual replacement of the tags
993 $newtext = str_ireplace($patterns, $replacement, $data->{$template});
995 /// no more html formatting and filtering - see MDL-6635
996 if ($return) {
997 return $newtext;
998 } else {
999 echo $newtext;
1001 // hack alert - return is always false in singletemplate anyway ;-)
1002 /**********************************
1003 * Printing Ratings Form *
1004 *********************************/
1005 if ($template == 'singletemplate') { //prints ratings options
1006 data_print_ratings($data, $record);
1009 /**********************************
1010 * Printing Ratings Form *
1011 *********************************/
1012 if (($template == 'singletemplate') && ($data->comments)) { //prints ratings options
1014 data_print_comments($data, $record, $page);
1021 /************************************************************************
1022 * function that takes in the current data, number of items per page, *
1023 * a search string and prints a preference box in view.php *
1025 * This preference box prints a searchable advanced search template if *
1026 * a) A template is defined *
1027 * b) The advanced search checkbox is checked. *
1029 * input @param object $data *
1030 * @param int $perpage *
1031 * @param string $search *
1032 * output null *
1033 ************************************************************************/
1034 function data_print_preference_form($data, $perpage, $search, $sort='', $order='ASC', $search_array = '', $advanced = 0, $mode= ''){
1035 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 $fields = get_records('data_fields','dataid',$data->id, 'name');
1062 echo '<select name="sort" id="pref_sortby"><option value="0">'.get_string('dateentered','data').'</option>';
1063 foreach ($fields as $field) {
1064 if ($field->id == $sort) {
1065 echo '<option value="'.$field->id.'" selected="selected">'.$field->name.'</option>';
1066 } else {
1067 echo '<option value="'.$field->id.'">'.$field->name.'</option>';
1070 echo '</select>';
1071 echo '<label for="pref_order" class="accesshide">'.get_string('order').'</label>';
1072 echo '<select id="pref_order" name="order">';
1073 if ($order == 'ASC') {
1074 echo '<option value="ASC" selected="selected">'.get_string('ascending','data').'</option>';
1075 } else {
1076 echo '<option value="ASC">'.get_string('ascending','data').'</option>';
1078 if ($order == 'DESC') {
1079 echo '<option value="DESC" selected="selected">'.get_string('descending','data').'</option>';
1080 } else {
1081 echo '<option value="DESC">'.get_string('descending','data').'</option>';
1083 echo '</select>';
1085 if ($advanced) {
1086 $checked = ' checked="checked" ';
1088 else {
1089 $checked = '';
1091 print '
1093 <script type="text/javascript">
1094 //<![CDATA[
1095 <!-- Start
1096 // javascript for hiding/displaying advanced search form
1098 function showHideAdvSearch(checked) {
1099 var divs = document.getElementsByTagName(\'div\');
1100 for(i=0;i<divs.length;i++) {
1101 if(divs[i].id.match(\'data_adv_form\')) {
1102 if(checked) {
1103 divs[i].style.display = \'inline\';
1105 else {
1106 divs[i].style.display = \'none\';
1109 else if (divs[i].id.match(\'reg_search\')) {
1110 if (!checked) {
1111 divs[i].style.display = \'inline\';
1113 else {
1114 divs[i].style.display = \'none\';
1119 // End -->
1120 //]]>
1121 </script>';
1122 echo '&nbsp;<input type="checkbox" name="advanced" value="1" '.$checked.' onchange="showHideAdvSearch(this.checked);" />'.get_string('advancedsearch', 'data');
1123 echo '&nbsp;<input type="submit" value="'.get_string('savesettings','data').'" />';
1125 echo '<br />';
1126 echo '<div class="dataadvancedsearch" id="data_adv_form" style="display: ';
1128 if ($advanced) {
1129 echo 'inline';
1131 else {
1132 echo 'none';
1134 echo ';margin-left:auto;margin-right:auto;" >';
1135 echo '<table class="boxaligncenter">';
1137 // print ASC or DESC
1138 echo '<tr><td colspan="2">&nbsp;</td></tr>';
1139 $i = 0;
1141 // Determine if we are printing all fields for advanced search, or the template for advanced search
1142 // If a template is not defined, use the deafault template and display all fields.
1143 if(empty($data->asearchtemplate)) {
1144 data_generate_default_template($data, 'asearchtemplate');
1147 static $fields = NULL;
1148 static $isteacher;
1149 static $dataid = NULL;
1151 if (empty($dataid)) {
1152 $dataid = $data->id;
1153 } else if ($dataid != $data->id) {
1154 $fields = NULL;
1157 if (empty($fields)) {
1158 $fieldrecords = get_records('data_fields','dataid', $data->id);
1159 foreach ($fieldrecords as $fieldrecord) {
1160 $fields[]= data_get_field($fieldrecord, $data);
1163 $isteacher = has_capability('mod/data:managetemplates', $context);
1166 /// Replacing tags
1167 $patterns = array();
1168 $replacement = array();
1170 /// Then we generate strings to replace for normal tags
1171 foreach ($fields as $field) {
1172 $patterns[]='/\[\['.$field->field->name.'\]\]/i';
1173 $searchfield = data_get_field_from_id($field->field->id, $data);
1174 if (!empty($search_array[$field->field->id]->data)) {
1175 $replacement[] = $searchfield->display_search_field($search_array[$field->field->id]->data);
1176 } else {
1177 $replacement[] = $searchfield->display_search_field();
1181 ///actual replacement of the tags
1182 $newtext = preg_replace($patterns, $replacement, $data->asearchtemplate);
1183 $options = new object();
1184 $options->para=false;
1185 $options->noclean=true;
1186 echo '<tr><td>';
1187 echo format_text($newtext, FORMAT_HTML, $options);
1188 echo '</td></tr>';
1190 echo '<tr><td colspan="4" style="text-align: center;"><br/><input type="submit" value="'.get_string('savesettings','data').'" /><input type="reset" value="'.get_string('resetsettings','data').'" /></td></tr>';
1191 echo '</table>';
1192 echo '</div>';
1193 echo '</div>';
1194 echo '</form>';
1195 echo '</div>';
1200 function data_print_ratings($data, $record) {
1201 global $USER;
1203 $cm = get_coursemodule_from_instance('data', $data->id);
1204 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1206 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))) {
1207 if ($ratingsscale = make_grades_menu($data->scale)) {
1208 $ratingsmenuused = false;
1210 echo '<div class="ratings" style="text-align:center">';
1211 echo '<form id="form" method="post" action="rate.php">';
1212 echo '<input type="hidden" name="dataid" value="'.$data->id.'" />';
1214 if (has_capability('mod/data:rate', $context) and !data_isowner($record->id)) {
1215 data_print_ratings_mean($record->id, $ratingsscale, has_capability('mod/data:viewrating', $context));
1216 echo '&nbsp;';
1217 data_print_rating_menu($record->id, $USER->id, $ratingsscale);
1218 $ratingsmenuused = true;
1220 } else {
1221 data_print_ratings_mean($record->id, $ratingsscale, true);
1224 if ($data->scale < 0) {
1225 if ($scale = get_record('scale', 'id', abs($data->scale))) {
1226 print_scale_menu_helpbutton($data->course, $scale );
1230 if ($ratingsmenuused) {
1231 echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
1232 echo '<input type="submit" value="'.get_string('sendinratings', 'data').'" />';
1234 echo '</form>';
1235 echo '</div>';
1240 function data_print_ratings_mean($recordid, $scale, $link=true) {
1241 /// Print the multiple ratings on a post given to the current user by others.
1242 /// Scale is an array of ratings
1244 static $strrate;
1246 $mean = data_get_ratings_mean($recordid, $scale);
1248 if ($mean !== "") {
1250 if (empty($strratings)) {
1251 $strratings = get_string("ratings", "data");
1254 echo "$strratings: ";
1255 if ($link) {
1256 link_to_popup_window ("/mod/data/report.php?id=$recordid", "ratings", $mean, 400, 600);
1257 } else {
1258 echo "$mean ";
1264 function data_get_ratings_mean($recordid, $scale, $ratings=NULL) {
1265 /// Return the mean rating of a post given to the current user by others.
1266 /// Scale is an array of possible ratings in the scale
1267 /// Ratings is an optional simple array of actual ratings (just integers)
1269 if (!$ratings) {
1270 $ratings = array();
1271 if ($rates = get_records("data_ratings", "recordid", $recordid)) {
1272 foreach ($rates as $rate) {
1273 $ratings[] = $rate->rating;
1278 $count = count($ratings);
1280 if ($count == 0) {
1281 return "";
1283 } else if ($count == 1) {
1284 return $scale[$ratings[0]];
1286 } else {
1287 $total = 0;
1288 foreach ($ratings as $rating) {
1289 $total += $rating;
1291 $mean = round( ((float)$total/(float)$count) + 0.001); // Little fudge factor so that 0.5 goes UP
1293 if (isset($scale[$mean])) {
1294 return $scale[$mean]." ($count)";
1295 } else {
1296 return "$mean ($count)"; // Should never happen, hopefully
1302 function data_print_rating_menu($recordid, $userid, $scale) {
1303 /// Print the menu of ratings as part of a larger form.
1304 /// If the post has already been - set that value.
1305 /// Scale is an array of ratings
1307 static $strrate;
1309 if (!$rating = get_record("data_ratings", "userid", $userid, "recordid", $recordid)) {
1310 $rating->rating = -999;
1313 if (empty($strrate)) {
1314 $strrate = get_string("rate", "data");
1317 choose_from_menu($scale, $recordid, $rating->rating, "$strrate...", '', -999);
1321 function data_get_ratings($recordid, $sort="u.firstname ASC") {
1322 /// Returns a list of ratings for a particular post - sorted.
1323 global $CFG;
1324 return get_records_sql("SELECT u.*, r.rating
1325 FROM {$CFG->prefix}data_ratings r,
1326 {$CFG->prefix}user u
1327 WHERE r.recordid = $recordid
1328 AND r.userid = u.id
1329 ORDER BY $sort");
1334 //prints all comments + a text box for adding additional comment
1335 function data_print_comments($data, $record, $page=0, $mform=false) {
1337 global $CFG;
1339 echo '<a name="comments"></a>';
1341 if ($comments = get_records('data_comments','recordid',$record->id)) {
1342 foreach ($comments as $comment) {
1343 data_print_comment($data, $comment, $page);
1345 echo '<br />';
1348 if (!isloggedin() or isguest()) {
1349 return;
1352 $editor = optional_param('addcomment', 0, PARAM_BOOL);
1354 if (!$mform and !$editor) {
1355 echo '<div class="newcomment" style="text-align:center">';
1356 echo '<a href="view.php?d='.$data->id.'&amp;page='.$page.'&amp;mode=single&amp;addcomment=1">'.get_string('addcomment', 'data').'</a>';
1357 echo '</div>';
1358 } else {
1359 if (!$mform) {
1360 require_once('comment_form.php');
1361 $mform = new mod_data_comment_form('comment.php');
1362 $mform->set_data(array('mode'=>'add', 'page'=>$page, 'rid'=>$record->id));
1364 echo '<div class="newcomment" style="text-align:center">';
1365 $mform->display();
1366 echo '</div>';
1370 //prints a single comment entry
1371 function data_print_comment($data, $comment, $page=0) {
1373 global $USER, $CFG;
1375 $cm = get_coursemodule_from_instance('data', $data->id);
1376 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1378 $stredit = get_string('edit');
1379 $strdelete = get_string('delete');
1381 $user = get_record('user','id',$comment->userid);
1383 echo '<table cellspacing="0" align="center" width="50%" class="datacomment forumpost">';
1385 echo '<tr class="header"><td class="picture left">';
1386 print_user_picture($comment->userid, $data->course, $user->picture);
1387 echo '</td>';
1389 echo '<td class="topic starter" align="left"><div class="author">';
1390 $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context));
1391 $by = new object();
1392 $by->name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.
1393 $user->id.'&amp;course='.$data->course.'">'.$fullname.'</a>';
1394 $by->date = userdate($comment->modified);
1395 print_string('bynameondate', 'data', $by);
1396 echo '</div></td></tr>';
1398 echo '<tr><td class="left side">';
1399 if ($groups = groups_get_all_groups($data->course, $comment->userid, $cm->groupingid)) {
1400 print_group_picture($groups, $data->course, false, false, true);
1401 } else {
1402 echo '&nbsp;';
1405 /// Actual content
1407 echo '</td><td class="content" align="left">'."\n";
1409 // Print whole message
1410 echo format_text($comment->content, $comment->format);
1412 /// Commands
1414 echo '<div class="commands">';
1415 if (data_isowner($comment->recordid) or has_capability('mod/data:managecomments', $context)) {
1416 echo '<a href="'.$CFG->wwwroot.'/mod/data/comment.php?rid='.$comment->recordid.'&amp;mode=edit&amp;commentid='.$comment->id.'&amp;page='.$page.'">'.$stredit.'</a>';
1417 echo '| <a href="'.$CFG->wwwroot.'/mod/data/comment.php?rid='.$comment->recordid.'&amp;mode=delete&amp;commentid='.$comment->id.'&amp;page='.$page.'">'.$strdelete.'</a>';
1420 echo '</div>';
1422 echo '</td></tr></table>'."\n\n";
1426 // For Participantion Reports
1427 function data_get_view_actions() {
1428 return array('view');
1431 function data_get_post_actions() {
1432 return array('add','update','record delete');
1435 function data_fieldname_exists($name, $dataid, $fieldid=0) {
1436 global $CFG;
1438 $LIKE = sql_ilike();
1439 if ($fieldid) {
1440 return record_exists_sql("SELECT * from {$CFG->prefix}data_fields df
1441 WHERE df.name $LIKE '$name' AND df.dataid = $dataid
1442 AND ((df.id < $fieldid) OR (df.id > $fieldid))");
1443 } else {
1444 return record_exists_sql("SELECT * from {$CFG->prefix}data_fields df
1445 WHERE df.name $LIKE '$name' AND df.dataid = $dataid");
1449 function data_convert_arrays_to_strings(&$fieldinput) {
1450 foreach ($fieldinput as $key => $val) {
1451 if (is_array($val)) {
1452 $str = '';
1453 foreach ($val as $inner) {
1454 $str .= $inner . ',';
1456 $str = substr($str, 0, -1);
1458 $fieldinput->$key = $str;
1465 * Converts a database (module instance) to use the Roles System
1466 * @param $data - a data object with the same attributes as a record
1467 * from the data database table
1468 * @param $datamodid - the id of the data module, from the modules table
1469 * @param $teacherroles - array of roles that have moodle/legacy:teacher
1470 * @param $studentroles - array of roles that have moodle/legacy:student
1471 * @param $guestroles - array of roles that have moodle/legacy:guest
1472 * @param $cmid - the course_module id for this data instance
1473 * @return boolean - data module was converted or not
1475 function data_convert_to_roles($data, $teacherroles=array(), $studentroles=array(), $cmid=NULL) {
1477 global $CFG;
1479 if (!isset($data->participants) && !isset($data->assesspublic)
1480 && !isset($data->groupmode)) {
1481 // We assume that this database has already been converted to use the
1482 // Roles System. above fields get dropped the data module has been
1483 // upgraded to use Roles.
1484 return false;
1487 if (empty($cmid)) {
1488 // We were not given the course_module id. Try to find it.
1489 if (!$cm = get_coursemodule_from_instance('data', $data->id)) {
1490 notify('Could not get the course module for the data');
1491 return false;
1492 } else {
1493 $cmid = $cm->id;
1496 $context = get_context_instance(CONTEXT_MODULE, $cmid);
1499 // $data->participants:
1500 // 1 - Only teachers can add entries
1501 // 3 - Teachers and students can add entries
1502 switch ($data->participants) {
1503 case 1:
1504 foreach ($studentroles as $studentrole) {
1505 assign_capability('mod/data:writeentry', CAP_PREVENT, $studentrole->id, $context->id);
1507 foreach ($teacherroles as $teacherrole) {
1508 assign_capability('mod/data:writeentry', CAP_ALLOW, $teacherrole->id, $context->id);
1510 break;
1511 case 3:
1512 foreach ($studentroles as $studentrole) {
1513 assign_capability('mod/data:writeentry', CAP_ALLOW, $studentrole->id, $context->id);
1515 foreach ($teacherroles as $teacherrole) {
1516 assign_capability('mod/data:writeentry', CAP_ALLOW, $teacherrole->id, $context->id);
1518 break;
1521 // $data->assessed:
1522 // 2 - Only teachers can rate posts
1523 // 1 - Everyone can rate posts
1524 // 0 - No one can rate posts
1525 switch ($data->assessed) {
1526 case 0:
1527 foreach ($studentroles as $studentrole) {
1528 assign_capability('mod/data:rate', CAP_PREVENT, $studentrole->id, $context->id);
1530 foreach ($teacherroles as $teacherrole) {
1531 assign_capability('mod/data:rate', CAP_PREVENT, $teacherrole->id, $context->id);
1533 break;
1534 case 1:
1535 foreach ($studentroles as $studentrole) {
1536 assign_capability('mod/data:rate', CAP_ALLOW, $studentrole->id, $context->id);
1538 foreach ($teacherroles as $teacherrole) {
1539 assign_capability('mod/data:rate', CAP_ALLOW, $teacherrole->id, $context->id);
1541 break;
1542 case 2:
1543 foreach ($studentroles as $studentrole) {
1544 assign_capability('mod/data:rate', CAP_PREVENT, $studentrole->id, $context->id);
1546 foreach ($teacherroles as $teacherrole) {
1547 assign_capability('mod/data:rate', CAP_ALLOW, $teacherrole->id, $context->id);
1549 break;
1552 // $data->assesspublic:
1553 // 0 - Students can only see their own ratings
1554 // 1 - Students can see everyone's ratings
1555 switch ($data->assesspublic) {
1556 case 0:
1557 foreach ($studentroles as $studentrole) {
1558 assign_capability('mod/data:viewrating', CAP_PREVENT, $studentrole->id, $context->id);
1560 foreach ($teacherroles as $teacherrole) {
1561 assign_capability('mod/data:viewrating', CAP_ALLOW, $teacherrole->id, $context->id);
1563 break;
1564 case 1:
1565 foreach ($studentroles as $studentrole) {
1566 assign_capability('mod/data:viewrating', CAP_ALLOW, $studentrole->id, $context->id);
1568 foreach ($teacherroles as $teacherrole) {
1569 assign_capability('mod/data:viewrating', CAP_ALLOW, $teacherrole->id, $context->id);
1571 break;
1574 if (empty($cm)) {
1575 $cm = get_record('course_modules', 'id', $cmid);
1578 switch ($cm->groupmode) {
1579 case NOGROUPS:
1580 break;
1581 case SEPARATEGROUPS:
1582 foreach ($studentroles as $studentrole) {
1583 assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $studentrole->id, $context->id);
1585 foreach ($teacherroles as $teacherrole) {
1586 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $teacherrole->id, $context->id);
1588 break;
1589 case VISIBLEGROUPS:
1590 foreach ($studentroles as $studentrole) {
1591 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $studentrole->id, $context->id);
1593 foreach ($teacherroles as $teacherrole) {
1594 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $teacherrole->id, $context->id);
1596 break;
1598 return true;
1602 * Returns the best name to show for a preset
1604 function data_preset_name($shortname, $path) {
1606 /// We are looking inside the preset itself as a first choice, but also in normal data directory
1607 $string = get_string('modulename', 'datapreset_'.$shortname);
1609 if (substr($string, 0, 1) == '[') {
1610 return $shortname;
1611 } else {
1612 return $string;
1617 * Returns an array of all the available presets
1619 function data_get_available_presets($context) {
1620 global $CFG, $USER;
1622 $presets = array();
1624 if ($dirs = get_list_of_plugins('mod/data/preset')) {
1625 foreach ($dirs as $dir) {
1626 $fulldir = $CFG->dirroot.'/mod/data/preset/'.$dir;
1628 if (is_directory_a_preset($fulldir)) {
1629 $preset = new object;
1630 $preset->path = $fulldir;
1631 $preset->userid = 0;
1632 $preset->shortname = $dir;
1633 $preset->name = data_preset_name($dir, $fulldir);
1634 if (file_exists($fulldir.'/screenshot.jpg')) {
1635 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.jpg';
1636 } else if (file_exists($fulldir.'/screenshot.png')) {
1637 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.png';
1638 } else if (file_exists($fulldir.'/screenshot.gif')) {
1639 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.gif';
1641 $presets[] = $preset;
1646 if ($userids = get_list_of_plugins('data/preset', '', $CFG->dataroot)) {
1647 foreach ($userids as $userid) {
1648 $fulldir = $CFG->dataroot.'/data/preset/'.$userid;
1650 if ($userid == 0 || $USER->id == $userid || has_capability('mod/data:viewalluserpresets', $context)) {
1652 if ($dirs = get_list_of_plugins('data/preset/'.$userid, '', $CFG->dataroot)) {
1653 foreach ($dirs as $dir) {
1654 $fulldir = $CFG->dataroot.'/data/preset/'.$userid.'/'.$dir;
1656 if (is_directory_a_preset($fulldir)) {
1657 $preset = new object;
1658 $preset->path = $fulldir;
1659 $preset->userid = $userid;
1660 $preset->shortname = $dir;
1661 $preset->name = data_preset_name($dir, $fulldir);
1662 if (file_exists($fulldir.'/screenshot.jpg')) {
1663 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.jpg';
1664 } else if (file_exists($fulldir.'/screenshot.png')) {
1665 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.png';
1666 } else if (file_exists($fulldir.'/screenshot.gif')) {
1667 $preset->screenshot = $CFG->wwwroot.'/mod/data/preset/'.$dir.'/screenshot.gif';
1669 $presets[] = $preset;
1677 return $presets;
1681 function data_print_header($course, $cm, $data, $currenttab='') {
1683 global $CFG, $displaynoticegood, $displaynoticebad;
1685 $strdata = get_string('modulenameplural','data');
1687 $navlinks = array();
1688 $navlinks[] = array('name' => $strdata, 'link' => "index.php?id=$course->id", 'type' => 'activity');
1689 $navlinks[] = array('name' => $data->name, 'link' => '', 'type' => 'activityinstance');
1691 $navigation = build_navigation($navlinks);
1693 print_header_simple($data->name, '', $navigation,
1694 '', '', true, update_module_button($cm->id, $course->id, get_string('modulename', 'data')),
1695 navmenu($course, $cm));
1697 print_heading(format_string($data->name));
1699 /// Groups needed for Add entry tab
1700 $currentgroup = groups_get_activity_group($cm);
1701 $groupmode = groups_get_activity_groupmode($cm);
1703 /// Print the tabs
1705 if ($currenttab) {
1706 include('tabs.php');
1709 /// Print any notices
1711 if (!empty($displaynoticegood)) {
1712 notify($displaynoticegood, 'notifysuccess'); // good (usually green)
1713 } else if (!empty($displaynoticebad)) {
1714 notify($displaynoticebad); // bad (usuually red)
1718 function data_user_can_add_entry($data, $currentgroup, $groupmode) {
1719 global $USER;
1721 if (!$cm = get_coursemodule_from_instance('data', $data->id)) {
1722 error('Course Module ID was incorrect');
1724 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1726 if (!has_capability('mod/data:writeentry', $context) and !has_capability('mod/data:manageentries',$context)) {
1727 return false;
1730 if (!$groupmode or has_capability('moodle/site:accessallgroups', $context)) {
1731 return true;
1734 if ($currentgroup) {
1735 return groups_is_member($currentgroup);
1736 } else {
1737 //else it might be group 0 in visible mode
1738 if ($groupmode == VISIBLEGROUPS){
1739 return true;
1740 } else {
1741 return false;
1746 // pulled directly out of preset.php Penny 20070426
1748 function is_directory_a_preset($directory) {
1749 $directory = rtrim($directory, '/\\') . '/';
1750 if (file_exists($directory.'singletemplate.html') &&
1751 file_exists($directory.'listtemplate.html') &&
1752 file_exists($directory.'listtemplateheader.html') &&
1753 file_exists($directory.'listtemplatefooter.html') &&
1754 file_exists($directory.'addtemplate.html') &&
1755 file_exists($directory.'rsstemplate.html') &&
1756 file_exists($directory.'rsstitletemplate.html') &&
1757 file_exists($directory.'csstemplate.css') &&
1758 file_exists($directory.'jstemplate.js') &&
1759 file_exists($directory.'preset.xml')) return true;
1760 else return false;
1764 function clean_preset($folder) {
1765 if (@unlink($folder.'/singletemplate.html') &&
1766 @unlink($folder.'/listtemplate.html') &&
1767 @unlink($folder.'/listtemplateheader.html') &&
1768 @unlink($folder.'/listtemplatefooter.html') &&
1769 @unlink($folder.'/addtemplate.html') &&
1770 @unlink($folder.'/rsstemplate.html') &&
1771 @unlink($folder.'/rsstitletemplate.html') &&
1772 @unlink($folder.'/csstemplate.css') &&
1773 @unlink($folder.'/jstemplate.js') &&
1774 @unlink($folder.'/preset.xml')) {
1775 return true;
1777 return false;
1781 function data_presets_export($course, $cm, $data) {
1782 global $CFG;
1784 /* Info Collected. Now need to make files in moodledata/temp */
1785 $tempfolder = $CFG->dataroot.'/temp';
1786 $singletemplate = fopen($tempfolder.'/singletemplate.html', 'w');
1787 $listtemplate = fopen($tempfolder.'/listtemplate.html', 'w');
1788 $listtemplateheader = fopen($tempfolder.'/listtemplateheader.html', 'w');
1789 $listtemplatefooter = fopen($tempfolder.'/listtemplatefooter.html', 'w');
1790 $addtemplate = fopen($tempfolder.'/addtemplate.html', 'w');
1791 $rsstemplate = fopen($tempfolder.'/rsstemplate.html', 'w');
1792 $rsstitletemplate = fopen($tempfolder.'/rsstitletemplate.html', 'w');
1793 $csstemplate = fopen($tempfolder.'/csstemplate.css', 'w');
1794 $jstemplate = fopen($tempfolder.'/jstemplate.js', 'w');
1796 fwrite($singletemplate, $data->singletemplate);
1797 fwrite($listtemplate, $data->listtemplate);
1798 fwrite($listtemplateheader, $data->listtemplateheader);
1799 fwrite($listtemplatefooter, $data->listtemplatefooter);
1800 fwrite($addtemplate, $data->addtemplate);
1801 fwrite($rsstemplate, $data->rsstemplate);
1802 fwrite($rsstitletemplate, $data->rsstitletemplate);
1803 fwrite($csstemplate, $data->csstemplate);
1804 fwrite($jstemplate, $data->jstemplate);
1806 fclose($singletemplate);
1807 fclose($listtemplate);
1808 fclose($listtemplateheader);
1809 fclose($listtemplatefooter);
1810 fclose($addtemplate);
1811 fclose($rsstemplate);
1812 fclose($rsstitletemplate);
1813 fclose($csstemplate);
1814 fclose($jstemplate);
1816 /* All the display data is now done. Now assemble preset.xml */
1817 $fields = get_records('data_fields', 'dataid', $data->id);
1818 $presetfile = fopen($tempfolder.'/preset.xml', 'w');
1819 $presetxml = "<preset>\n\n";
1821 /* Database settings first. Name not included? */
1822 $settingssaved = array('intro', 'comments',
1823 'requiredentries', 'requiredentriestoview', 'maxentries',
1824 'rssarticles', 'approval', 'scale', 'assessed',
1825 'defaultsort', 'defaultsortdir', 'editany');
1827 $presetxml .= "<settings>\n";
1828 foreach ($settingssaved as $setting) {
1829 $presetxml .= "<$setting>{$data->$setting}</$setting>\n";
1831 $presetxml .= "</settings>\n\n";
1833 /* Now for the fields. Grabs all settings that are non-empty */
1834 if (!empty($fields)) {
1835 foreach ($fields as $field) {
1836 $presetxml .= "<field>\n";
1837 foreach ($field as $key => $value) {
1838 if ($value != '' && $key != 'id' && $key != 'dataid') {
1839 $presetxml .= "<$key>$value</$key>\n";
1842 $presetxml .= "</field>\n\n";
1846 $presetxml .= "</preset>";
1847 fwrite($presetfile, $presetxml);
1848 fclose($presetfile);
1850 /* Check all is well */
1851 if (!is_directory_a_preset($tempfolder)) {
1852 error("Not all files generated!");
1855 $filelist = array(
1856 'singletemplate.html',
1857 'listtemplate.html',
1858 'listtemplateheader.html',
1859 'listtemplatefooter.html',
1860 'addtemplate.html',
1861 'rsstemplate.html',
1862 'rsstitletemplate.html',
1863 'csstemplate.css',
1864 'jstemplate.js',
1865 'preset.xml');
1867 foreach ($filelist as $key => $file) {
1868 $filelist[$key] = $tempfolder.'/'.$filelist[$key];
1871 @unlink($tempfolder.'/export.zip');
1872 $status = zip_files($filelist, $tempfolder.'/export.zip');
1874 /* made the zip... now return the filename for storage.*/
1875 return $tempfolder.'/export.zip';
1880 class PresetImporter {
1881 function PresetImporter($course, $cm, $data, $userid, $shortname) {
1882 global $CFG;
1883 $this->course = $course;
1884 $this->cm = $cm;
1885 $this->data = $data;
1886 $this->userid = $userid;
1887 $this->shortname = $shortname;
1888 $this->folder = data_preset_path($course, $userid, $shortname);
1891 function get_settings() {
1892 global $CFG;
1894 if (!is_directory_a_preset($this->folder)) {
1895 error("$this->userid/$this->shortname Not a preset");
1898 /* Grab XML */
1899 $presetxml = file_get_contents($this->folder.'/preset.xml');
1900 $parsedxml = xmlize($presetxml);
1902 /* First, do settings. Put in user friendly array. */
1903 $settingsarray = $parsedxml['preset']['#']['settings'][0]['#'];
1904 $settings = new StdClass();
1906 foreach ($settingsarray as $setting => $value) {
1907 $settings->$setting = $value[0]['#'];
1910 /* Now work out fields to user friendly array */
1911 $fieldsarray = $parsedxml['preset']['#']['field'];
1912 $fields = array();
1913 foreach ($fieldsarray as $field) {
1914 $f = new StdClass();
1915 foreach ($field['#'] as $param => $value) {
1916 $f->$param = $value[0]['#'];
1918 $f->dataid = $this->data->id;
1919 $f->type = clean_param($f->type, PARAM_ALPHA);
1920 $fields[] = $f;
1923 /* Now add the HTML templates to the settings array so we can update d */
1924 $settings->singletemplate = file_get_contents($this->folder."/singletemplate.html");
1925 $settings->listtemplate = file_get_contents($this->folder."/listtemplate.html");
1926 $settings->listtemplateheader = file_get_contents($this->folder."/listtemplateheader.html");
1927 $settings->listtemplatefooter = file_get_contents($this->folder."/listtemplatefooter.html");
1928 $settings->addtemplate = file_get_contents($this->folder."/addtemplate.html");
1929 $settings->rsstemplate = file_get_contents($this->folder."/rsstemplate.html");
1930 $settings->rsstitletemplate = file_get_contents($this->folder."/rsstitletemplate.html");
1931 $settings->csstemplate = file_get_contents($this->folder."/csstemplate.css");
1932 $settings->jstemplate = file_get_contents($this->folder."/jstemplate.js");
1934 $settings->instance = $this->data->id;
1936 /* Now we look at the current structure (if any) to work out whether we need to clear db
1937 or save the data */
1938 $currentfields = array();
1939 $currentfields = get_records('data_fields', 'dataid', $this->data->id);
1941 return array($settings, $fields, $currentfields);
1944 function import_options() {
1945 if (!confirm_sesskey()) {
1946 error("Sesskey Invalid");
1949 $strblank = get_string('blank', 'data');
1950 $strnofields = get_string('nofields', 'data');
1951 $strcontinue = get_string('continue');
1952 $strwarning = get_string('mappingwarning', 'data');
1953 $strfieldmappings = get_string('fieldmappings', 'data');
1954 $strnew = get_string('new');
1955 $strold = get_string('old');
1957 $sesskey = sesskey();
1959 list($settings, $newfields, $currentfields) = $this->get_settings();
1961 echo '<div style="text-align:center"><form action="preset.php" method="post">';
1962 echo '<fieldset class="invisiblefieldset">';
1963 echo '<input type="hidden" name="action" value="finishimport" />';
1964 echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
1965 echo '<input type="hidden" name="d" value="'.$this->data->id.'" />';
1966 echo '<input type="hidden" name="fullname" value="'.$this->userid.'/'.$this->shortname.'" />';
1968 if (!empty($currentfields) && !empty($newfields)) {
1969 echo "<h3>$strfieldmappings ";
1970 helpbutton('fieldmappings', '', 'data');
1971 echo '</h3><table>';
1973 foreach ($newfields as $nid => $newfield) {
1974 echo "<tr><td><label for=\"id_$newfield->name\">$newfield->name</label></td>";
1975 echo '<td><select name="field_'.$nid.'" id="id_'.$newfield->name.'">';
1977 $selected = false;
1978 foreach ($currentfields as $cid => $currentfield) {
1979 if ($currentfield->type == $newfield->type) {
1980 if ($currentfield->name == $newfield->name) {
1981 echo '<option value="'.$cid.'" selected="selected">'.$currentfield->name.'</option>';
1982 $selected=true;
1984 else {
1985 echo '<option value="$cid">'.$currentfield->name.'</option>';
1990 if ($selected)
1991 echo '<option value="-1">-</option>';
1992 else
1993 echo '<option value="-1" selected="selected">-</option>';
1994 echo '</select></td></tr>';
1996 echo '</table>';
1997 echo "<p>$strwarning</p>";
1999 else if (empty($newfields)) {
2000 error("New preset has no defined fields!");
2002 echo '<input type="submit" value="'.$strcontinue.'" /></fieldset></form></div>';
2006 function import() {
2007 global $CFG;
2009 list($settings, $newfields, $currentfields) = $this->get_settings();
2010 $preservedfields = array();
2012 /* Maps fields and makes new ones */
2013 if (!empty($newfields)) {
2014 /* We require an injective mapping, and need to know what to protect */
2015 foreach ($newfields as $nid => $newfield) {
2016 $cid = optional_param("field_$nid", -1, PARAM_INT);
2017 if ($cid == -1) continue;
2019 if (array_key_exists($cid, $preservedfields)) error("Not an injective map");
2020 else $preservedfields[$cid] = true;
2023 foreach ($newfields as $nid => $newfield) {
2024 $cid = optional_param("field_$nid", -1, PARAM_INT);
2026 /* A mapping. Just need to change field params. Data kept. */
2027 if ($cid != -1 and isset($currentfields[$cid])) {
2028 $fieldobject = data_get_field_from_id($currentfields[$cid]->id, $this->data);
2029 foreach ($newfield as $param => $value) {
2030 if ($param != "id") {
2031 $fieldobject->field->$param = $value;
2034 unset($fieldobject->field->similarfield);
2035 $fieldobject->update_field();
2036 unset($fieldobject);
2038 /* Make a new field */
2039 else {
2040 include_once("field/$newfield->type/field.class.php");
2042 if (!isset($newfield->description)) {
2043 $newfield->description = '';
2045 $classname = 'data_field_'.$newfield->type;
2046 $fieldclass = new $classname($newfield, $this->data);
2047 $fieldclass->insert_field();
2048 unset($fieldclass);
2053 /* Get rid of all old unused data */
2054 if (!empty($preservedfields)) {
2055 foreach ($currentfields as $cid => $currentfield) {
2056 if (!array_key_exists($cid, $preservedfields)) {
2057 /* Data not used anymore so wipe! */
2058 print "Deleting field $currentfield->name<br />";
2060 $id = $currentfield->id;
2061 //Why delete existing data records and related comments/ratings??
2063 if ($content = get_records('data_content', 'fieldid', $id)) {
2064 foreach ($content as $item) {
2065 delete_records('data_ratings', 'recordid', $item->recordid);
2066 delete_records('data_comments', 'recordid', $item->recordid);
2067 delete_records('data_records', 'id', $item->recordid);
2070 delete_records('data_content', 'fieldid', $id);
2071 delete_records('data_fields', 'id', $id);
2076 // existing valuas MUST be sent too - it can not work without them!
2077 foreach ($this->data as $prop=>$unused) {
2078 if (array_key_exists($prop, $settings)) {
2079 $this->$prop = $settings->$prop;
2082 data_update_instance(addslashes_object($this->data));
2084 if (strstr($this->folder, '/temp/')) clean_preset($this->folder); /* Removes the temporary files */
2085 return true;
2089 function data_preset_path($course, $userid, $shortname) {
2090 global $USER, $CFG;
2092 $context = get_context_instance(CONTEXT_COURSE, $course->id);
2094 $userid = (int)$userid;
2096 if ($userid > 0 && ($userid == $USER->id || has_capability('mod/data:viewalluserpresets', $context))) {
2097 return $CFG->dataroot.'/data/preset/'.$userid.'/'.$shortname;
2098 } else if ($userid == 0) {
2099 return $CFG->dirroot.'/mod/data/preset/'.$shortname;
2100 } else if ($userid < 0) {
2101 return $CFG->dataroot.'/temp/data/'.-$userid.'/'.$shortname;
2104 return 'Does it disturb you that this code will never run?';