2e95a1017a807c590015adf5ccb927eb211af7ae
[moodle.git] / mod / feedback / lib.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Library of functions and constants for module feedback
19  * includes the main-part of feedback-functions
20  *
21  * @package mod-feedback
22  * @copyright Andreas Grabs
23  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 /** Include eventslib.php */
27 require_once($CFG->libdir.'/eventslib.php');
28 /** Include calendar/lib.php */
29 require_once($CFG->dirroot.'/calendar/lib.php');
31 define('FEEDBACK_ANONYMOUS_YES', 1);
32 define('FEEDBACK_ANONYMOUS_NO', 2);
33 define('FEEDBACK_MIN_ANONYMOUS_COUNT_IN_GROUP', 2);
34 define('FEEDBACK_DECIMAL', '.');
35 define('FEEDBACK_THOUSAND', ',');
36 define('FEEDBACK_RESETFORM_RESET', 'feedback_reset_data_');
37 define('FEEDBACK_RESETFORM_DROP', 'feedback_drop_feedback_');
38 define('FEEDBACK_MAX_PIX_LENGTH', '400'); //max. Breite des grafischen Balkens in der Auswertung
39 define('FEEDBACK_DEFAULT_PAGE_COUNT', 20);
41 /**
42  * @uses FEATURE_GROUPS
43  * @uses FEATURE_GROUPINGS
44  * @uses FEATURE_GROUPMEMBERSONLY
45  * @uses FEATURE_MOD_INTRO
46  * @uses FEATURE_COMPLETION_TRACKS_VIEWS
47  * @uses FEATURE_GRADE_HAS_GRADE
48  * @uses FEATURE_GRADE_OUTCOMES
49  * @param string $feature FEATURE_xx constant for requested feature
50  * @return mixed True if module supports feature, null if doesn't know
51  */
52 function feedback_supports($feature) {
53     switch($feature) {
54         case FEATURE_GROUPS:                  return true;
55         case FEATURE_GROUPINGS:               return true;
56         case FEATURE_GROUPMEMBERSONLY:        return true;
57         case FEATURE_MOD_INTRO:               return true;
58         case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
59         case FEATURE_COMPLETION_HAS_RULES:    return true;
60         case FEATURE_GRADE_HAS_GRADE:         return false;
61         case FEATURE_GRADE_OUTCOMES:          return false;
62         case FEATURE_BACKUP_MOODLE2:          return true;
63         case FEATURE_SHOW_DESCRIPTION:        return true;
65         default: return null;
66     }
67 }
69 /**
70  * this will create a new instance and return the id number
71  * of the new instance.
72  *
73  * @global object
74  * @param object $feedback the object given by mod_feedback_mod_form
75  * @return int
76  */
77 function feedback_add_instance($feedback) {
78     global $DB;
80     $feedback->timemodified = time();
81     $feedback->id = '';
83     //check if openenable and/or closeenable is set and set correctly to save in db
84     if (empty($feedback->openenable)) {
85         $feedback->timeopen = 0;
86     }
87     if (empty($feedback->closeenable)) {
88         $feedback->timeclose = 0;
89     }
90     if (empty($feedback->site_after_submit)) {
91         $feedback->site_after_submit = '';
92     }
94     //saving the feedback in db
95     $feedbackid = $DB->insert_record("feedback", $feedback);
97     $feedback->id = $feedbackid;
99     feedback_set_events($feedback);
101     if (!isset($feedback->coursemodule)) {
102         $cm = get_coursemodule_from_id('feedback', $feedback->id);
103         $feedback->coursemodule = $cm->id;
104     }
105     $context = get_context_instance(CONTEXT_MODULE, $feedback->coursemodule);
107     $editoroptions = feedback_get_editor_options();
109     // process the custom wysiwyg editor in page_after_submit
110     if ($draftitemid = $feedback->page_after_submit_editor['itemid']) {
111         $feedback->page_after_submit = file_save_draft_area_files($draftitemid, $context->id,
112                                                     'mod_feedback', 'page_after_submit',
113                                                     0, $editoroptions,
114                                                     $feedback->page_after_submit_editor['text']);
116         $feedback->page_after_submitformat = $feedback->page_after_submit_editor['format'];
117     }
118     $DB->update_record('feedback', $feedback);
120     return $feedbackid;
123 /**
124  * this will update a given instance
125  *
126  * @global object
127  * @param object $feedback the object given by mod_feedback_mod_form
128  * @return boolean
129  */
130 function feedback_update_instance($feedback) {
131     global $DB;
133     $feedback->timemodified = time();
134     $feedback->id = $feedback->instance;
136     //check if openenable and/or closeenable is set and set correctly to save in db
137     if (empty($feedback->openenable)) {
138         $feedback->timeopen = 0;
139     }
140     if (empty($feedback->closeenable)) {
141         $feedback->timeclose = 0;
142     }
143     if (empty($feedback->site_after_submit)) {
144         $feedback->site_after_submit = '';
145     }
147     //save the feedback into the db
148     $DB->update_record("feedback", $feedback);
150     //create or update the new events
151     feedback_set_events($feedback);
153     $context = get_context_instance(CONTEXT_MODULE, $feedback->coursemodule);
155     $editoroptions = feedback_get_editor_options();
157     // process the custom wysiwyg editor in page_after_submit
158     if ($draftitemid = $feedback->page_after_submit_editor['itemid']) {
159         $feedback->page_after_submit = file_save_draft_area_files($draftitemid, $context->id,
160                                                     'mod_feedback', 'page_after_submit',
161                                                     0, $editoroptions,
162                                                     $feedback->page_after_submit_editor['text']);
164         $feedback->page_after_submitformat = $feedback->page_after_submit_editor['format'];
165     }
166     $DB->update_record('feedback', $feedback);
168     return true;
171 /**
172  * Serves the files included in feedback items like label. Implements needed access control ;-)
173  *
174  * There are two situations in general where the files will be sent.
175  * 1) filearea = item, 2) filearea = template
176  *
177  * @package  mod_feedback
178  * @category files
179  * @param stdClass $course course object
180  * @param stdClass $cm course module object
181  * @param stdClass $context context object
182  * @param string $filearea file area
183  * @param array $args extra arguments
184  * @param bool $forcedownload whether or not force download
185  * @param array $options additional options affecting the file serving
186  * @return bool false if file not found, does not return if found - justsend the file
187  */
188 function feedback_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
189     global $CFG, $DB;
191     if ($filearea === 'item' or $filearea === 'template') {
192         $itemid = (int)array_shift($args);
193         //get the item what includes the file
194         if (!$item = $DB->get_record('feedback_item', array('id'=>$itemid))) {
195             return false;
196         }
197         $feedbackid = $item->feedback;
198         $templateid = $item->template;
199     }
201     if ($filearea === 'page_after_submit' or $filearea === 'item') {
202         if (! $feedback = $DB->get_record("feedback", array("id"=>$cm->instance))) {
203             return false;
204         }
206         $feedbackid = $feedback->id;
208         //if the filearea is "item" so we check the permissions like view/complete the feedback
209         $canload = false;
210         //first check whether the user has the complete capability
211         if (has_capability('mod/feedback:complete', $context)) {
212             $canload = true;
213         }
215         //now we check whether the user has the view capability
216         if (has_capability('mod/feedback:view', $context)) {
217             $canload = true;
218         }
220         //if the feedback is on frontpage and anonymous and the fullanonymous is allowed
221         //so the file can be loaded too.
222         if (isset($CFG->feedback_allowfullanonymous)
223                     AND $CFG->feedback_allowfullanonymous
224                     AND $course->id == SITEID
225                     AND $feedback->anonymous == FEEDBACK_ANONYMOUS_YES ) {
226             $canload = true;
227         }
229         if (!$canload) {
230             return false;
231         }
232     } else if ($filearea === 'template') { //now we check files in templates
233         if (!$template = $DB->get_record('feedback_template', array('id'=>$templateid))) {
234             return false;
235         }
237         //if the file is not public so the capability edititems has to be there
238         if (!$template->ispublic) {
239             if (!has_capability('mod/feedback:edititems', $context)) {
240                 return false;
241             }
242         } else { //on public templates, at least the user has to be logged in
243             if (!isloggedin()) {
244                 return false;
245             }
246         }
247     } else {
248         return false;
249     }
251     if ($context->contextlevel == CONTEXT_MODULE) {
252         if ($filearea !== 'item' and $filearea !== 'page_after_submit') {
253             return false;
254         }
255     }
257     if ($context->contextlevel == CONTEXT_COURSE || $context->contextlevel == CONTEXT_SYSTEM) {
258         if ($filearea !== 'template') {
259             return false;
260         }
261     }
263     $relativepath = implode('/', $args);
264     if ($filearea === 'page_after_submit') {
265         $fullpath = "/{$context->id}/mod_feedback/$filearea/$relativepath";
266     } else {
267         $fullpath = "/{$context->id}/mod_feedback/$filearea/{$item->id}/$relativepath";
268     }
270     $fs = get_file_storage();
272     if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
273         return false;
274     }
276     // finally send the file
277     send_stored_file($file, 0, 0, true, $options); // download MUST be forced - security!
279     return false;
282 /**
283  * this will delete a given instance.
284  * all referenced data also will be deleted
285  *
286  * @global object
287  * @param int $id the instanceid of feedback
288  * @return boolean
289  */
290 function feedback_delete_instance($id) {
291     global $DB;
293     //get all referenced items
294     $feedbackitems = $DB->get_records('feedback_item', array('feedback'=>$id));
296     //deleting all referenced items and values
297     if (is_array($feedbackitems)) {
298         foreach ($feedbackitems as $feedbackitem) {
299             $DB->delete_records("feedback_value", array("item"=>$feedbackitem->id));
300             $DB->delete_records("feedback_valuetmp", array("item"=>$feedbackitem->id));
301         }
302         if ($delitems = $DB->get_records("feedback_item", array("feedback"=>$id))) {
303             foreach ($delitems as $delitem) {
304                 feedback_delete_item($delitem->id, false);
305             }
306         }
307     }
309     //deleting the referenced tracking data
310     $DB->delete_records('feedback_tracking', array('feedback'=>$id));
312     //deleting the completeds
313     $DB->delete_records("feedback_completed", array("feedback"=>$id));
315     //deleting the unfinished completeds
316     $DB->delete_records("feedback_completedtmp", array("feedback"=>$id));
318     //deleting old events
319     $DB->delete_records('event', array('modulename'=>'feedback', 'instance'=>$id));
320     return $DB->delete_records("feedback", array("id"=>$id));
323 /**
324  * this is called after deleting all instances if the course will be deleted.
325  * only templates have to be deleted
326  *
327  * @global object
328  * @param object $course
329  * @return boolean
330  */
331 function feedback_delete_course($course) {
332     global $DB;
334     //delete all templates of given course
335     return $DB->delete_records('feedback_template', array('course'=>$course->id));
338 /**
339  * Return a small object with summary information about what a
340  * user has done with a given particular instance of this module
341  * Used for user activity reports.
342  * $return->time = the time they did it
343  * $return->info = a short text description
344  *
345  * @param object $course
346  * @param object $user
347  * @param object $mod
348  * @param object $feedback
349  * @return object
350  */
351 function feedback_user_outline($course, $user, $mod, $feedback) {
352     return null;
355 /**
356  * Returns all users who has completed a specified feedback since a given time
357  * many thanks to Manolescu Dorel, who contributed these two functions
358  *
359  * @global object
360  * @global object
361  * @global object
362  * @global object
363  * @uses CONTEXT_MODULE
364  * @param array $activities Passed by reference
365  * @param int $index Passed by reference
366  * @param int $timemodified Timestamp
367  * @param int $courseid
368  * @param int $cmid
369  * @param int $userid
370  * @param int $groupid
371  * @return void
372  */
373 function feedback_get_recent_mod_activity(&$activities, &$index,
374                                           $timemodified, $courseid,
375                                           $cmid, $userid="", $groupid="") {
377     global $CFG, $COURSE, $USER, $DB;
379     if ($COURSE->id == $courseid) {
380         $course = $COURSE;
381     } else {
382         $course = $DB->get_record('course', array('id'=>$courseid));
383     }
385     $modinfo = get_fast_modinfo($course);
387     $cm = $modinfo->cms[$cmid];
389     $sqlargs = array();
391     //TODO: user user_picture::fields;
392     $sql = " SELECT fk . * , fc . * , u.firstname, u.lastname, u.email, u.picture, u.email
393                                             FROM {feedback_completed} fc
394                                                 JOIN {feedback} fk ON fk.id = fc.feedback
395                                                 JOIN {user} u ON u.id = fc.userid ";
397     if ($groupid) {
398         $sql .= " JOIN {groups_members} gm ON  gm.userid=u.id ";
399     }
401     $sql .= " WHERE fc.timemodified > ? AND fk.id = ? ";
402     $sqlargs[] = $timemodified;
403     $sqlargs[] = $cm->instace;
405     if ($userid) {
406         $sql .= " AND u.id = ? ";
407         $sqlargs[] = $userid;
408     }
410     if ($groupid) {
411         $sql .= " AND gm.groupid = ? ";
412         $sqlargs[] = $groupid;
413     }
415     if (!$feedbackitems = $DB->get_records_sql($sql, $sqlargs)) {
416         return;
417     }
419     $cm_context      = get_context_instance(CONTEXT_MODULE, $cm->id);
420     $accessallgroups = has_capability('moodle/site:accessallgroups', $cm_context);
421     $viewfullnames   = has_capability('moodle/site:viewfullnames', $cm_context);
422     $groupmode       = groups_get_activity_groupmode($cm, $course);
424     if (is_null($modinfo->groups)) {
425         // load all my groups and cache it in modinfo
426         $modinfo->groups = groups_get_user_groups($course->id);
427     }
429     $aname = format_string($cm->name, true);
430     foreach ($feedbackitems as $feedbackitem) {
431         if ($feedbackitem->userid != $USER->id) {
433             if ($groupmode == SEPARATEGROUPS and !$accessallgroups) {
434                 $usersgroups = groups_get_all_groups($course->id,
435                                                      $feedbackitem->userid,
436                                                      $cm->groupingid);
437                 if (!is_array($usersgroups)) {
438                     continue;
439                 }
440                 $usersgroups = array_keys($usersgroups);
441                 $intersect = array_intersect($usersgroups, $modinfo->groups[$cm->id]);
442                 if (empty($intersect)) {
443                     continue;
444                 }
445             }
446         }
448         $tmpactivity = new stdClass();
450         $tmpactivity->type      = 'feedback';
451         $tmpactivity->cmid      = $cm->id;
452         $tmpactivity->name      = $aname;
453         $tmpactivity->sectionnum= $cm->sectionnum;
454         $tmpactivity->timestamp = $feedbackitem->timemodified;
456         $tmpactivity->content->feedbackid = $feedbackitem->id;
457         $tmpactivity->content->feedbackuserid = $feedbackitem->userid;
459         //TODO: add all necessary user fields, this is not enough for user_picture
460         $tmpactivity->user->userid   = $feedbackitem->userid;
461         $tmpactivity->user->fullname = fullname($feedbackitem, $viewfullnames);
462         $tmpactivity->user->picture  = $feedbackitem->picture;
464         $activities[$index++] = $tmpactivity;
465     }
467     return;
470 /**
471  * Prints all users who has completed a specified feedback since a given time
472  * many thanks to Manolescu Dorel, who contributed these two functions
473  *
474  * @global object
475  * @param object $activity
476  * @param int $courseid
477  * @param string $detail
478  * @param array $modnames
479  * @return void Output is echo'd
480  */
481 function feedback_print_recent_mod_activity($activity, $courseid, $detail, $modnames) {
482     global $CFG, $OUTPUT;
484     echo '<table border="0" cellpadding="3" cellspacing="0" class="forum-recent">';
486     echo "<tr><td class=\"userpicture\" valign=\"top\">";
487     echo $OUTPUT->user_picture($activity->user, array('courseid'=>$courseid));
488     echo "</td><td>";
490     if ($detail) {
491         $modname = $modnames[$activity->type];
492         echo '<div class="title">';
493         echo "<img src=\"" . $OUTPUT->pix_url('icon', $activity->type) . "\" ".
494              "class=\"icon\" alt=\"$modname\" />";
495         echo "<a href=\"$CFG->wwwroot/mod/feedback/view.php?id={$activity->cmid}\">{$activity->name}</a>";
496         echo '</div>';
497     }
499     echo '<div class="title">';
500     echo '</div>';
502     echo '<div class="user">';
503     echo "<a href=\"$CFG->wwwroot/user/view.php?id={$activity->user->userid}&amp;course=$courseid\">"
504          ."{$activity->user->fullname}</a> - ".userdate($activity->timestamp);
505     echo '</div>';
507     echo "</td></tr></table>";
509     return;
512 /**
513  * Obtains the automatic completion state for this feedback based on the condition
514  * in feedback settings.
515  *
516  * @param object $course Course
517  * @param object $cm Course-module
518  * @param int $userid User ID
519  * @param bool $type Type of comparison (or/and; can be used as return value if no conditions)
520  * @return bool True if completed, false if not, $type if conditions not set.
521  */
522 function feedback_get_completion_state($course, $cm, $userid, $type) {
523     global $CFG, $DB;
525     // Get feedback details
526     $feedback = $DB->get_record('feedback', array('id'=>$cm->instance), '*', MUST_EXIST);
528     // If completion option is enabled, evaluate it and return true/false
529     if ($feedback->completionsubmit) {
530         $params = array('userid'=>$userid, 'feedback'=>$feedback->id);
531         return $DB->record_exists('feedback_tracking', $params);
532     } else {
533         // Completion option is not enabled so just return $type
534         return $type;
535     }
539 /**
540  * Print a detailed representation of what a  user has done with
541  * a given particular instance of this module, for user activity reports.
542  *
543  * @param object $course
544  * @param object $user
545  * @param object $mod
546  * @param object $feedback
547  * @return bool
548  */
549 function feedback_user_complete($course, $user, $mod, $feedback) {
550     return true;
553 /**
554  * @return bool true
555  */
556 function feedback_cron () {
557     return true;
560 /**
561  * @todo: deprecated - to be deleted in 2.2
562  * @return bool false
563  */
564 function feedback_get_participants($feedbackid) {
565     return false;
569 /**
570  * @return bool false
571  */
572 function feedback_scale_used ($feedbackid, $scaleid) {
573     return false;
576 /**
577  * Checks if scale is being used by any instance of feedback
578  *
579  * This is used to find out if scale used anywhere
580  * @param $scaleid int
581  * @return boolean True if the scale is used by any assignment
582  */
583 function feedback_scale_used_anywhere($scaleid) {
584     return false;
587 /**
588  * @return array
589  */
590 function feedback_get_view_actions() {
591     return array('view', 'view all');
594 /**
595  * @return array
596  */
597 function feedback_get_post_actions() {
598     return array('submit');
601 /**
602  * This function is used by the reset_course_userdata function in moodlelib.
603  * This function will remove all responses from the specified feedback
604  * and clean up any related data.
605  *
606  * @global object
607  * @global object
608  * @uses FEEDBACK_RESETFORM_RESET
609  * @uses FEEDBACK_RESETFORM_DROP
610  * @param object $data the data submitted from the reset course.
611  * @return array status array
612  */
613 function feedback_reset_userdata($data) {
614     global $CFG, $DB;
616     $resetfeedbacks = array();
617     $dropfeedbacks = array();
618     $status = array();
619     $componentstr = get_string('modulenameplural', 'feedback');
621     //get the relevant entries from $data
622     foreach ($data as $key => $value) {
623         switch(true) {
624             case substr($key, 0, strlen(FEEDBACK_RESETFORM_RESET)) == FEEDBACK_RESETFORM_RESET:
625                 if ($value == 1) {
626                     $templist = explode('_', $key);
627                     if (isset($templist[3])) {
628                         $resetfeedbacks[] = intval($templist[3]);
629                     }
630                 }
631             break;
632             case substr($key, 0, strlen(FEEDBACK_RESETFORM_DROP)) == FEEDBACK_RESETFORM_DROP:
633                 if ($value == 1) {
634                     $templist = explode('_', $key);
635                     if (isset($templist[3])) {
636                         $dropfeedbacks[] = intval($templist[3]);
637                     }
638                 }
639             break;
640         }
641     }
643     //reset the selected feedbacks
644     foreach ($resetfeedbacks as $id) {
645         $feedback = $DB->get_record('feedback', array('id'=>$id));
646         feedback_delete_all_completeds($id);
647         $status[] = array('component'=>$componentstr.':'.$feedback->name,
648                         'item'=>get_string('resetting_data', 'feedback'),
649                         'error'=>false);
650     }
652     return $status;
655 /**
656  * Called by course/reset.php
657  *
658  * @global object
659  * @uses FEEDBACK_RESETFORM_RESET
660  * @param object $mform form passed by reference
661  */
662 function feedback_reset_course_form_definition(&$mform) {
663     global $COURSE, $DB;
665     $mform->addElement('header', 'feedbackheader', get_string('modulenameplural', 'feedback'));
667     if (!$feedbacks = $DB->get_records('feedback', array('course'=>$COURSE->id), 'name')) {
668         return;
669     }
671     $mform->addElement('static', 'hint', get_string('resetting_data', 'feedback'));
672     foreach ($feedbacks as $feedback) {
673         $mform->addElement('checkbox', FEEDBACK_RESETFORM_RESET.$feedback->id, $feedback->name);
674     }
677 /**
678  * Course reset form defaults.
679  *
680  * @global object
681  * @uses FEEDBACK_RESETFORM_RESET
682  * @param object $course
683  */
684 function feedback_reset_course_form_defaults($course) {
685     global $DB;
687     $return = array();
688     if (!$feedbacks = $DB->get_records('feedback', array('course'=>$course->id), 'name')) {
689         return;
690     }
691     foreach ($feedbacks as $feedback) {
692         $return[FEEDBACK_RESETFORM_RESET.$feedback->id] = true;
693     }
694     return $return;
697 /**
698  * Called by course/reset.php and shows the formdata by coursereset.
699  * it prints checkboxes for each feedback available at the given course
700  * there are two checkboxes:
701  * 1) delete userdata and keep the feedback
702  * 2) delete userdata and drop the feedback
703  *
704  * @global object
705  * @uses FEEDBACK_RESETFORM_RESET
706  * @uses FEEDBACK_RESETFORM_DROP
707  * @param object $course
708  * @return void
709  */
710 function feedback_reset_course_form($course) {
711     global $DB, $OUTPUT;
713     echo get_string('resetting_feedbacks', 'feedback'); echo ':<br />';
714     if (!$feedbacks = $DB->get_records('feedback', array('course'=>$course->id), 'name')) {
715         return;
716     }
718     foreach ($feedbacks as $feedback) {
719         echo '<p>';
720         echo get_string('name', 'feedback').': '.$feedback->name.'<br />';
721         echo html_writer::checkbox(FEEDBACK_RESETFORM_RESET.$feedback->id,
722                                 1, true,
723                                 get_string('resetting_data', 'feedback'));
724         echo '<br />';
725         echo html_writer::checkbox(FEEDBACK_RESETFORM_DROP.$feedback->id,
726                                 1, false,
727                                 get_string('drop_feedback', 'feedback'));
728         echo '</p>';
729     }
732 /**
733  * This gets an array with default options for the editor
734  *
735  * @return array the options
736  */
737 function feedback_get_editor_options() {
738     return array('maxfiles' => EDITOR_UNLIMITED_FILES,
739                 'trusttext'=>true);
742 /**
743  * This creates new events given as timeopen and closeopen by $feedback.
744  *
745  * @global object
746  * @param object $feedback
747  * @return void
748  */
749 function feedback_set_events($feedback) {
750     global $DB;
752     // adding the feedback to the eventtable (I have seen this at quiz-module)
753     $DB->delete_records('event', array('modulename'=>'feedback', 'instance'=>$feedback->id));
755     if (!isset($feedback->coursemodule)) {
756         $cm = get_coursemodule_from_id('feedback', $feedback->id);
757         $feedback->coursemodule = $cm->id;
758     }
760     // the open-event
761     if ($feedback->timeopen > 0) {
762         $event = new stdClass();
763         $event->name         = get_string('start', 'feedback').' '.$feedback->name;
764         $event->description  = format_module_intro('feedback', $feedback, $feedback->coursemodule);
765         $event->courseid     = $feedback->course;
766         $event->groupid      = 0;
767         $event->userid       = 0;
768         $event->modulename   = 'feedback';
769         $event->instance     = $feedback->id;
770         $event->eventtype    = 'open';
771         $event->timestart    = $feedback->timeopen;
772         $event->visible      = instance_is_visible('feedback', $feedback);
773         if ($feedback->timeclose > 0) {
774             $event->timeduration = ($feedback->timeclose - $feedback->timeopen);
775         } else {
776             $event->timeduration = 0;
777         }
779         calendar_event::create($event);
780     }
782     // the close-event
783     if ($feedback->timeclose > 0) {
784         $event = new stdClass();
785         $event->name         = get_string('stop', 'feedback').' '.$feedback->name;
786         $event->description  = format_module_intro('feedback', $feedback, $feedback->coursemodule);
787         $event->courseid     = $feedback->course;
788         $event->groupid      = 0;
789         $event->userid       = 0;
790         $event->modulename   = 'feedback';
791         $event->instance     = $feedback->id;
792         $event->eventtype    = 'close';
793         $event->timestart    = $feedback->timeclose;
794         $event->visible      = instance_is_visible('feedback', $feedback);
795         $event->timeduration = 0;
797         calendar_event::create($event);
798     }
801 /**
802  * this function is called by {@link feedback_delete_userdata()}
803  * it drops the feedback-instance from the course_module table
804  *
805  * @global object
806  * @param int $id the id from the coursemodule
807  * @return boolean
808  */
809 function feedback_delete_course_module($id) {
810     global $DB;
812     if (!$cm = $DB->get_record('course_modules', array('id'=>$id))) {
813         return true;
814     }
815     return $DB->delete_records('course_modules', array('id'=>$cm->id));
820 ////////////////////////////////////////////////
821 //functions to handle capabilities
822 ////////////////////////////////////////////////
824 /**
825  * returns the context-id related to the given coursemodule-id
826  *
827  * @staticvar object $context
828  * @param int $cmid the coursemodule-id
829  * @return object $context
830  */
831 function feedback_get_context($cmid) {
832     static $context;
834     if (isset($context)) {
835         return $context;
836     }
838     if (!$context = get_context_instance(CONTEXT_MODULE, $cmid)) {
839             print_error('badcontext');
840     }
841     return $context;
844 /**
845  *  returns true if the current role is faked by switching role feature
846  *
847  * @global object
848  * @return boolean
849  */
850 function feedback_check_is_switchrole() {
851     global $USER;
852     if (isset($USER->switchrole) AND
853             is_array($USER->switchrole) AND
854             count($USER->switchrole) > 0) {
856         return true;
857     }
858     return false;
861 /**
862  * count users which have not completed the feedback
863  *
864  * @global object
865  * @uses CONTEXT_MODULE
866  * @param object $cm
867  * @param int $group single groupid
868  * @param string $sort
869  * @param int $startpage
870  * @param int $pagecount
871  * @return object the userrecords
872  */
873 function feedback_get_incomplete_users($cm,
874                                        $group = false,
875                                        $sort = '',
876                                        $startpage = false,
877                                        $pagecount = false) {
879     global $DB;
881     $context = get_context_instance(CONTEXT_MODULE, $cm->id);
883     //first get all user who can complete this feedback
884     $cap = 'mod/feedback:complete';
885     $fields = 'u.id, u.username';
886     if (!$allusers = get_users_by_capability($context,
887                                             $cap,
888                                             $fields,
889                                             $sort,
890                                             '',
891                                             '',
892                                             $group,
893                                             '',
894                                             true)) {
895         return false;
896     }
897     $allusers = array_keys($allusers);
899     //now get all completeds
900     $params = array('feedback'=>$cm->instance);
901     if (!$completedusers = $DB->get_records_menu('feedback_completed', $params, '', 'userid,id')) {
902         return $allusers;
903     }
904     $completedusers = array_keys($completedusers);
906     //now strike all completedusers from allusers
907     $allusers = array_diff($allusers, $completedusers);
909     //for paging I use array_slice()
910     if ($startpage !== false AND $pagecount !== false) {
911         $allusers = array_slice($allusers, $startpage, $pagecount);
912     }
914     return $allusers;
917 /**
918  * count users which have not completed the feedback
919  *
920  * @global object
921  * @param object $cm
922  * @param int $group single groupid
923  * @return int count of userrecords
924  */
925 function feedback_count_incomplete_users($cm, $group = false) {
926     if ($allusers = feedback_get_incomplete_users($cm, $group)) {
927         return count($allusers);
928     }
929     return 0;
932 /**
933  * count users which have completed a feedback
934  *
935  * @global object
936  * @uses FEEDBACK_ANONYMOUS_NO
937  * @param object $cm
938  * @param int $group single groupid
939  * @return int count of userrecords
940  */
941 function feedback_count_complete_users($cm, $group = false) {
942     global $DB;
944     $params = array(FEEDBACK_ANONYMOUS_NO, $cm->instance);
946     $fromgroup = '';
947     $wheregroup = '';
948     if ($group) {
949         $fromgroup = ', {groups_members} g';
950         $wheregroup = ' AND g.groupid = ? AND g.userid = c.userid';
951         $params[] = $group;
952     }
954     $sql = 'SELECT COUNT(u.id) FROM {user} u, {feedback_completed} c'.$fromgroup.'
955               WHERE anonymous_response = ? AND u.id = c.userid AND c.feedback = ?
956               '.$wheregroup;
958     return $DB->count_records_sql($sql, $params);
962 /**
963  * get users which have completed a feedback
964  *
965  * @global object
966  * @uses CONTEXT_MODULE
967  * @uses FEEDBACK_ANONYMOUS_NO
968  * @param object $cm
969  * @param int $group single groupid
970  * @param string $where a sql where condition (must end with " AND ")
971  * @param array parameters used in $where
972  * @param string $sort a table field
973  * @param int $startpage
974  * @param int $pagecount
975  * @return object the userrecords
976  */
977 function feedback_get_complete_users($cm,
978                                      $group = false,
979                                      $where = '',
980                                      array $params = null,
981                                      $sort = '',
982                                      $startpage = false,
983                                      $pagecount = false) {
985     global $DB;
987     if (!$context = get_context_instance(CONTEXT_MODULE, $cm->id)) {
988             print_error('badcontext');
989     }
991     $params = (array)$params;
993     $params['anon'] = FEEDBACK_ANONYMOUS_NO;
994     $params['instance'] = $cm->instance;
996     $fromgroup = '';
997     $wheregroup = '';
998     if ($group) {
999         $fromgroup = ', {groups_members} g';
1000         $wheregroup = ' AND g.groupid = :group AND g.userid = c.userid';
1001         $params['group'] = $group;
1002     }
1004     if ($sort) {
1005         $sortsql = ' ORDER BY '.$sort;
1006     } else {
1007         $sortsql = '';
1008     }
1010     $ufields = user_picture::fields('u');
1011     $sql = 'SELECT DISTINCT '.$ufields.', c.timemodified as completed_timemodified
1012             FROM {user} u, {feedback_completed} c '.$fromgroup.'
1013             WHERE '.$where.' anonymous_response = :anon
1014                 AND u.id = c.userid
1015                 AND c.feedback = :instance
1016               '.$wheregroup.$sortsql;
1018     if ($startpage === false OR $pagecount === false) {
1019         $startpage = false;
1020         $pagecount = false;
1021     }
1022     return $DB->get_records_sql($sql, $params, $startpage, $pagecount);
1025 /**
1026  * get users which have the viewreports-capability
1027  *
1028  * @uses CONTEXT_MODULE
1029  * @param int $cmid
1030  * @param mixed $groups single groupid or array of groupids - group(s) user is in
1031  * @return object the userrecords
1032  */
1033 function feedback_get_viewreports_users($cmid, $groups = false) {
1035     if (!$context = get_context_instance(CONTEXT_MODULE, $cmid)) {
1036             print_error('badcontext');
1037     }
1039     //description of the call below:
1040     //get_users_by_capability($context, $capability, $fields='', $sort='', $limitfrom='',
1041     //                          $limitnum='', $groups='', $exceptions='', $doanything=true)
1042     return get_users_by_capability($context,
1043                             'mod/feedback:viewreports',
1044                             '',
1045                             'lastname',
1046                             '',
1047                             '',
1048                             $groups,
1049                             '',
1050                             false);
1053 /**
1054  * get users which have the receivemail-capability
1055  *
1056  * @uses CONTEXT_MODULE
1057  * @param int $cmid
1058  * @param mixed $groups single groupid or array of groupids - group(s) user is in
1059  * @return object the userrecords
1060  */
1061 function feedback_get_receivemail_users($cmid, $groups = false) {
1063     if (!$context = get_context_instance(CONTEXT_MODULE, $cmid)) {
1064             print_error('badcontext');
1065     }
1067     //description of the call below:
1068     //get_users_by_capability($context, $capability, $fields='', $sort='', $limitfrom='',
1069     //                          $limitnum='', $groups='', $exceptions='', $doanything=true)
1070     return get_users_by_capability($context,
1071                             'mod/feedback:receivemail',
1072                             '',
1073                             'lastname',
1074                             '',
1075                             '',
1076                             $groups,
1077                             '',
1078                             false);
1081 ////////////////////////////////////////////////
1082 //functions to handle the templates
1083 ////////////////////////////////////////////////
1084 ////////////////////////////////////////////////
1086 /**
1087  * creates a new template-record.
1088  *
1089  * @global object
1090  * @param int $courseid
1091  * @param string $name the name of template shown in the templatelist
1092  * @param int $ispublic 0:privat 1:public
1093  * @return int the new templateid
1094  */
1095 function feedback_create_template($courseid, $name, $ispublic = 0) {
1096     global $DB;
1098     $templ = new stdClass();
1099     $templ->course   = ($ispublic ? 0 : $courseid);
1100     $templ->name     = $name;
1101     $templ->ispublic = $ispublic;
1103     $templid = $DB->insert_record('feedback_template', $templ);
1104     return $DB->get_record('feedback_template', array('id'=>$templid));
1107 /**
1108  * creates new template items.
1109  * all items will be copied and the attribute feedback will be set to 0
1110  * and the attribute template will be set to the new templateid
1111  *
1112  * @global object
1113  * @uses CONTEXT_MODULE
1114  * @uses CONTEXT_COURSE
1115  * @param object $feedback
1116  * @param string $name the name of template shown in the templatelist
1117  * @param int $ispublic 0:privat 1:public
1118  * @return boolean
1119  */
1120 function feedback_save_as_template($feedback, $name, $ispublic = 0) {
1121     global $DB;
1122     $fs = get_file_storage();
1124     if (!$feedbackitems = $DB->get_records('feedback_item', array('feedback'=>$feedback->id))) {
1125         return false;
1126     }
1128     if (!$newtempl = feedback_create_template($feedback->course, $name, $ispublic)) {
1129         return false;
1130     }
1132     //files in the template_item are in the context of the current course or
1133     //if the template is public the files are in the system context
1134     //files in the feedback_item are in the feedback_context of the feedback
1135     if ($ispublic) {
1136         $s_context = get_system_context();
1137     } else {
1138         $s_context = get_context_instance(CONTEXT_COURSE, $newtempl->course);
1139     }
1140     $cm = get_coursemodule_from_instance('feedback', $feedback->id);
1141     $f_context = get_context_instance(CONTEXT_MODULE, $cm->id);
1143     //create items of this new template
1144     //depend items we are storing temporary in an mapping list array(new id => dependitem)
1145     //we also store a mapping of all items array(oldid => newid)
1146     $dependitemsmap = array();
1147     $itembackup = array();
1148     foreach ($feedbackitems as $item) {
1150         $t_item = clone($item);
1152         unset($t_item->id);
1153         $t_item->feedback = 0;
1154         $t_item->template     = $newtempl->id;
1155         $t_item->id = $DB->insert_record('feedback_item', $t_item);
1156         //copy all included files to the feedback_template filearea
1157         $itemfiles = $fs->get_area_files($f_context->id,
1158                                     'mod_feedback',
1159                                     'item',
1160                                     $item->id,
1161                                     "id",
1162                                     false);
1163         if ($itemfiles) {
1164             foreach ($itemfiles as $ifile) {
1165                 $file_record = new stdClass();
1166                 $file_record->contextid = $s_context->id;
1167                 $file_record->component = 'mod_feedback';
1168                 $file_record->filearea = 'template';
1169                 $file_record->itemid = $t_item->id;
1170                 $fs->create_file_from_storedfile($file_record, $ifile);
1171             }
1172         }
1174         $itembackup[$item->id] = $t_item->id;
1175         if ($t_item->dependitem) {
1176             $dependitemsmap[$t_item->id] = $t_item->dependitem;
1177         }
1179     }
1181     //remapping the dependency
1182     foreach ($dependitemsmap as $key => $dependitem) {
1183         $newitem = $DB->get_record('feedback_item', array('id'=>$key));
1184         $newitem->dependitem = $itembackup[$newitem->dependitem];
1185         $DB->update_record('feedback_item', $newitem);
1186     }
1188     return true;
1191 /**
1192  * deletes all feedback_items related to the given template id
1193  *
1194  * @global object
1195  * @uses CONTEXT_COURSE
1196  * @param object $template the template
1197  * @return void
1198  */
1199 function feedback_delete_template($template) {
1200     global $DB;
1202     //deleting the files from the item is done by feedback_delete_item
1203     if ($t_items = $DB->get_records("feedback_item", array("template"=>$template->id))) {
1204         foreach ($t_items as $t_item) {
1205             feedback_delete_item($t_item->id, false, $template);
1206         }
1207     }
1208     $DB->delete_records("feedback_template", array("id"=>$template->id));
1211 /**
1212  * creates new feedback_item-records from template.
1213  * if $deleteold is set true so the existing items of the given feedback will be deleted
1214  * if $deleteold is set false so the new items will be appanded to the old items
1215  *
1216  * @global object
1217  * @uses CONTEXT_COURSE
1218  * @uses CONTEXT_MODULE
1219  * @param object $feedback
1220  * @param int $templateid
1221  * @param boolean $deleteold
1222  */
1223 function feedback_items_from_template($feedback, $templateid, $deleteold = false) {
1224     global $DB, $CFG;
1226     require_once($CFG->libdir.'/completionlib.php');
1228     $fs = get_file_storage();
1230     if (!$template = $DB->get_record('feedback_template', array('id'=>$templateid))) {
1231         return false;
1232     }
1233     //get all templateitems
1234     if (!$templitems = $DB->get_records('feedback_item', array('template'=>$templateid))) {
1235         return false;
1236     }
1238     //files in the template_item are in the context of the current course
1239     //files in the feedback_item are in the feedback_context of the feedback
1240     if ($template->ispublic) {
1241         $s_context = get_system_context();
1242     } else {
1243         $s_context = get_context_instance(CONTEXT_COURSE, $feedback->course);
1244     }
1245     $course = $DB->get_record('course', array('id'=>$feedback->course));
1246     $cm = get_coursemodule_from_instance('feedback', $feedback->id);
1247     $f_context = get_context_instance(CONTEXT_MODULE, $cm->id);
1249     //if deleteold then delete all old items before
1250     //get all items
1251     if ($deleteold) {
1252         if ($feedbackitems = $DB->get_records('feedback_item', array('feedback'=>$feedback->id))) {
1253             //delete all items of this feedback
1254             foreach ($feedbackitems as $item) {
1255                 feedback_delete_item($item->id, false);
1256             }
1257             //delete tracking-data
1258             $DB->delete_records('feedback_tracking', array('feedback'=>$feedback->id));
1260             $params = array('feedback'=>$feedback->id);
1261             if ($completeds = $DB->get_records('feedback_completed', $params)) {
1262                 $completion = new completion_info($course);
1263                 foreach ($completeds as $completed) {
1264                     // Update completion state
1265                     if ($completion->is_enabled($cm) && $feedback->completionsubmit) {
1266                         $completion->update_state($cm, COMPLETION_INCOMPLETE, $completed->userid);
1267                     }
1268                     $DB->delete_records('feedback_completed', array('id'=>$completed->id));
1269                 }
1270             }
1271             $DB->delete_records('feedback_completedtmp', array('feedback'=>$feedback->id));
1272         }
1273         $positionoffset = 0;
1274     } else {
1275         //if the old items are kept the new items will be appended
1276         //therefor the new position has an offset
1277         $positionoffset = $DB->count_records('feedback_item', array('feedback'=>$feedback->id));
1278     }
1280     //create items of this new template
1281     //depend items we are storing temporary in an mapping list array(new id => dependitem)
1282     //we also store a mapping of all items array(oldid => newid)
1283     $dependitemsmap = array();
1284     $itembackup = array();
1285     foreach ($templitems as $t_item) {
1286         $item = clone($t_item);
1287         unset($item->id);
1288         $item->feedback = $feedback->id;
1289         $item->template = 0;
1290         $item->position = $item->position + $positionoffset;
1292         $item->id = $DB->insert_record('feedback_item', $item);
1294         //moving the files to the new item
1295         $templatefiles = $fs->get_area_files($s_context->id,
1296                                         'mod_feedback',
1297                                         'template',
1298                                         $t_item->id,
1299                                         "id",
1300                                         false);
1301         if ($templatefiles) {
1302             foreach ($templatefiles as $tfile) {
1303                 $file_record = new stdClass();
1304                 $file_record->contextid = $f_context->id;
1305                 $file_record->component = 'mod_feedback';
1306                 $file_record->filearea = 'item';
1307                 $file_record->itemid = $item->id;
1308                 $fs->create_file_from_storedfile($file_record, $tfile);
1309             }
1310         }
1312         $itembackup[$t_item->id] = $item->id;
1313         if ($item->dependitem) {
1314             $dependitemsmap[$item->id] = $item->dependitem;
1315         }
1316     }
1318     //remapping the dependency
1319     foreach ($dependitemsmap as $key => $dependitem) {
1320         $newitem = $DB->get_record('feedback_item', array('id'=>$key));
1321         $newitem->dependitem = $itembackup[$newitem->dependitem];
1322         $DB->update_record('feedback_item', $newitem);
1323     }
1326 /**
1327  * get the list of available templates.
1328  * if the $onlyown param is set true so only templates from own course will be served
1329  * this is important for droping templates
1330  *
1331  * @global object
1332  * @param object $course
1333  * @param string $onlyownorpublic
1334  * @return array the template recordsets
1335  */
1336 function feedback_get_template_list($course, $onlyownorpublic = '') {
1337     global $DB, $CFG;
1339     switch($onlyownorpublic) {
1340         case '':
1341             $templates = $DB->get_records_select('feedback_template',
1342                                                  'course = ? OR ispublic = 1',
1343                                                  array($course->id),
1344                                                  'name');
1345             break;
1346         case 'own':
1347             $templates = $DB->get_records('feedback_template',
1348                                           array('course'=>$course->id),
1349                                           'name');
1350             break;
1351         case 'public':
1352             $templates = $DB->get_records('feedback_template', array('ispublic'=>1), 'name');
1353             break;
1354     }
1355     return $templates;
1358 ////////////////////////////////////////////////
1359 //Handling der Items
1360 ////////////////////////////////////////////////
1361 ////////////////////////////////////////////////
1363 /**
1364  * load the lib.php from item-plugin-dir and returns the instance of the itemclass
1365  *
1366  * @global object
1367  * @param object $item
1368  * @return object the instanz of itemclass
1369  */
1370 function feedback_get_item_class($typ) {
1371     global $CFG;
1373     //get the class of item-typ
1374     $itemclass = 'feedback_item_'.$typ;
1375     //get the instance of item-class
1376     if (!class_exists($itemclass)) {
1377         require_once($CFG->dirroot.'/mod/feedback/item/'.$typ.'/lib.php');
1378     }
1379     return new $itemclass();
1382 /**
1383  * load the available item plugins from given subdirectory of $CFG->dirroot
1384  * the default is "mod/feedback/item"
1385  *
1386  * @global object
1387  * @param string $dir the subdir
1388  * @return array pluginnames as string
1389  */
1390 function feedback_load_feedback_items($dir = 'mod/feedback/item') {
1391     global $CFG;
1392     $names = get_list_of_plugins($dir);
1393     $ret_names = array();
1395     foreach ($names as $name) {
1396         require_once($CFG->dirroot.'/'.$dir.'/'.$name.'/lib.php');
1397         if (class_exists('feedback_item_'.$name)) {
1398             $ret_names[] = $name;
1399         }
1400     }
1401     return $ret_names;
1404 /**
1405  * load the available item plugins to use as dropdown-options
1406  *
1407  * @global object
1408  * @return array pluginnames as string
1409  */
1410 function feedback_load_feedback_items_options() {
1411     global $CFG;
1413     $feedback_options = array("pagebreak" => get_string('add_pagebreak', 'feedback'));
1415     if (!$feedback_names = feedback_load_feedback_items('mod/feedback/item')) {
1416         return array();
1417     }
1419     foreach ($feedback_names as $fn) {
1420         $feedback_options[$fn] = get_string($fn, 'feedback');
1421     }
1422     asort($feedback_options);
1423     $feedback_options = array_merge( array(' ' => get_string('select')), $feedback_options );
1424     return $feedback_options;
1427 /**
1428  * load the available items for the depend item dropdown list shown in the edit_item form
1429  *
1430  * @global object
1431  * @param object $feedback
1432  * @param object $item the item of the edit_item form
1433  * @return array all items except the item $item, labels and pagebreaks
1434  */
1435 function feedback_get_depend_candidates_for_item($feedback, $item) {
1436     global $DB;
1437     //all items for dependitem
1438     $where = "feedback = ? AND typ != 'pagebreak' AND hasvalue = 1";
1439     $params = array($feedback->id);
1440     if (isset($item->id) AND $item->id) {
1441         $where .= ' AND id != ?';
1442         $params[] = $item->id;
1443     }
1444     $dependitems = array(0 => get_string('choose'));
1445     $feedbackitems = $DB->get_records_select_menu('feedback_item',
1446                                                   $where,
1447                                                   $params,
1448                                                   'position',
1449                                                   'id, label');
1451     if (!$feedbackitems) {
1452         return $dependitems;
1453     }
1454     //adding the choose-option
1455     foreach ($feedbackitems as $key => $val) {
1456         $dependitems[$key] = $val;
1457     }
1458     return $dependitems;
1461 /**
1462  * creates a new item-record
1463  *
1464  * @global object
1465  * @param object $data the data from edit_item_form
1466  * @return int the new itemid
1467  */
1468 function feedback_create_item($data) {
1469     global $DB;
1471     $item = new stdClass();
1472     $item->feedback = $data->feedbackid;
1474     $item->template=0;
1475     if (isset($data->templateid)) {
1476             $item->template = intval($data->templateid);
1477     }
1479     $itemname = trim($data->itemname);
1480     $item->name = ($itemname ? $data->itemname : get_string('no_itemname', 'feedback'));
1482     if (!empty($data->itemlabel)) {
1483         $item->label = trim($data->itemlabel);
1484     } else {
1485         $item->label = get_string('no_itemlabel', 'feedback');
1486     }
1488     $itemobj = feedback_get_item_class($data->typ);
1489     $item->presentation = ''; //the date comes from postupdate() of the itemobj
1491     $item->hasvalue = $itemobj->get_hasvalue();
1493     $item->typ = $data->typ;
1494     $item->position = $data->position;
1496     $item->required=0;
1497     if (!empty($data->required)) {
1498         $item->required = $data->required;
1499     }
1501     $item->id = $DB->insert_record('feedback_item', $item);
1503     //move all itemdata to the data
1504     $data->id = $item->id;
1505     $data->feedback = $item->feedback;
1506     $data->name = $item->name;
1507     $data->label = $item->label;
1508     $data->required = $item->required;
1509     return $itemobj->postupdate($data);
1512 /**
1513  * save the changes of a given item.
1514  *
1515  * @global object
1516  * @param object $item
1517  * @return boolean
1518  */
1519 function feedback_update_item($item) {
1520     global $DB;
1521     return $DB->update_record("feedback_item", $item);
1524 /**
1525  * deletes an item and also deletes all related values
1526  *
1527  * @global object
1528  * @uses CONTEXT_MODULE
1529  * @param int $itemid
1530  * @param boolean $renumber should the kept items renumbered Yes/No
1531  * @param object $template if the template is given so the items are bound to it
1532  * @return void
1533  */
1534 function feedback_delete_item($itemid, $renumber = true, $template = false) {
1535     global $DB;
1537     $item = $DB->get_record('feedback_item', array('id'=>$itemid));
1539     //deleting the files from the item
1540     $fs = get_file_storage();
1542     if ($template) {
1543         if ($template->ispublic) {
1544             $context = get_system_context();
1545         } else {
1546             $context = get_context_instance(CONTEXT_COURSE, $template->course);
1547         }
1548         $templatefiles = $fs->get_area_files($context->id,
1549                                     'mod_feedback',
1550                                     'template',
1551                                     $item->id,
1552                                     "id",
1553                                     false);
1555         if ($templatefiles) {
1556             $fs->delete_area_files($context->id, 'mod_feedback', 'template', $item->id);
1557         }
1558     } else {
1559         if (!$cm = get_coursemodule_from_instance('feedback', $item->feedback)) {
1560             return false;
1561         }
1562         $context = get_context_instance(CONTEXT_MODULE, $cm->id);
1564         $itemfiles = $fs->get_area_files($context->id,
1565                                     'mod_feedback',
1566                                     'item',
1567                                     $item->id,
1568                                     "id", false);
1570         if ($itemfiles) {
1571             $fs->delete_area_files($context->id, 'mod_feedback', 'item', $item->id);
1572         }
1573     }
1575     $DB->delete_records("feedback_value", array("item"=>$itemid));
1576     $DB->delete_records("feedback_valuetmp", array("item"=>$itemid));
1578     //remove all depends
1579     $DB->set_field('feedback_item', 'dependvalue', '', array('dependitem'=>$itemid));
1580     $DB->set_field('feedback_item', 'dependitem', 0, array('dependitem'=>$itemid));
1582     $DB->delete_records("feedback_item", array("id"=>$itemid));
1583     if ($renumber) {
1584         feedback_renumber_items($item->feedback);
1585     }
1588 /**
1589  * deletes all items of the given feedbackid
1590  *
1591  * @global object
1592  * @param int $feedbackid
1593  * @return void
1594  */
1595 function feedback_delete_all_items($feedbackid) {
1596     global $DB, $CFG;
1597     require_once($CFG->libdir.'/completionlib.php');
1599     if (!$feedback = $DB->get_record('feedback', array('id'=>$feedbackid))) {
1600         return false;
1601     }
1603     if (!$cm = get_coursemodule_from_instance('feedback', $feedback->id)) {
1604         return false;
1605     }
1607     if (!$course = $DB->get_record('course', array('id'=>$feedback->course))) {
1608         return false;
1609     }
1611     if (!$items = $DB->get_records('feedback_item', array('feedback'=>$feedbackid))) {
1612         return;
1613     }
1614     foreach ($items as $item) {
1615         feedback_delete_item($item->id, false);
1616     }
1617     if ($completeds = $DB->get_records('feedback_completed', array('feedback'=>$feedback->id))) {
1618         $completion = new completion_info($course);
1619         foreach ($completeds as $completed) {
1620             // Update completion state
1621             if ($completion->is_enabled($cm) && $feedback->completionsubmit) {
1622                 $completion->update_state($cm, COMPLETION_INCOMPLETE, $completed->userid);
1623             }
1624             $DB->delete_records('feedback_completed', array('id'=>$completed->id));
1625         }
1626     }
1628     $DB->delete_records('feedback_completedtmp', array('feedback'=>$feedbackid));
1632 /**
1633  * this function toggled the item-attribute required (yes/no)
1634  *
1635  * @global object
1636  * @param object $item
1637  * @return boolean
1638  */
1639 function feedback_switch_item_required($item) {
1640     global $DB, $CFG;
1642     $itemobj = feedback_get_item_class($item->typ);
1644     if ($itemobj->can_switch_require()) {
1645         $new_require_val = (int)!(bool)$item->required;
1646         $params = array('id'=>$item->id);
1647         $DB->set_field('feedback_item', 'required', $new_require_val, $params);
1648     }
1649     return true;
1652 /**
1653  * renumbers all items of the given feedbackid
1654  *
1655  * @global object
1656  * @param int $feedbackid
1657  * @return void
1658  */
1659 function feedback_renumber_items($feedbackid) {
1660     global $DB;
1662     $items = $DB->get_records('feedback_item', array('feedback'=>$feedbackid), 'position');
1663     $pos = 1;
1664     if ($items) {
1665         foreach ($items as $item) {
1666             $DB->set_field('feedback_item', 'position', $pos, array('id'=>$item->id));
1667             $pos++;
1668         }
1669     }
1672 /**
1673  * this decreases the position of the given item
1674  *
1675  * @global object
1676  * @param object $item
1677  * @return bool
1678  */
1679 function feedback_moveup_item($item) {
1680     global $DB;
1682     if ($item->position == 1) {
1683         return true;
1684     }
1686     $params = array('feedback'=>$item->feedback);
1687     if (!$items = $DB->get_records('feedback_item', $params, 'position')) {
1688         return false;
1689     }
1691     $itembefore = null;
1692     foreach ($items as $i) {
1693         if ($i->id == $item->id) {
1694             if (is_null($itembefore)) {
1695                 return true;
1696             }
1697             $itembefore->position = $item->position;
1698             $item->position--;
1699             feedback_update_item($itembefore);
1700             feedback_update_item($item);
1701             feedback_renumber_items($item->feedback);
1702             return true;
1703         }
1704         $itembefore = $i;
1705     }
1706     return false;
1709 /**
1710  * this increased the position of the given item
1711  *
1712  * @global object
1713  * @param object $item
1714  * @return bool
1715  */
1716 function feedback_movedown_item($item) {
1717     global $DB;
1719     $params = array('feedback'=>$item->feedback);
1720     if (!$items = $DB->get_records('feedback_item', $params, 'position')) {
1721         return false;
1722     }
1724     $movedownitem = null;
1725     foreach ($items as $i) {
1726         if (!is_null($movedownitem) AND $movedownitem->id == $item->id) {
1727             $movedownitem->position = $i->position;
1728             $i->position--;
1729             feedback_update_item($movedownitem);
1730             feedback_update_item($i);
1731             feedback_renumber_items($item->feedback);
1732             return true;
1733         }
1734         $movedownitem = $i;
1735     }
1736     return false;
1739 /**
1740  * here the position of the given item will be set to the value in $pos
1741  *
1742  * @global object
1743  * @param object $moveitem
1744  * @param int $pos
1745  * @return boolean
1746  */
1747 function feedback_move_item($moveitem, $pos) {
1748     global $DB;
1750     $params = array('feedback'=>$moveitem->feedback);
1751     if (!$allitems = $DB->get_records('feedback_item', $params, 'position')) {
1752         return false;
1753     }
1754     if (is_array($allitems)) {
1755         $index = 1;
1756         foreach ($allitems as $item) {
1757             if ($index == $pos) {
1758                 $index++;
1759             }
1760             if ($item->id == $moveitem->id) {
1761                 $moveitem->position = $pos;
1762                 feedback_update_item($moveitem);
1763                 continue;
1764             }
1765             $item->position = $index;
1766             feedback_update_item($item);
1767             $index++;
1768         }
1769         return true;
1770     }
1771     return false;
1774 /**
1775  * prints the given item as a preview.
1776  * each item-class has an own print_item_preview function implemented.
1777  *
1778  * @global object
1779  * @param object $item the item what we want to print out
1780  * @return void
1781  */
1782 function feedback_print_item_preview($item) {
1783     global $CFG;
1784     if ($item->typ == 'pagebreak') {
1785         return;
1786     }
1787     //get the instance of the item-class
1788     $itemobj = feedback_get_item_class($item->typ);
1789     $itemobj->print_item_preview($item);
1792 /**
1793  * prints the given item in the completion form.
1794  * each item-class has an own print_item_complete function implemented.
1795  *
1796  * @param object $item the item what we want to print out
1797  * @param mixed $value the value
1798  * @param boolean $highlightrequire if this set true and the value are false on completing so the item will be highlighted
1799  * @return void
1800  */
1801 function feedback_print_item_complete($item, $value = false, $highlightrequire = false) {
1802     global $CFG;
1803     if ($item->typ == 'pagebreak') {
1804         return;
1805     }
1807     //get the instance of the item-class
1808     $itemobj = feedback_get_item_class($item->typ);
1809     $itemobj->print_item_complete($item, $value, $highlightrequire);
1812 /**
1813  * prints the given item in the show entries page.
1814  * each item-class has an own print_item_show_value function implemented.
1815  *
1816  * @param object $item the item what we want to print out
1817  * @param mixed $value
1818  * @return void
1819  */
1820 function feedback_print_item_show_value($item, $value = false) {
1821     global $CFG;
1822     if ($item->typ == 'pagebreak') {
1823         return;
1824     }
1826     //get the instance of the item-class
1827     $itemobj = feedback_get_item_class($item->typ);
1828     $itemobj->print_item_show_value($item, $value);
1831 /**
1832  * if the user completes a feedback and there is a pagebreak so the values are saved temporary.
1833  * the values are not saved permanently until the user click on save button
1834  *
1835  * @global object
1836  * @param object $feedbackcompleted
1837  * @return object temporary saved completed-record
1838  */
1839 function feedback_set_tmp_values($feedbackcompleted) {
1840     global $DB;
1842     //first we create a completedtmp
1843     $tmpcpl = new stdClass();
1844     foreach ($feedbackcompleted as $key => $value) {
1845         $tmpcpl->{$key} = $value;
1846     }
1847     unset($tmpcpl->id);
1848     $tmpcpl->timemodified = time();
1849     $tmpcpl->id = $DB->insert_record('feedback_completedtmp', $tmpcpl);
1850     //get all values of original-completed
1851     if (!$values = $DB->get_records('feedback_value', array('completed'=>$feedbackcompleted->id))) {
1852         return;
1853     }
1854     foreach ($values as $value) {
1855         unset($value->id);
1856         $value->completed = $tmpcpl->id;
1857         $DB->insert_record('feedback_valuetmp', $value);
1858     }
1859     return $tmpcpl;
1862 /**
1863  * this saves the temporary saved values permanently
1864  *
1865  * @global object
1866  * @param object $feedbackcompletedtmp the temporary completed
1867  * @param object $feedbackcompleted the target completed
1868  * @param int $userid
1869  * @return int the id of the completed
1870  */
1871 function feedback_save_tmp_values($feedbackcompletedtmp, $feedbackcompleted, $userid) {
1872     global $DB;
1874     $tmpcplid = $feedbackcompletedtmp->id;
1875     if ($feedbackcompleted) {
1876         //first drop all existing values
1877         $DB->delete_records('feedback_value', array('completed'=>$feedbackcompleted->id));
1878         //update the current completed
1879         $feedbackcompleted->timemodified = time();
1880         $DB->update_record('feedback_completed', $feedbackcompleted);
1881     } else {
1882         $feedbackcompleted = clone($feedbackcompletedtmp);
1883         $feedbackcompleted->id = '';
1884         $feedbackcompleted->userid = $userid;
1885         $feedbackcompleted->timemodified = time();
1886         $feedbackcompleted->id = $DB->insert_record('feedback_completed', $feedbackcompleted);
1887     }
1889     //save all the new values from feedback_valuetmp
1890     //get all values of tmp-completed
1891     $params = array('completed'=>$feedbackcompletedtmp->id);
1892     if (!$values = $DB->get_records('feedback_valuetmp', $params)) {
1893         return false;
1894     }
1895     foreach ($values as $value) {
1896         //check if there are depend items
1897         $item = $DB->get_record('feedback_item', array('id'=>$value->item));
1898         if ($item->dependitem > 0) {
1899             $check = feedback_compare_item_value($tmpcplid,
1900                                         $item->dependitem,
1901                                         $item->dependvalue,
1902                                         true);
1903         } else {
1904             $check = true;
1905         }
1906         if ($check) {
1907             unset($value->id);
1908             $value->completed = $feedbackcompleted->id;
1909             $DB->insert_record('feedback_value', $value);
1910         }
1911     }
1912     //drop all the tmpvalues
1913     $DB->delete_records('feedback_valuetmp', array('completed'=>$tmpcplid));
1914     $DB->delete_records('feedback_completedtmp', array('id'=>$tmpcplid));
1915     return $feedbackcompleted->id;
1919 /**
1920  * deletes the given temporary completed and all related temporary values
1921  *
1922  * @global object
1923  * @param int $tmpcplid
1924  * @return void
1925  */
1926 function feedback_delete_completedtmp($tmpcplid) {
1927     global $DB;
1929     $DB->delete_records('feedback_valuetmp', array('completed'=>$tmpcplid));
1930     $DB->delete_records('feedback_completedtmp', array('id'=>$tmpcplid));
1933 ////////////////////////////////////////////////
1934 ////////////////////////////////////////////////
1935 ////////////////////////////////////////////////
1936 //functions to handle the pagebreaks
1937 ////////////////////////////////////////////////
1939 /**
1940  * this creates a pagebreak.
1941  * a pagebreak is a special kind of item
1942  *
1943  * @global object
1944  * @param int $feedbackid
1945  * @return mixed false if there already is a pagebreak on last position or the id of the pagebreak-item
1946  */
1947 function feedback_create_pagebreak($feedbackid) {
1948     global $DB;
1950     //check if there already is a pagebreak on the last position
1951     $lastposition = $DB->count_records('feedback_item', array('feedback'=>$feedbackid));
1952     if ($lastposition == feedback_get_last_break_position($feedbackid)) {
1953         return false;
1954     }
1956     $item = new stdClass();
1957     $item->feedback = $feedbackid;
1959     $item->template=0;
1961     $item->name = '';
1963     $item->presentation = '';
1964     $item->hasvalue = 0;
1966     $item->typ = 'pagebreak';
1967     $item->position = $lastposition + 1;
1969     $item->required=0;
1971     return $DB->insert_record('feedback_item', $item);
1974 /**
1975  * get all positions of pagebreaks in the given feedback
1976  *
1977  * @global object
1978  * @param int $feedbackid
1979  * @return array all ordered pagebreak positions
1980  */
1981 function feedback_get_all_break_positions($feedbackid) {
1982     global $DB;
1984     $params = array('typ'=>'pagebreak', 'feedback'=>$feedbackid);
1985     $allbreaks = $DB->get_records_menu('feedback_item', $params, 'position', 'id, position');
1986     if (!$allbreaks) {
1987         return false;
1988     }
1989     return array_values($allbreaks);
1992 /**
1993  * get the position of the last pagebreak
1994  *
1995  * @param int $feedbackid
1996  * @return int the position of the last pagebreak
1997  */
1998 function feedback_get_last_break_position($feedbackid) {
1999     if (!$allbreaks = feedback_get_all_break_positions($feedbackid)) {
2000         return false;
2001     }
2002     return $allbreaks[count($allbreaks) - 1];
2005 /**
2006  * this returns the position where the user can continue the completing.
2007  *
2008  * @global object
2009  * @global object
2010  * @global object
2011  * @param int $feedbackid
2012  * @param int $courseid
2013  * @param string $guestid this id will be saved temporary and is unique
2014  * @return int the position to continue
2015  */
2016 function feedback_get_page_to_continue($feedbackid, $courseid = false, $guestid = false) {
2017     global $CFG, $USER, $DB;
2019     //is there any break?
2021     if (!$allbreaks = feedback_get_all_break_positions($feedbackid)) {
2022         return false;
2023     }
2025     $params = array();
2026     if ($courseid) {
2027         $courseselect = "AND fv.course_id = :courseid";
2028         $params['courseid'] = $courseid;
2029     } else {
2030         $courseselect = '';
2031     }
2033     if ($guestid) {
2034         $userselect = "AND fc.guestid = :guestid";
2035         $usergroup = "GROUP BY fc.guestid";
2036         $params['guestid'] = $guestid;
2037     } else {
2038         $userselect = "AND fc.userid = :userid";
2039         $usergroup = "GROUP BY fc.userid";
2040         $params['userid'] = $USER->id;
2041     }
2043     $sql =  "SELECT MAX(fi.position)
2044                FROM {feedback_completedtmp} fc, {feedback_valuetmp} fv, {feedback_item} fi
2045               WHERE fc.id = fv.completed
2046                     $userselect
2047                     AND fc.feedback = :feedbackid
2048                     $courseselect
2049                     AND fi.id = fv.item
2050          $usergroup";
2051     $params['feedbackid'] = $feedbackid;
2053     $lastpos = $DB->get_field_sql($sql, $params);
2055     //the index of found pagebreak is the searched pagenumber
2056     foreach ($allbreaks as $pagenr => $br) {
2057         if ($lastpos < $br) {
2058             return $pagenr;
2059         }
2060     }
2061     return count($allbreaks);
2064 ////////////////////////////////////////////////
2065 ////////////////////////////////////////////////
2066 ////////////////////////////////////////////////
2067 //functions to handle the values
2068 ////////////////////////////////////////////////
2070 /**
2071  * this saves the values of an completed.
2072  * if the param $tmp is set true so the values are saved temporary in table feedback_valuetmp.
2073  * if there is already a completed and the userid is set so the values are updated.
2074  * on all other things new value records will be created.
2075  *
2076  * @global object
2077  * @param int $userid
2078  * @param boolean $tmp
2079  * @return mixed false on error or the completeid
2080  */
2081 function feedback_save_values($usrid, $tmp = false) {
2082     global $DB;
2084     $completedid = optional_param('completedid', 0, PARAM_INT);
2086     $tmpstr = $tmp ? 'tmp' : '';
2087     $time = time();
2088     $timemodified = mktime(0, 0, 0, date('m', $time), date('d', $time), date('Y', $time));
2090     if ($usrid == 0) {
2091         return feedback_create_values($usrid, $timemodified, $tmp);
2092     }
2093     $completed = $DB->get_record('feedback_completed'.$tmpstr, array('id'=>$completedid));
2094     if (!$completed) {
2095         return feedback_create_values($usrid, $timemodified, $tmp);
2096     } else {
2097         $completed->timemodified = $timemodified;
2098         return feedback_update_values($completed, $tmp);
2099     }
2102 /**
2103  * this saves the values from anonymous user such as guest on the main-site
2104  *
2105  * @global object
2106  * @param string $guestid the unique guestidentifier
2107  * @return mixed false on error or the completeid
2108  */
2109 function feedback_save_guest_values($guestid) {
2110     global $DB;
2112     $completedid = optional_param('completedid', false, PARAM_INT);
2114     $timemodified = time();
2115     if (!$completed = $DB->get_record('feedback_completedtmp', array('id'=>$completedid))) {
2116         return feedback_create_values(0, $timemodified, true, $guestid);
2117     } else {
2118         $completed->timemodified = $timemodified;
2119         return feedback_update_values($completed, true);
2120     }
2123 /**
2124  * get the value from the given item related to the given completed.
2125  * the value can come as temporary or as permanently value. the deciding is done by $tmp
2126  *
2127  * @global object
2128  * @param int $completeid
2129  * @param int $itemid
2130  * @param boolean $tmp
2131  * @return mixed the value, the type depends on plugin-definition
2132  */
2133 function feedback_get_item_value($completedid, $itemid, $tmp = false) {
2134     global $DB;
2136     $tmpstr = $tmp ? 'tmp' : '';
2137     $params = array('completed'=>$completedid, 'item'=>$itemid);
2138     return $DB->get_field('feedback_value'.$tmpstr, 'value', $params);
2141 /**
2142  * compares the value of the itemid related to the completedid with the dependvalue.
2143  * this is used if a depend item is set.
2144  * the value can come as temporary or as permanently value. the deciding is done by $tmp.
2145  *
2146  * @global object
2147  * @global object
2148  * @param int $completeid
2149  * @param int $itemid
2150  * @param mixed $dependvalue
2151  * @param boolean $tmp
2152  * @return bool
2153  */
2154 function feedback_compare_item_value($completedid, $itemid, $dependvalue, $tmp = false) {
2155     global $DB, $CFG;
2157     $dbvalue = feedback_get_item_value($completedid, $itemid, $tmp);
2159     //get the class of the given item-typ
2160     $item = $DB->get_record('feedback_item', array('id'=>$itemid));
2162     //get the instance of the item-class
2163     $itemobj = feedback_get_item_class($item->typ);
2164     return $itemobj->compare_value($item, $dbvalue, $dependvalue); //true or false
2167 /**
2168  * this function checks the correctness of values.
2169  * the rules for this are implemented in the class of each item.
2170  * it can be the required attribute or the value self e.g. numeric.
2171  * the params first/lastitem are given to determine the visible range between pagebreaks.
2172  *
2173  * @global object
2174  * @param int $firstitem the position of firstitem for checking
2175  * @param int $lastitem the position of lastitem for checking
2176  * @return boolean
2177  */
2178 function feedback_check_values($firstitem, $lastitem) {
2179     global $DB, $CFG;
2181     $feedbackid = optional_param('feedbackid', 0, PARAM_INT);
2183     //get all items between the first- and lastitem
2184     $select = "feedback = ?
2185                     AND position >= ?
2186                     AND position <= ?
2187                     AND hasvalue = 1";
2188     $params = array($feedbackid, $firstitem, $lastitem);
2189     if (!$feedbackitems = $DB->get_records_select('feedback_item', $select, $params)) {
2190         //if no values are given so no values can be wrong ;-)
2191         return true;
2192     }
2194     foreach ($feedbackitems as $item) {
2195         //get the instance of the item-class
2196         $itemobj = feedback_get_item_class($item->typ);
2198         //the name of the input field of the completeform is given in a special form:
2199         //<item-typ>_<item-id> eg. numeric_234
2200         //this is the key to get the value for the correct item
2201         $formvalname = $item->typ . '_' . $item->id;
2203         if ($itemobj->value_is_array()) {
2204             $value = optional_param_array($formvalname, null, $itemobj->value_type());
2205         } else {
2206             $value = optional_param($formvalname, null, $itemobj->value_type());
2207         }
2209         //check if the value is set
2210         if (is_null($value) AND $item->required == 1) {
2211             return false;
2212         }
2214         //now we let check the value by the item-class
2215         if (!$itemobj->check_value($value, $item)) {
2216             return false;
2217         }
2218     }
2219     //if no wrong values so we can return true
2220     return true;
2223 /**
2224  * this function create a complete-record and the related value-records.
2225  * depending on the $tmp (true/false) the values are saved temporary or permanently
2226  *
2227  * @global object
2228  * @param int $userid
2229  * @param int $timemodified
2230  * @param boolean $tmp
2231  * @param string $guestid a unique identifier to save temporary data
2232  * @return mixed false on error or the completedid
2233  */
2234 function feedback_create_values($usrid, $timemodified, $tmp = false, $guestid = false) {
2235     global $DB;
2237     $feedbackid = optional_param('feedbackid', false, PARAM_INT);
2238     $anonymous_response = optional_param('anonymous_response', false, PARAM_INT);
2239     $courseid = optional_param('courseid', false, PARAM_INT);
2241     $tmpstr = $tmp ? 'tmp' : '';
2242     //first we create a new completed record
2243     $completed = new stdClass();
2244     $completed->feedback           = $feedbackid;
2245     $completed->userid             = $usrid;
2246     $completed->guestid            = $guestid;
2247     $completed->timemodified       = $timemodified;
2248     $completed->anonymous_response = $anonymous_response;
2250     $completedid = $DB->insert_record('feedback_completed'.$tmpstr, $completed);
2252     $completed = $DB->get_record('feedback_completed'.$tmpstr, array('id'=>$completedid));
2254     //the keys are in the form like abc_xxx
2255     //with explode we make an array with(abc, xxx) and (abc=typ und xxx=itemnr)
2257     //get the items of the feedback
2258     if (!$allitems = $DB->get_records('feedback_item', array('feedback'=>$completed->feedback))) {
2259         return false;
2260     }
2261     foreach ($allitems as $item) {
2262         if (!$item->hasvalue) {
2263             continue;
2264         }
2265         //get the class of item-typ
2266         $itemobj = feedback_get_item_class($item->typ);
2268         $keyname = $item->typ.'_'.$item->id;
2270         if ($itemobj->value_is_array()) {
2271             $itemvalue = optional_param_array($keyname, null, $itemobj->value_type());
2272         } else {
2273             $itemvalue = optional_param($keyname, null, $itemobj->value_type());
2274         }
2276         if (is_null($itemvalue)) {
2277             continue;
2278         }
2280         $value = new stdClass();
2281         $value->item = $item->id;
2282         $value->completed = $completed->id;
2283         $value->course_id = $courseid;
2285         //the kind of values can be absolutely different
2286         //so we run create_value directly by the item-class
2287         $value->value = $itemobj->create_value($itemvalue);
2288         $DB->insert_record('feedback_value'.$tmpstr, $value);
2289     }
2290     return $completed->id;
2293 /**
2294  * this function updates a complete-record and the related value-records.
2295  * depending on the $tmp (true/false) the values are saved temporary or permanently
2296  *
2297  * @global object
2298  * @param object $completed
2299  * @param boolean $tmp
2300  * @return int the completedid
2301  */
2302 function feedback_update_values($completed, $tmp = false) {
2303     global $DB;
2305     $courseid = optional_param('courseid', false, PARAM_INT);
2306     $tmpstr = $tmp ? 'tmp' : '';
2308     $DB->update_record('feedback_completed'.$tmpstr, $completed);
2309     //get the values of this completed
2310     $values = $DB->get_records('feedback_value'.$tmpstr, array('completed'=>$completed->id));
2312     //get the items of the feedback
2313     if (!$allitems = $DB->get_records('feedback_item', array('feedback'=>$completed->feedback))) {
2314         return false;
2315     }
2316     foreach ($allitems as $item) {
2317         if (!$item->hasvalue) {
2318             continue;
2319         }
2320         //get the class of item-typ
2321         $itemobj = feedback_get_item_class($item->typ);
2323         $keyname = $item->typ.'_'.$item->id;
2325         if ($itemobj->value_is_array()) {
2326             $itemvalue = optional_param_array($keyname, null, $itemobj->value_type());
2327         } else {
2328             $itemvalue = optional_param($keyname, null, $itemobj->value_type());
2329         }
2331         //is the itemvalue set (could be a subset of items because pagebreak)?
2332         if (is_null($itemvalue)) {
2333             continue;
2334         }
2336         $newvalue = new stdClass();
2337         $newvalue->item = $item->id;
2338         $newvalue->completed = $completed->id;
2339         $newvalue->course_id = $courseid;
2341         //the kind of values can be absolutely different
2342         //so we run create_value directly by the item-class
2343         $newvalue->value = $itemobj->create_value($itemvalue);
2345         //check, if we have to create or update the value
2346         $exist = false;
2347         foreach ($values as $value) {
2348             if ($value->item == $newvalue->item) {
2349                 $newvalue->id = $value->id;
2350                 $exist = true;
2351                 break;
2352             }
2353         }
2354         if ($exist) {
2355             $DB->update_record('feedback_value'.$tmpstr, $newvalue);
2356         } else {
2357             $DB->insert_record('feedback_value'.$tmpstr, $newvalue);
2358         }
2359     }
2361     return $completed->id;
2364 /**
2365  * get the values of an item depending on the given groupid.
2366  * if the feedback is anonymous so the values are shuffled
2367  *
2368  * @global object
2369  * @global object
2370  * @param object $item
2371  * @param int $groupid
2372  * @param int $courseid
2373  * @param bool $ignore_empty if this is set true so empty values are not delivered
2374  * @return array the value-records
2375  */
2376 function feedback_get_group_values($item,
2377                                    $groupid = false,
2378                                    $courseid = false,
2379                                    $ignore_empty = false) {
2381     global $CFG, $DB;
2383     //if the groupid is given?
2384     if (intval($groupid) > 0) {
2385         if ($ignore_empty) {
2386             $ignore_empty_select = "AND fbv.value != '' AND fbv.value != '0'";
2387         } else {
2388             $ignore_empty_select = "";
2389         }
2391         $query = 'SELECT fbv .  *
2392                     FROM {feedback_value} fbv, {feedback_completed} fbc, {groups_members} gm
2393                    WHERE fbv.item = ?
2394                          AND fbv.completed = fbc.id
2395                          AND fbc.userid = gm.userid
2396                          '.$ignore_empty_select.'
2397                          AND gm.groupid = ?
2398                 ORDER BY fbc.timemodified';
2399         $values = $DB->get_records_sql($query, array($item->id, $groupid));
2401     } else {
2402         if ($ignore_empty) {
2403             $ignore_empty_select = "AND value != '' AND value != '0'";
2404         } else {
2405             $ignore_empty_select = "";
2406         }
2408         if ($courseid) {
2409             $select = "item = ? AND course_id = ? ".$ignore_empty_select;
2410             $params = array($item->id, $courseid);
2411             $values = $DB->get_records_select('feedback_value', $select, $params);
2412         } else {
2413             $select = "item = ? ".$ignore_empty_select;
2414             $params = array($item->id);
2415             $values = $DB->get_records_select('feedback_value', $select, $params);
2416         }
2417     }
2418     $params = array('id'=>$item->feedback);
2419     if ($DB->get_field('feedback', 'anonymous', $params) == FEEDBACK_ANONYMOUS_YES) {
2420         if (is_array($values)) {
2421             shuffle($values);
2422         }
2423     }
2424     return $values;
2427 /**
2428  * check for multiple_submit = false.
2429  * if the feedback is global so the courseid must be given
2430  *
2431  * @global object
2432  * @global object
2433  * @param int $feedbackid
2434  * @param int $courseid
2435  * @return boolean true if the feedback already is submitted otherwise false
2436  */
2437 function feedback_is_already_submitted($feedbackid, $courseid = false) {
2438     global $USER, $DB;
2440     $params = array('userid'=>$USER->id, 'feedback'=>$feedbackid);
2441     if (!$trackings = $DB->get_records_menu('feedback_tracking', $params, '', 'id, completed')) {
2442         return false;
2443     }
2445     if ($courseid) {
2446         $select = 'completed IN ('.implode(',', $trackings).') AND course_id = ?';
2447         if (!$values = $DB->get_records_select('feedback_value', $select, array($courseid))) {
2448             return false;
2449         }
2450     }
2452     return true;
2455 /**
2456  * if the completion of a feedback will be continued eg.
2457  * by pagebreak or by multiple submit so the complete must be found.
2458  * if the param $tmp is set true so all things are related to temporary completeds
2459  *
2460  * @global object
2461  * @global object
2462  * @global object
2463  * @param int $feedbackid
2464  * @param boolean $tmp
2465  * @param int $courseid
2466  * @param string $guestid
2467  * @return int the id of the found completed
2468  */
2469 function feedback_get_current_completed($feedbackid,
2470                                         $tmp = false,
2471                                         $courseid = false,
2472                                         $guestid = false) {
2474     global $USER, $CFG, $DB;
2476     $tmpstr = $tmp ? 'tmp' : '';
2478     if (!$courseid) {
2479         if ($guestid) {
2480             $params = array('feedback'=>$feedbackid, 'guestid'=>$guestid);
2481             return $DB->get_record('feedback_completed'.$tmpstr, $params);
2482         } else {
2483             $params = array('feedback'=>$feedbackid, 'userid'=>$USER->id);
2484             return $DB->get_record('feedback_completed'.$tmpstr, $params);
2485         }
2486     }
2488     $params = array();
2490     if ($guestid) {
2491         $userselect = "AND fc.guestid = :guestid";
2492         $params['guestid'] = $guestid;
2493     } else {
2494         $userselect = "AND fc.userid = :userid";
2495         $params['userid'] = $USER->id;
2496     }
2497     //if courseid is set the feedback is global.
2498     //there can be more than one completed on one feedback
2499     $sql =  "SELECT DISTINCT fc.*
2500                FROM {feedback_value{$tmpstr}} fv, {feedback_completed{$tmpstr}} fc
2501               WHERE fv.course_id = :courseid
2502                     AND fv.completed = fc.id
2503                     $userselect
2504                     AND fc.feedback = :feedbackid";
2505     $params['courseid']   = intval($courseid);
2506     $params['feedbackid'] = $feedbackid;
2508     if (!$sqlresult = $DB->get_records_sql($sql, $params)) {
2509         return false;
2510     }
2511     foreach ($sqlresult as $r) {
2512         return $DB->get_record('feedback_completed'.$tmpstr, array('id'=>$r->id));
2513     }
2516 /**
2517  * get the completeds depending on the given groupid.
2518  *
2519  * @global object
2520  * @global object
2521  * @param object $feedback
2522  * @param int $groupid
2523  * @param int $courseid
2524  * @return mixed array of found completeds otherwise false
2525  */
2526 function feedback_get_completeds_group($feedback, $groupid = false, $courseid = false) {
2527     global $CFG, $DB;
2529     if (intval($groupid) > 0) {
2530         $query = "SELECT fbc.*
2531                     FROM {feedback_completed} fbc, {groups_members} gm
2532                    WHERE fbc.feedback = ?
2533                          AND gm.groupid = ?
2534                          AND fbc.userid = gm.userid";
2535         if ($values = $DB->get_records_sql($query, array($feedback->id, $groupid))) {
2536             return $values;
2537         } else {
2538             return false;
2539         }
2540     } else {
2541         if ($courseid) {
2542             $query = "SELECT DISTINCT fbc.*
2543                         FROM {feedback_completed} fbc, {feedback_value} fbv
2544                         WHERE fbc.id = fbv.completed
2545                             AND fbc.feedback = ?
2546                             AND fbv.course_id = ?
2547                         ORDER BY random_response";
2548             if ($values = $DB->get_records_sql($query, array($feedback->id, $courseid))) {
2549                 return $values;
2550             } else {
2551                 return false;
2552             }
2553         } else {
2554             if ($values = $DB->get_records('feedback_completed', array('feedback'=>$feedback->id))) {
2555                 return $values;
2556             } else {
2557                 return false;
2558             }
2559         }
2560     }
2563 /**
2564  * get the count of completeds depending on the given groupid.
2565  *
2566  * @global object
2567  * @global object
2568  * @param object $feedback
2569  * @param int $groupid
2570  * @param int $courseid
2571  * @return mixed count of completeds or false
2572  */
2573 function feedback_get_completeds_group_count($feedback, $groupid = false, $courseid = false) {
2574     global $CFG, $DB;
2576     if ($courseid > 0 AND !$groupid <= 0) {
2577         $sql = "SELECT id, COUNT(item) AS ci
2578                   FROM {feedback_value}
2579                  WHERE course_id  = ?
2580               GROUP BY item ORDER BY ci DESC";
2581         if ($foundrecs = $DB->get_records_sql($sql, array($courseid))) {
2582             $foundrecs = array_values($foundrecs);
2583             return $foundrecs[0]->ci;
2584         }
2585         return false;
2586     }
2587     if ($values = feedback_get_completeds_group($feedback, $groupid)) {
2588         return count($values);
2589     } else {
2590         return false;
2591     }
2594 /**
2595  * deletes all completed-recordsets from a feedback.
2596  * all related data such as values also will be deleted
2597  *
2598  * @global object
2599  * @param int $feedbackid
2600  * @return void
2601  */
2602 function feedback_delete_all_completeds($feedbackid) {
2603     global $DB;
2605     if (!$completeds = $DB->get_records('feedback_completed', array('feedback'=>$feedbackid))) {
2606         return;
2607     }
2608     foreach ($completeds as $completed) {
2609         feedback_delete_completed($completed->id);
2610     }
2613 /**
2614  * deletes a completed given by completedid.
2615  * all related data such values or tracking data also will be deleted
2616  *
2617  * @global object
2618  * @param int $completedid
2619  * @return boolean
2620  */
2621 function feedback_delete_completed($completedid) {
2622     global $DB, $CFG;
2623     require_once($CFG->libdir.'/completionlib.php');
2625     if (!$completed = $DB->get_record('feedback_completed', array('id'=>$completedid))) {
2626         return false;
2627     }
2629     if (!$feedback = $DB->get_record('feedback', array('id'=>$completed->feedback))) {
2630         return false;
2631     }
2633     if (!$course = $DB->get_record('course', array('id'=>$feedback->course))) {
2634         return false;
2635     }
2637     if (!$cm = get_coursemodule_from_instance('feedback', $feedback->id)) {
2638         return false;
2639     }
2641     //first we delete all related values
2642     $DB->delete_records('feedback_value', array('completed'=>$completed->id));
2644     //now we delete all tracking data
2645     $params = array('completed'=>$completed->id, 'feedback'=>$completed->feedback);
2646     if ($tracking = $DB->get_record('feedback_tracking', $params)) {
2647         $DB->delete_records('feedback_tracking', array('completed'=>$completed->id));
2648     }
2650     // Update completion state
2651     $completion = new completion_info($course);
2652     if ($completion->is_enabled($cm) && $feedback->completionsubmit) {
2653         $completion->update_state($cm, COMPLETION_INCOMPLETE, $completed->userid);
2654     }
2655     //last we delete the completed-record
2656     return $DB->delete_records('feedback_completed', array('id'=>$completed->id));
2659 ////////////////////////////////////////////////
2660 ////////////////////////////////////////////////
2661 ////////////////////////////////////////////////
2662 //functions to handle sitecourse mapping
2663 ////////////////////////////////////////////////
2665 /**
2666  * checks if the course and the feedback is in the table feedback_sitecourse_map.
2667  *
2668  * @global object
2669  * @param int $feedbackid
2670  * @param int $courseid
2671  * @return int the count of records
2672  */
2673 function feedback_is_course_in_sitecourse_map($feedbackid, $courseid) {
2674     global $DB;
2675     $params = array('feedbackid'=>$feedbackid, 'courseid'=>$courseid);
2676     return $DB->count_records('feedback_sitecourse_map', $params);
2679 /**
2680  * checks if the feedback is in the table feedback_sitecourse_map.
2681  *
2682  * @global object
2683  * @param int $feedbackid
2684  * @return boolean
2685  */
2686 function feedback_is_feedback_in_sitecourse_map($feedbackid) {
2687     global $DB;
2688     return $DB->record_exists('feedback_sitecourse_map', array('feedbackid'=>$feedbackid));
2691 /**
2692  * gets the feedbacks from table feedback_sitecourse_map.
2693  * this is used to show the global feedbacks on the feedback block
2694  * all feedbacks with the following criteria will be selected:<br />
2695  *
2696  * 1) all feedbacks which id are listed together with the courseid in sitecoursemap and<br />
2697  * 2) all feedbacks which not are listed in sitecoursemap
2698  *
2699  * @global object
2700  * @param int $courseid
2701  * @return array the feedback-records
2702  */
2703 function feedback_get_feedbacks_from_sitecourse_map($courseid) {
2704     global $DB;
2706     //first get all feedbacks listed in sitecourse_map with named courseid
2707     $sql = "SELECT f.id AS id,
2708                    cm.id AS cmid,
2709                    f.name AS name,
2710                    f.timeopen AS timeopen,
2711                    f.timeclose AS timeclose
2712             FROM {feedback} f, {course_modules} cm, {feedback_sitecourse_map} sm, {modules} m
2713             WHERE f.id = cm.instance
2714                    AND f.course = '".SITEID."'
2715                    AND m.id = cm.module
2716                    AND m.name = 'feedback'
2717                    AND sm.courseid = ?
2718                    AND sm.feedbackid = f.id";
2720     if (!$feedbacks1 = $DB->get_records_sql($sql, array($courseid))) {
2721         $feedbacks1 = array();
2722     }
2724     //second get all feedbacks not listed in sitecourse_map
2725     $feedbacks2 = array();
2726     $sql = "SELECT f.id AS id,
2727                    cm.id AS cmid,
2728                    f.name AS name,
2729                    f.timeopen AS timeopen,
2730                    f.timeclose AS timeclose
2731             FROM {feedback} f, {course_modules} cm, {modules} m
2732             WHERE f.id = cm.instance
2733                    AND f.course = '".SITEID."'
2734                    AND m.id = cm.module
2735                    AND m.name = 'feedback'";
2736     if (!$allfeedbacks = $DB->get_records_sql($sql)) {
2737         $allfeedbacks = array();
2738     }
2739     foreach ($allfeedbacks as $a) {
2740         if (!$DB->record_exists('feedback_sitecourse_map', array('feedbackid'=>$a->id))) {
2741             $feedbacks2[] = $a;
2742         }
2743     }
2745     return array_merge($feedbacks1, $feedbacks2);
2749 /**
2750  * gets the courses from table feedback_sitecourse_map.
2751  *
2752  * @global object
2753  * @param int $feedbackid
2754  * @return array the course-records
2755  */
2756 function feedback_get_courses_from_sitecourse_map($feedbackid) {
2757     global $DB;
2759     $sql = "SELECT f.id, f.courseid, c.fullname, c.shortname
2760               FROM {feedback_sitecourse_map} f, {course} c
2761              WHERE c.id = f.courseid
2762                    AND f.feedbackid = ?
2763           ORDER BY c.fullname";
2765     return $DB->get_records_sql($sql, array($feedbackid));
2769 /**
2770  * removes non existing courses or feedbacks from sitecourse_map.
2771  * it shouldn't be called all too often
2772  * a good place for it could be the mapcourse.php or unmapcourse.php
2773  *
2774  * @global object
2775  * @return void
2776  */
2777 function feedback_clean_up_sitecourse_map() {
2778     global $DB;
2780     $maps = $DB->get_records('feedback_sitecourse_map');
2781     foreach ($maps as $map) {
2782         if (!$DB->get_record('course', array('id'=>$map->courseid))) {
2783             $params = array('courseid'=>$map->courseid, 'feedbackid'=>$map->feedbackid);
2784             $DB->delete_records('feedback_sitecourse_map', $params);
2785             continue;
2786         }
2787         if (!$DB->get_record('feedback', array('id'=>$map->feedbackid))) {
2788             $params = array('courseid'=>$map->courseid, 'feedbackid'=>$map->feedbackid);
2789             $DB->delete_records('feedback_sitecourse_map', $params);
2790             continue;
2791         }
2793     }
2796 ////////////////////////////////////////////////
2797 ////////////////////////////////////////////////
2798 ////////////////////////////////////////////////
2799 //not relatable functions
2800 ////////////////////////////////////////////////
2802 /**
2803  * prints the option items of a selection-input item (dropdownlist).
2804  * @param int $startval the first value of the list
2805  * @param int $endval the last value of the list
2806  * @param int $selectval which item should be selected
2807  * @param int $interval the stepsize from the first to the last value
2808  * @return void
2809  */
2810 function feedback_print_numeric_option_list($startval, $endval, $selectval = '', $interval = 1) {
2811     for ($i = $startval; $i <= $endval; $i += $interval) {
2812         if ($selectval == ($i)) {
2813             $selected = 'selected="selected"';
2814         } else {
2815             $selected = '';
2816         }
2817         echo '<option '.$selected.'>'.$i.'</option>';
2818     }
2821 /**
2822  * sends an email to the teachers of the course where the given feedback is placed.
2823  *
2824  * @global object
2825  * @global object
2826  * @uses FEEDBACK_ANONYMOUS_NO
2827  * @uses FORMAT_PLAIN
2828  * @param object $cm the coursemodule-record
2829  * @param object $feedback
2830  * @param object $course
2831  * @param int $userid
2832  * @return void
2833  */
2834 function feedback_send_email($cm, $feedback, $course, $userid) {
2835     global $CFG, $DB;
2837     if ($feedback->email_notification == 0) {  // No need to do anything
2838         return;
2839     }
2841     $user = $DB->get_record('user', array('id'=>$userid));
2843     if (isset($cm->groupmode) && empty($course->groupmodeforce)) {
2844         $groupmode =  $cm->groupmode;
2845     } else {
2846         $groupmode = $course->groupmode;
2847     }
2849     if ($groupmode == SEPARATEGROUPS) {
2850         $groups = $DB->get_records_sql_menu("SELECT g.name, g.id
2851                                                FROM {groups} g, {groups_members} m
2852                                               WHERE g.courseid = ?
2853                                                     AND g.id = m.groupid
2854                                                     AND m.userid = ?
2855                                            ORDER BY name ASC", array($course->id, $userid));
2856         $groups = array_values($groups);
2858         $teachers = feedback_get_receivemail_users($cm->id, $groups);
2859     } else {
2860         $teachers = feedback_get_receivemail_users($cm->id);
2861     }
2863     if ($teachers) {
2865         $strfeedbacks = get_string('modulenameplural', 'feedback');
2866         $strfeedback  = get_string('modulename', 'feedback');
2867         $strcompleted  = get_string('completed', 'feedback');
2869         if ($feedback->anonymous == FEEDBACK_ANONYMOUS_NO) {
2870             $printusername = fullname($user);
2871         } else {
2872             $printusername = get_string('anonymous_user', 'feedback');
2873         }
2875         foreach ($teachers as $teacher) {
2876             $info = new stdClass();
2877             $info->username = $printusername;
2878             $info->feedback = format_string($feedback->name, true);
2879             $info->url = $CFG->wwwroot.'/mod/feedback/show_entries.php?'.
2880                             'id='.$cm->id.'&'.
2881                             'userid='.$userid.'&'.
2882                             'do_show=showentries';
2884             $postsubject = $strcompleted.': '.$info->username.' -> '.$feedback->name;
2885             $posttext = feedback_send_email_text($info, $course);
2887             if ($teacher->mailformat == 1) {
2888                 $posthtml = feedback_send_email_html($info, $course, $cm);
2889             } else {
2890                 $posthtml = '';
2891             }
2893             if ($feedback->anonymous == FEEDBACK_ANONYMOUS_NO) {
2894                 $eventdata = new stdClass();
2895                 $eventdata->name             = 'submission';
2896                 $eventdata->component        = 'mod_feedback';
2897                 $eventdata->userfrom         = $user;
2898                 $eventdata->userto           = $teacher;
2899                 $eventdata->subject          = $postsubject;
2900                 $eventdata->fullmessage      = $posttext;
2901                 $eventdata->fullmessageformat = FORMAT_PLAIN;
2902                 $eventdata->fullmessagehtml  = $posthtml;
2903                 $eventdata->smallmessage     = '';
2904                 message_send($eventdata);
2905             } else {
2906                 $eventdata = new stdClass();
2907                 $eventdata->name             = 'submission';
2908                 $eventdata->component        = 'mod_feedback';
2909                 $eventdata->userfrom         = $teacher;
2910                 $eventdata->userto           = $teacher;
2911                 $eventdata->subject          = $postsubject;
2912                 $eventdata->fullmessage      = $posttext;
2913                 $eventdata->fullmessageformat = FORMAT_PLAIN;
2914                 $eventdata->fullmessagehtml  = $posthtml;
2915                 $eventdata->smallmessage     = '';
2916                 message_send($eventdata);
2917             }
2918         }
2919     }
2922 /**
2923  * sends an email to the teachers of the course where the given feedback is placed.
2924  *
2925  * @global object
2926  * @uses FORMAT_PLAIN
2927  * @param object $cm the coursemodule-record
2928  * @param object $feedback
2929  * @param object $course
2930  * @return void
2931  */
2932 function feedback_send_email_anonym($cm, $feedback, $course) {
2933     global $CFG;
2935     if ($feedback->email_notification == 0) { // No need to do anything
2936         return;
2937     }
2939     $teachers = feedback_get_receivemail_users($cm->id);
2941     if ($teachers) {
2943         $strfeedbacks = get_string('modulenameplural', 'feedback');
2944         $strfeedback  = get_string('modulename', 'feedback');
2945         $strcompleted  = get_string('completed', 'feedback');
2946         $printusername = get_string('anonymous_user', 'feedback');
2948         foreach ($teachers as $teacher) {
2949             $info = new stdClass();
2950             $info->username = $printusername;
2951             $info->feedback = format_string($feedback->name, true);
2952             $info->url = $CFG->wwwroot.'/mod/feedback/show_entries_anonym.php?id='.$cm->id;
2954             $postsubject = $strcompleted.': '.$info->username.' -> '.$feedback->name;
2955             $posttext = feedback_send_email_text($info, $course);
2957             if ($teacher->mailformat == 1) {
2958                 $posthtml = feedback_send_email_html($info, $course, $cm);
2959             } else {
2960                 $posthtml = '';
2961             }
2963             $eventdata = new stdClass();
2964             $eventdata->name             = 'submission';
2965             $eventdata->component        = 'mod_feedback';
2966             $eventdata->userfrom         = $teacher;
2967             $eventdata->userto           = $teacher;
2968             $eventdata->subject          = $postsubject;
2969             $eventdata->fullmessage      = $posttext;
2970             $eventdata->fullmessageformat = FORMAT_PLAIN;
2971             $eventdata->fullmessagehtml  = $posthtml;
2972             $eventdata->smallmessage     = '';
2973             message_send($eventdata);
2974         }
2975     }
2978 /**
2979  * send the text-part of the email
2980  *
2981  * @param object $info includes some infos about the feedback you want to send
2982  * @param object $course
2983  * @return string the text you want to post
2984  */
2985 function feedback_send_email_text($info, $course) {
2986     $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
2987     $courseshortname = format_string($course->shortname, true, array('context' => $coursecontext));
2988     $posttext  = $courseshortname.' -> '.get_string('modulenameplural', 'feedback').' -> '.
2989                     $info->feedback."\n";
2990     $posttext .= '---------------------------------------------------------------------'."\n";
2991     $posttext .= get_string("emailteachermail", "feedback", $info)."\n";
2992     $posttext .= '---------------------------------------------------------------------'."\n";
2993     return $posttext;
2997 /**
2998  * send the html-part of the email
2999  *
3000  * @global object
3001  * @param object $info includes some infos about the feedback you want to send
3002  * @param object $course
3003  * @return string the text you want to post
3004  */
3005 function feedback_send_email_html($info, $course, $cm) {
3006     global $CFG;
3007     $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
3008     $courseshortname = format_string($course->shortname, true, array('context' => $coursecontext));
3009     $course_url = $CFG->wwwroot.'/course/view.php?id='.$course->id;
3010     $feedback_all_url = $CFG->wwwroot.'/mod/feedback/index.php?id='.$course->id;
3011     $feedback_url = $CFG->wwwroot.'/mod/feedback/view.php?id='.$cm->id;
3013     $posthtml = '<p><font face="sans-serif">'.
3014             '<a href="'.$course_url.'">'.$courseshortname.'</a> ->'.
3015             '<a href="'.$feedback_all_url.'">'.get_string('modulenameplural', 'feedback').'</a> ->'.
3016             '<a href="'.$feedback_url.'">'.$info->feedback.'</a></font></p>';
3017     $posthtml .= '<hr /><font face="sans-serif">';
3018     $posthtml .= '<p>'.get_string('emailteachermailhtml', 'feedback', $info).'</p>';
3019     $posthtml .= '</font><hr />';
3020     return $posthtml;
3023 /**
3024  * @param string $url
3025  * @return string
3026  */
3027 function feedback_encode_target_url($url) {
3028     if (strpos($url, '?')) {
3029         list($part1, $part2) = explode('?', $url, 2); //maximal 2 parts
3030         return $part1 . '?' . htmlentities($part2);
3031     } else {
3032         return $url;
3033     }
3036 /**
3037  * Adds module specific settings to the settings block
3038  *
3039  * @param settings_navigation $settings The settings navigation object
3040  * @param navigation_node $feedbacknode The node to add module settings to
3041  */
3042 function feedback_extend_settings_navigation(settings_navigation $settings,
3043                                              navigation_node $feedbacknode) {
3045     global $PAGE, $DB;
3047     if (!$context = get_context_instance(CONTEXT_MODULE, $PAGE->cm->id)) {
3048         print_error('badcontext');
3049     }
3051     if (has_capability('mod/feedback:edititems', $context)) {
3052         $questionnode = $feedbacknode->add(get_string('questions', 'feedback'));
3054         $questionnode->add(get_string('edit_items', 'feedback'),
3055                     new moodle_url('/mod/feedback/edit.php',
3056                                     array('id' => $PAGE->cm->id,
3057                                           'do_show' => 'edit')));
3059         $questionnode->add(get_string('export_questions', 'feedback'),
3060                     new moodle_url('/mod/feedback/export.php',
3061                                     array('id' => $PAGE->cm->id,
3062                                           'action' => 'exportfile')));
3064         $questionnode->add(get_string('import_questions', 'feedback'),
3065                     new moodle_url('/mod/feedback/import.php',
3066                                     array('id' => $PAGE->cm->id)));
3068         $questionnode->add(get_string('templates', 'feedback'),
3069                     new moodle_url('/mod/feedback/edit.php',
3070                                     array('id' => $PAGE->cm->id,
3071                                           'do_show' => 'templates')));
3072     }
3074     if (has_capability('mod/feedback:viewreports', $context)) {
3075         $feedback = $DB->get_record('feedback', array('id'=>$PAGE->cm->instance));
3076         if ($feedback->course == SITEID) {
3077             $feedbacknode->add(get_string('analysis', 'feedback'),
3078                     new moodle_url('/mod/feedback/analysis_course.php',
3079                                     array('id' => $PAGE->cm->id,
3080                                           'course' => $PAGE->course->id,
3081                                           'do_show' => 'analysis')));
3082         } else {
3083             $feedbacknode->add(get_string('analysis', 'feedback'),
3084                     new moodle_url('/mod/feedback/analysis.php',
3085                                     array('id' => $PAGE->cm->id,
3086                                           'course' => $PAGE->course->id,
3087                                           'do_show' => 'analysis')));
3088         }
3090         $feedbacknode->add(get_string('show_entries', 'feedback'),
3091                     new moodle_url('/mod/feedback/show_entries.php',
3092                                     array('id' => $PAGE->cm->id,
3093                                           'do_show' => 'showentries')));
3094     }
3097 function feedback_init_feedback_session() {
3098     //initialize the feedback-Session - not nice at all!!
3099     global $SESSION;
3100     if (!empty($SESSION)) {
3101         if (!isset($SESSION->feedback) OR !is_object($SESSION->feedback)) {
3102             $SESSION->feedback = new stdClass();
3103         }
3104     }
3107 /**
3108  * Return a list of page types
3109  * @param string $pagetype current page type
3110  * @param stdClass $parentcontext Block's parent context
3111  * @param stdClass $currentcontext Current context of block
3112  */
3113 function feedback_page_type_list($pagetype, $parentcontext, $currentcontext) {
3114     $module_pagetype = array('mod-feedback-*'=>get_string('page-mod-feedback-x', 'feedback'));
3115     return $module_pagetype;