2 ///////////////////////////////////////////////////////////////////////////
4 // NOTICE OF COPYRIGHT //
6 // Moodle - Modular Object-Oriented Dynamic Learning Environment //
7 // http://moodle.org //
9 // Copyright (C) 2005 Moodle Pty Ltd http://moodle.com //
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. //
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: //
21 // http://www.gnu.org/copyleft/gpl.html //
23 ///////////////////////////////////////////////////////////////////////////
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. ');
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);
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
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;
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
= '';
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
);
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()');
135 if (!$this->field
->id
= insert_record('data_fields',$this->field
)){
136 notify('Insertion of new field failed!');
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!');
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();
161 // Print the relevant form element in the ADD template for this field
162 function display_add_field($recordid=0){
164 $content = get_field('data_content', 'content', 'fieldid', $this->field
->id
, 'recordid', $recordid);
169 // beware get_field returns false for new, empty records MDL-18567
170 if ($content===false) {
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).'" />';
181 // Print the relevant form element to define the attributes for this field
182 // viewable by teachers only.
183 function display_edit_field() {
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');
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";
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);
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);
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);
259 return delete_records('data_content', 'fieldid', $this->field
->id
, 'recordid', $recordid);
261 return delete_records('data_content', 'fieldid', $this->field
->id
);
265 // Deletes any files associated with this field
266 function delete_content_files($recordid='') {
269 require_once($CFG->libdir
.'/filelib.php');
271 $dir = $CFG->dataroot
.'/'.$this->data
->course
.'/'.$CFG->moddata
.'/data/'.$this->data
->id
.'/'.$this->field
->id
;
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() {
300 // Returns the SQL needed to refer to the column. Some fields may need to CAST() etc.
301 function get_sort_sql($fieldname) {
305 // Returns the name/type of the field
307 return get_string('name'.$this->type
, 'data');
310 // Prints the respective type icon
314 $str = '<a href="field.php?d='.$this->data
->id
.'&fid='.$this->field
->id
.'&mode=display&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>';
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() {
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
341 function data_generate_default_template(&$data, $template, $recordid=0, $form=false, $update=true) {
343 if (!$data && !$template) {
346 if ($template == 'csstemplate' or $template == 'jstemplate' ) {
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') {
362 //if (!in_array($field->type, array('picture', 'checkbox', 'date', 'latlong', 'radiobutton'))) {
363 // $str .= ' for="[['.$field->name.'#id]]"';
365 //$str .= '>'.$field->name.'</label>';
368 $str .= $field->name
.': ';
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>';
395 if ($template == 'listtemplate'){
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');
406 $data->{$template} = $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)) {
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
;
462 if (!empty($data->singletemplate
)) {
463 $newdata->singletemplate
= addslashes($data->singletemplate
.' [[' . $newfieldname .']]');
466 if (!empty($data->addtemplate
)) {
467 $newdata->addtemplate
= addslashes($data->addtemplate
.' [[' . $newfieldname . ']]');
470 if (!empty($data->rsstemplate
)) {
471 $newdata->rsstemplate
= addslashes($data->singletemplate
.' [[' . $newfieldname . ']]');
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
);
487 return data_get_field($field, $data);
493 /************************************************************************
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
);
500 return data_get_field($field, $data);
506 /************************************************************************
508 * this function creates an instance of the particular subfield class *
509 ************************************************************************/
510 function data_get_field_new($type, $data) {
512 require_once($CFG->dirroot
.'/mod/data/field/'.$type.'/field.class.php');
513 $newfield = 'data_field_'.$type;
514 $newfield = new $newfield(0, $data);
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) {
526 require_once('field/'.$field->type
.'/field.class.php');
527 $newfield = 'data_field_'.$field->type
;
528 $newfield = new $newfield($field, $data);
534 /***************************************************************************
535 * given record id, returns true if the record belongs to the current user *
536 * input @param $rid - record id *
538 ***************************************************************************/
539 function data_isowner($rid){
541 if (empty($USER->id
)) {
545 if ($record = get_record('data_records','id',$rid)) {
546 return ($record->userid
== $USER->id
);
552 /***********************************************************************
553 * has a user reached the max number of entries? *
554 * input object $data *
556 ***********************************************************************/
557 function data_atmaxentries($data) {
558 if (!$data->maxentries
) {
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 *
570 **********************************************************************/
571 function data_numentries($data) {
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 *
583 ****************************************************************/
584 function data_add_record($data, $groupid=0) {
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;
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 *
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) {
619 notify ('[['.$field->name
.']] - '.get_string('multipletags','data'));
626 /************************************************************************
627 * Adds an instance of a data *
628 ************************************************************************/
629 function data_add_instance($data) {
631 if (empty($data->assessed
)) {
635 $data->timemodified
= time();
636 if (! $data->id
= insert_record('data', $data)) {
640 $data = stripslashes_recursive($data);
641 data_grade_item_update($data);
645 /************************************************************************
646 * updates an instance of a data *
647 ************************************************************************/
648 function data_update_instance($data) {
650 $data->timemodified
= time();
651 $data->id
= $data->instance
;
653 if (empty($data->assessed
)) {
656 if (empty($data->notification
)) {
657 $data->notification
= 0;
659 if (! update_record('data', $data)) {
663 $data = stripslashes_recursive($data);
664 data_grade_item_update($data);
668 /************************************************************************
669 * deletes an instance of a data *
670 ************************************************************************/
671 function data_delete_instance($id) { // takes the dataid
674 if (! $data = get_record('data', 'id', $id)) {
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);
704 /************************************************************************
705 * returns a summary of data activity of this user *
706 ************************************************************************/
707 function data_user_outline($course, $user, $mod, $data) {
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
)) {
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
;
726 $result->info
.= ', ' . get_string('grade') . ': ' . $grade->str_long_grade
;
730 $result = new object();
731 $result->info
= get_string('grade') . ': ' . $grade->str_long_grade
;
732 $result->time
= $grade->dategraded
;
738 /************************************************************************
739 * Prints all the records uploaded by this user *
740 ************************************************************************/
741 function data_user_complete($course, $user, $mod, $data) {
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) {
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
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) {
787 if (!function_exists('grade_update')) { //workaround for buggy PHP versions
788 require_once($CFG->libdir
.'/gradelib.php');
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);
800 data_grade_item_update($data);
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);
811 data_grade_item_update($data);
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) {
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;
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) {
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)
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'
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'
887 AND r.id = a.recordid");
888 $participants = array();
890 foreach ($records as $record) {
891 $participants[$record->id
] = $record;
895 foreach ($comments as $comment) {
896 $participants[$comment->id
] = $comment;
900 foreach ($ratings as $rating) {
901 $participants[$rating->id
] = $rating;
904 return $participants;
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 *
916 ************************************************************************/
917 function data_print_template($template, $records, $data, $search='', $page=0, $return=false) {
919 $cm = get_coursemodule_from_instance('data', $data->id
);
920 $context = get_context_instance(CONTEXT_MODULE
, $cm->id
);
921 static $fields = NULL;
923 static $dataid = NULL;
924 if (empty($dataid)) {
926 } else if ($dataid != $data->id
) {
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)) {
939 foreach ($records as $record) { // Might be just one for the single template
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
.'&rid='.$record->id
.'&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
.'&delete='.$record->id
.'&sesskey='.sesskey().'"><img src="'.$CFG->pixpath
.'/t/delete.gif" class="iconsmall" alt="'.get_string('delete').'" title="'.get_string('delete').'" /></a>';
961 $moreurl = $CFG->wwwroot
. '/mod/data/view.php?d=' . $data->id
. '&rid=' . $record->id
;
963 $moreurl .= '&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 '&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
.'&approve='.$record->id
.'&sesskey='.sesskey().'"><img src="'.$CFG->pixpath
.'/i/approve.gif" class="icon" alt="'.get_string('approve').'" /></a></span>';
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>';
996 // actual replacement of the tags
997 $newtext = str_ireplace($patterns, $replacement, $data->{$template});
999 // no more html formatting and filtering - see MDL-6635
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 *
1034 ************************************************************************/
1035 function data_print_preference_form($data, $perpage, $search, $sort='', $order='ASC', $search_array = '', $advanced = 0, $mode= '') {
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">';
1042 echo '<input type="hidden" name="d" value="'.$data->id
.'" />';
1043 if ($mode =='asearch') {
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: ';
1058 echo ';" > <label for="pref_search">'.get_string('search').'</label> <input type="text" size="16" name="search" id= "pref_search" value="'.s($search).'" /></div>';
1059 echo ' <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>';
1068 echo '<option value="'.$field->id
.'">'.$field->name
.'</option>';
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>';
1086 echo '<option value="'.$key.'">'.$name.'</option>';
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>';
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>';
1101 echo '<option value="DESC">'.get_string('descending','data').'</option>';
1106 $checked = ' checked="checked" ';
1112 <script type="text/javascript">
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\')) {
1122 divs[i].style.display = \'inline\';
1125 divs[i].style.display = \'none\';
1128 else if (divs[i].id.match(\'reg_search\')) {
1130 divs[i].style.display = \'inline\';
1133 divs[i].style.display = \'none\';
1141 echo ' <input type="hidden" name="advanced" value="0" />';
1142 echo ' <input type="hidden" name="filter" value="1" />';
1143 echo ' <input type="checkbox" id="advancedcheckbox" name="advanced" value="1" '.$checked.' onchange="showHideAdvSearch(this.checked);" /><label for="advancedcheckbox">'.get_string('advancedsearch', 'data').'</label>';
1144 echo ' <input type="submit" value="'.get_string('savesettings','data').'" />';
1146 echo '<div class="dataadvancedsearch" id="data_adv_form" style="display: ';
1153 echo ';margin-left:auto;margin-right:auto;" >';
1154 echo '<table class="boxaligncenter">';
1155 // print ASC or DESC
1156 echo '<tr><td colspan="2"> </td></tr>';
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;
1167 static $dataid = NULL;
1168 if (empty($dataid)) {
1169 $dataid = $data->id
;
1170 } else if ($dataid != $data->id
) {
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);
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
);
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;
1211 echo format_text($newtext, FORMAT_HTML
, $options);
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>';
1221 function data_print_ratings($data, $record) {
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));
1235 data_print_rating_menu($record->id
, $USER->id
, $ratingsscale);
1236 $ratingsmenuused = true;
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').'" />';
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
1261 $mean = data_get_ratings_mean($recordid, $scale);
1263 if (empty($strratings)) {
1264 $strratings = get_string("ratings", "data");
1266 echo "$strratings: ";
1268 link_to_popup_window ("/mod/data/report.php?id=$recordid", "ratings", $mean, 400, 600);
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)
1282 if ($rates = get_records("data_ratings", "recordid", $recordid)) {
1283 foreach ($rates as $rate) {
1284 $ratings[] = $rate->rating
;
1288 $count = count($ratings);
1291 } else if ($count == 1) {
1292 return $scale[$ratings[0]];
1295 foreach ($ratings as $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)";
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
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.
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
1335 // prints all comments + a text box for adding additional comment
1336 function data_print_comments($data, $record, $page=0, $mform=false) {
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);
1348 if (!isloggedin() or isguest() or !$cancomment) {
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
.'&rid='.$record->id
.'&mode=single&addcomment=1">'.get_string('addcomment', 'data').'</a>';
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">';
1368 // prints a single comment entry
1369 function data_print_comment($data, $comment, $page=0) {
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
);
1380 echo '<td class="topic starter" align="left"><div class="author">';
1381 $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context));
1383 $by->name
= '<a href="'.$CFG->wwwroot
.'/user/view.php?id='.
1384 $user->id
.'&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);
1396 echo '</td><td class="content" align="left">'."\n";
1397 // Print whole message
1398 echo format_text($comment->content
, $comment->format
);
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
.'&mode=edit&commentid='.$comment->id
.'&page='.$page.'">'.$stredit.'</a>';
1404 echo '| <a href="'.$CFG->wwwroot
.'/mod/data/comment.php?rid='.$comment->recordid
.'&mode=delete&commentid='.$comment->id
.'&page='.$page.'">'.$strdelete.'</a>';
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) {
1423 $LIKE = sql_ilike();
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))");
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)) {
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) {
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.
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');
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
) {
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
);
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
);
1502 // 2 - Only teachers can rate posts
1503 // 1 - Everyone can rate posts
1504 // 0 - No one can rate posts
1505 switch ($data->assessed
) {
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
);
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
);
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
);
1532 // $data->assesspublic:
1533 // 0 - Students can only see their own ratings
1534 // 1 - Students can see everyone's ratings
1535 switch ($data->assesspublic
) {
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
);
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
);
1555 $cm = get_record('course_modules', 'id', $cmid);
1558 switch ($cm->groupmode
) {
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
);
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
);
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) == '[') {
1597 * Returns an array of all the available presets
1599 function data_get_available_presets($context) {
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;
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);
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) {
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)) {
1686 if (!$groupmode or has_capability('moodle/site:accessallgroups', $context)) {
1690 if ($currentgroup) {
1691 return groups_is_member($currentgroup);
1693 //else it might be group 0 in visible mode
1694 if ($groupmode == VISIBLEGROUPS
){
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');
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');
1732 @unlink
($folder.'/asearchtemplate.html');
1737 class PresetImporter
{
1738 function PresetImporter($course, $cm, $data, $userid, $shortname) {
1740 $this->course
= $course;
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() {
1751 if (!is_directory_a_preset($this->folder
)) {
1752 error("$this->userid/$this->shortname Not a preset");
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)) {
1770 if (!in_array($setting, $allowed_settings)) {
1771 // unsupported setting
1774 $settings->$setting = $value[0]['#'];
1777 /* Now work out fields to user friendly array */
1778 $fieldsarray = $parsedxml['preset']['#']['field'];
1780 foreach ($fieldsarray as $field) {
1781 if (!is_array($field)) {
1784 $f = new StdClass();
1785 foreach ($field['#'] as $param => $value) {
1786 if (!is_array($value)) {
1789 $f->$param = addslashes($value[0]['#']);
1791 $f->dataid
= $this->data
->id
;
1792 $f->type
= clean_param($f->type
, PARAM_ALPHA
);
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");
1807 if (file_exists($this->folder
."/asearchtemplate.html")) {
1808 $settings->asearchtemplate
= file_get_contents($this->folder
."/asearchtemplate.html");
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
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">';
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
.'">';
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>';
1856 echo '<option value="'.$cid.'">'.$currentfield->name
.'</option>';
1861 echo '<option value="-1">-</option>';
1863 echo '<option value="-1" selected="selected">-</option>';
1864 echo '</select></td></tr>';
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>';
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 */
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();
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
)) {
1944 $settings->defaultsort
= 0;
1946 $settings->defaultsort
= (int)get_field('data_fields', 'id', 'dataid', $this->data
->id
, 'name', addslashes($settings->defaultsort
));
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);
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
);
1979 function data_preset_path($course, $userid, $shortname) {
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='') {
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) {
2044 require_once($CFG->libdir
.'/filelib.php');
2045 $componentstr = get_string('modulenameplural', 'data');
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();
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);
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;
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);
2134 * Returns all other caps used in module
2136 function data_get_extra_capabilities() {
2137 return array('moodle/site:accessallgroups', 'moodle/site:viewfullnames');