MDL-11082 Improved groups upgrade performance 1.8x -> 1.9; thanks Eloy for telling...
[moodle-pu.git] / mod / exercise / lib.php
blobf7f1319bc974d6387cc0b6696985f94bb5402aef
1 <?php // $Id: lib.php,v 1.1 23 Aug 2003
3 // exercise constants and standard moodle functions plus those functions called directly
4 // see locallib.php for other non-standard exercise functions
6 require_once($CFG->libdir.'/filelib.php');
7 require_once('locallib.php');
9 /*** Constants **********************************/
11 $EXERCISE_TYPE = array (0 => get_string("notgraded", "exercise"),
12 1 => get_string("accumulative", "exercise"),
13 2 => get_string("errorbanded", "exercise"),
14 3 => get_string("criterion", "exercise"),
15 4 => get_string("rubric", "exercise") );
17 $EXERCISE_SCALES = array(
18 0 => array( 'name' => get_string("scaleyes", "exercise"), 'type' => 'radio', 'size' => 2, 'start' => get_string("yes"), 'end' => get_string("no")),
19 1 => array( 'name' => get_string("scalepresent", "exercise"), 'type' => 'radio', 'size' => 2, 'start' => get_string("present", "exercise"), 'end' => get_string("absent", "exercise")),
20 2 => array( 'name' => get_string("scalecorrect", "exercise"), 'type' => 'radio', 'size' => 2, 'start' => get_string("correct", "exercise"), 'end' => get_string("incorrect", "exercise")),
21 3 => array( 'name' => get_string("scalegood3", "exercise"), 'type' => 'radio', 'size' => 3, 'start' => get_string("good", "exercise"), 'end' => get_string("poor", "exercise")),
22 4 => array( 'name' => get_string("scaleexcellent4", "exercise"), 'type' => 'radio', 'size' => 4, 'start' => get_string("excellent", "exercise"), 'end' => get_string("verypoor", "exercise")),
23 5 => array( 'name' => get_string("scaleexcellent5", "exercise"), 'type' => 'radio', 'size' => 5, 'start' => get_string("excellent", "exercise"), 'end' => get_string("verypoor", "exercise")),
24 6 => array( 'name' => get_string("scaleexcellent7", "exercise"), 'type' => 'radio', 'size' => 7, 'start' => get_string("excellent", "exercise"), 'end' => get_string("verypoor", "exercise")),
25 7 => array( 'name' => get_string("scale10", "exercise"), 'type' => 'selection', 'size' => 10),
26 8 => array( 'name' => get_string("scale20", "exercise"), 'type' => 'selection', 'size' => 20),
27 9 => array( 'name' => get_string("scale100", "exercise"), 'type' => 'selection', 'size' => 100));
29 $EXERCISE_EWEIGHTS = array( 0 => -4.0, 1 => -2.0, 2 => -1.5, 3 => -1.0, 4 => -0.75, 5 => -0.5, 6 => -0.25,
30 7 => 0.0, 8 => 0.25, 9 => 0.5, 10 => 0.75, 11=> 1.0, 12 => 1.5, 13=> 2.0, 14 => 4.0);
32 $EXERCISE_ASSESSMENT_COMPS = array (
33 0 => array('name' => get_string("verylax", "exercise"), 'value' => 1),
34 1 => array('name' => get_string("lax", "exercise"), 'value' => 0.6),
35 2 => array('name' => get_string("fair", "exercise"), 'value' => 0.4),
36 3 => array('name' => get_string("strict", "exercise"), 'value' => 0.33),
37 4 => array('name' => get_string("verystrict", "exercise"), 'value' => 0.2) );
39 /*** Standard Moodle functions ******************
40 function exercise_add_instance($exercise)
41 function exercise_choose_from_menu ($options, $name, $selected="", $nothing="choose", $script="", $nothingvalue="0", $return=false) {
42 function exercise_cron ()
43 function exercise_delete_instance($id)
44 function exercise_grades($exerciseid)
45 function exercise_print_recent_activity(&$logs, $isteacher=false)
46 function exercise_update_instance($exercise)
47 function exercise_user_outline($course, $user, $mod, $exercise)
48 function exercise_user_complete($course, $user, $mod, $exercise)
49 **********************************************/
51 /*******************************************************************/
52 function exercise_add_instance($exercise) {
53 // Given an object containing all the necessary data,
54 // (defined by the form in mod.html) this function
55 // will create a new instance and return the id number
56 // of the new instance.
58 $exercise->timemodified = time();
60 // encode password if necessary
61 if (!empty($exercise->password)) {
62 $exercise->password = md5($exercise->password);
63 } else {
64 unset($exercise->password);
67 if ($returnid = insert_record("exercise", $exercise)) {
69 $event = NULL;
70 $event->name = $exercise->name;
71 $event->description = $exercise->description;
72 $event->courseid = $exercise->course;
73 $event->groupid = 0;
74 $event->userid = 0;
75 $event->modulename = 'exercise';
76 $event->instance = $returnid;
77 $event->eventtype = 'deadline';
78 $event->timestart = $exercise->deadline;
79 $event->timeduration = 0;
81 add_event($event);
85 return $returnid;
89 /*******************************************************************/
90 function exercise_choose_from_menu ($options, $name, $selected="", $nothing="choose", $script="", $nothingvalue="0", $return=false) {
91 /// Given an array of value, creates a popup menu to be part of a form
92 /// $options["value"]["label"]
94 if ($nothing == "choose") {
95 $nothing = get_string("choose")."...";
98 if ($script) {
99 $javascript = "onChange=\"$script\"";
100 } else {
101 $javascript = "";
104 $output = "<select name=\"$name\" $javascript>\n";
105 if ($nothing) {
106 $output .= " <option value=\"$nothingvalue\"\n";
107 if ($nothingvalue == $selected) {
108 $output .= " selected=\"selected\"";
110 $output .= ">$nothing</option>\n";
112 if (!empty($options)) {
113 foreach ($options as $value => $label) {
114 $output .= " <option value=\"$value\"";
115 if ($value == $selected) {
116 $output .= " selected=\"selected\"";
118 // stop zero label being replaced by array index value
119 // if ($label) {
120 // $output .= ">$label</option>\n";
121 // } else {
122 // $output .= ">$value</option>\n";
123 // }
124 $output .= ">$label</option>\n";
128 $output .= "</select>\n";
130 if ($return) {
131 return $output;
132 } else {
133 echo $output;
138 /*******************************************************************/
139 function exercise_cron() {
140 // Function to be run periodically according to the moodle cron
141 // Finds all exercise notifications that have yet to be mailed out, and mails them
143 global $CFG, $USER;
145 $cutofftime = time() - $CFG->maxeditingtime;
147 // look for new assessments
148 if ($assessments = exercise_get_unmailed_assessments($cutofftime)) {
149 $timenow = time();
151 foreach ($assessments as $assessment) {
152 echo "Processing exercise assessment $assessment->id\n";
153 // switch on mailed
154 if (! set_field("exercise_assessments", "mailed", "1", "id", "$assessment->id")) {
155 echo "Could not update the mailed field for id $assessment->id\n";
157 if (! $submission = get_record("exercise_submissions", "id", "$assessment->submissionid")) {
158 echo "Could not find submission $assessment->submissionid\n";
159 continue;
161 if (! $exercise = get_record("exercise", "id", $submission->exerciseid)) {
162 echo "Could not find exercise record for id $submission->exerciseid\n";
163 continue;
165 if (! $course = get_record("course", "id", "$exercise->course")) {
166 echo "Could not find course $exercise->course\n";
167 continue;
169 if (! $cm = get_coursemodule_from_instance("exercise", $exercise->id, $course->id)) {
170 error("Course Module ID was incorrect");
171 continue;
173 if (! $submissionowner = get_record("user", "id", "$submission->userid")) {
174 echo "Could not find user $submission->userid\n";
175 continue;
177 if (! $assessmentowner = get_record("user", "id", "$assessment->userid")) {
178 echo "Could not find user $assessment->userid\n";
179 continue;
181 if (! isstudent($course->id, $submissionowner->id) and !isteacher($course->id, $submissionowner->id)) {
182 continue; // Not an active participant
184 if (! isstudent($course->id, $assessmentowner->id) and !isteacher($course->id, $assessmentowner->id)) {
185 continue; // Not an active participant
188 // if the submission belongs to a teacher it's a student assessment. No need to email anything.
189 if (isteacher($course->id, $submissionowner->id)) {
190 continue;
193 $strexercises = get_string("modulenameplural", "exercise");
194 $strexercise = get_string("modulename", "exercise");
196 // it's an assessment, tell the submission owner
197 $USER->lang = $submissionowner->lang;
198 $sendto = $submissionowner;
199 // "Your assignment \"$submission->title\" has been assessed by"
200 $msg = get_string("mail1", "exercise", $submission->title).' '.fullname($assessmentowner).".\n";
201 // "The comments and grade can be seen in the exercise assignment '$exercise->name'
202 $msg .= get_string("mail2", "exercise", format_string($exercise->name,true))."\n\n";
204 $postsubject = "$course->shortname: $strexercises: ".format_string($exercise->name,true);
205 $posttext = "$course->shortname -> $strexercises -> ".format_string($exercise->name,true)."\n";
206 $posttext .= "---------------------------------------------------------------------\n";
207 $posttext .= $msg;
208 // "You can see it in your exercise assignment"
209 $posttext .= get_string("mail3", "exercise").":\n";
210 $posttext .= " $CFG->wwwroot/mod/exercise/view.php?id=$cm->id\n";
211 $posttext .= "---------------------------------------------------------------------\n";
212 if ($sendto->mailformat == 1) { // HTML
213 $posthtml = "<p><font face=\"sans-serif\">".
214 "<a href=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</a> ->".
215 "<a href=\"$CFG->wwwroot/mod/exercise/index.php?id=$course->id\">$strexercises</a> ->".
216 "<a href=\"$CFG->wwwroot/mod/exercise/view.php?id=$cm->id\">".format_string($exercise->name,true)."</a></font></p>";
217 $posthtml .= "<hr /><font face=\"sans-serif\">";
218 $posthtml .= "<p>$msg</p>";
219 $posthtml .= "<p>".get_string("mail3", "exercise").
220 " <a href=\"$CFG->wwwroot/mod/exercise/view.php?id=$cm->id\">".format_string($exercise->name,true)."</a>.</p></font><hr />";
221 } else {
222 $posthtml = "";
225 if (!$teacher = get_teacher($course->id)) {
226 echo "Error: can not find teacher for course $course->id!\n";
229 if (! email_to_user($sendto, $teacher, $postsubject, $posttext, $posthtml)) {
230 echo "Error: exercise cron: Could not send out mail for id $submission->id to user $sendto->id ($sendto->email)\n";
234 return true;
238 /*******************************************************************/
239 function exercise_delete_instance($id) {
240 // Given an ID of an instance of this module,
241 // this function will permanently delete the instance
242 // and any data that depends on it.
244 if (! $exercise = get_record("exercise", "id", "$id")) {
245 return false;
248 // delete all the associated records in the exercise tables, start positive...
249 $result = true;
251 if (! delete_records("exercise_grades", "exerciseid", "$exercise->id")) {
252 $result = false;
255 if (! delete_records("exercise_rubrics", "exerciseid", "$exercise->id")) {
256 $result = false;
259 if (! delete_records("exercise_elements", "exerciseid", "$exercise->id")) {
260 $result = false;
263 if (! delete_records("exercise_assessments", "exerciseid", "$exercise->id")) {
264 $result = false;
267 if (! delete_records("exercise_submissions", "exerciseid", "$exercise->id")) {
268 $result = false;
271 if (! delete_records("exercise", "id", "$exercise->id")) {
272 $result = false;
275 return $result;
279 /*******************************************************************/
280 function exercise_grades($exerciseid) {
281 /// Must return an array of grades, indexed by user, and a max grade.
282 if (!$exercise = get_record("exercise", "id", $exerciseid)) {
283 error("Exercise record not found");
286 if (! $course = get_record("course", "id", $exercise->course)) {
287 error("Course is misconfigured");
290 if (!$return->maxgrade = ($exercise->grade + $exercise->gradinggrade)) {
291 return NULL;
293 // how to handle multiple submissions?
294 if ($exercise->usemaximum) {
295 if ($bestgrades = exercise_get_best_submission_grades($exercise)) {
296 foreach ($bestgrades as $grade) {
297 $usergrade[$grade->userid] = $grade->grade * $exercise->grade / 100.0;
302 else { // use mean values
303 if ($meangrades = exercise_get_mean_submission_grades($exercise)) {
304 foreach ($meangrades as $grade) {
305 $usergrade[$grade->userid] = $grade->grade * $exercise->grade / 100.0;
309 // now get the users grading grades
310 if ($assessments = exercise_get_teacher_submission_assessments($exercise)) {
311 foreach ($assessments as $assessment) {
312 // add the grading grade if the student's work has been assessed
313 if (isset($usergrade[$assessment->userid])) {
314 $usergrade[$assessment->userid] += $assessment->gradinggrade * $exercise->gradinggrade / 100.0;
318 // tidy the numbers and set up the return array
319 if (isset($usergrade)) {
320 foreach ($usergrade as $userid => $g) {
321 $return->grades[$userid] = number_format($g, 1);
324 return $return;
328 /*******************************************************************/
329 function exercise_print_recent_activity($course, $isteacher, $timestart) {
330 global $CFG;
332 // have a look for new submissions (only show to teachers)
333 $submitcontent = false;
334 if ($isteacher) {
335 if ($logs = exercise_get_submit_logs($course, $timestart)) {
336 // got some, see if any belong to a visible module
337 foreach ($logs as $log) {
338 // Create a temp valid module structure (only need courseid, moduleid)
339 $tempmod->course = $course->id;
340 $tempmod->id = $log->exerciseid;
341 //Obtain the visible property from the instance
342 if (instance_is_visible('exercise',$tempmod)) {
343 $submitcontent = true;
344 break;
347 // if we got some 'live' ones then output them
348 if ($submitcontent) {
349 print_headline(get_string('exercisesubmissions', 'exercise').':');
350 foreach ($logs as $log) {
351 //Create a temp valid module structure (only need courseid, moduleid)
352 $tempmod->course = $course->id;
353 $tempmod->id = $log->exerciseid;
354 //Obtain the visible property from the instance
355 if (instance_is_visible('exercise',$tempmod)) {
356 print_recent_activity_note($log->time, $log, $log->name,
357 $CFG->wwwroot.'/mod/exercise/'.str_replace('&', '&amp;', $log->url));
364 // have a look for new assessment gradings for this user
365 $gradecontent = false;
366 if ($logs = exercise_get_grade_logs($course, $timestart)) {
367 // got some, see if any belong to a visible module
368 foreach ($logs as $log) {
369 // Create a temp valid module structure (only need courseid, moduleid)
370 $tempmod->course = $course->id;
371 $tempmod->id = $log->exerciseid;
372 //Obtain the visible property from the instance
373 if (instance_is_visible("exercise",$tempmod)) {
374 $gradecontent = true;
375 break;
378 // if we got some "live" ones then output them
379 if ($gradecontent) {
380 print_headline(get_string('exercisefeedback', 'exercise').':');
381 foreach ($logs as $log) {
382 //Create a temp valid module structure (only need courseid, moduleid)
383 $tempmod->course = $course->id;
384 $tempmod->id = $log->exerciseid;
385 //Obtain the visible property from the instance
386 if (instance_is_visible('exercise',$tempmod)) {
387 print_recent_activity_note($log->time, $log, $log->name,
388 $CFG->wwwroot.'/mod/exercise/'.str_replace('&', '&amp;', $log->url));
394 // have a look for new assessments for this user
395 $assesscontent = false;
396 if (!$isteacher) { // teachers only need to see submissions
397 if ($logs = exercise_get_assess_logs($course, $timestart)) {
398 // got some, see if any belong to a visible module
399 foreach ($logs as $log) {
400 // Create a temp valid module structure (only need courseid, moduleid)
401 $tempmod->course = $course->id;
402 $tempmod->id = $log->exerciseid;
403 //Obtain the visible property from the instance
404 if (instance_is_visible("exercise",$tempmod)) {
405 $assesscontent = true;
406 break;
409 // if we got some "live" ones then output them
410 if ($assesscontent) {
411 print_headline(get_string('exerciseassessments', 'exercise').':');
412 foreach ($logs as $log) {
413 //Create a temp valid module structure (only need courseid, moduleid)
414 $tempmod->course = $course->id;
415 $tempmod->id = $log->exerciseid;
416 //Obtain the visible property from the instance
417 if (instance_is_visible('exercise',$tempmod)) {
418 print_recent_activity_note($log->time, $log, $log->name,
419 $CFG->wwwroot.'/mod/exercise/'.str_replace('&', '&amp;', $log->url));
425 return $submitcontent or $gradecontent or $assesscontent;
429 ///////////////////////////////////////////////////////////////////////////////
430 function exercise_refresh_events($courseid = 0) {
431 // This standard function will check all instances of this module
432 // and make sure there are up-to-date events created for each of them.
433 // If courseid = 0, then every exercise event in the site is checked, else
434 // only exercise events belonging to the course specified are checked.
435 // This function is used, in its new format, by restore_refresh_events()
437 if ($courseid == 0) {
438 if (! $exercises = get_records("exercise")) {
439 return true;
441 } else {
442 if (! $exercises = get_records("exercise", "course", $courseid)) {
443 return true;
446 $moduleid = get_field('modules', 'id', 'name', 'exercise');
448 foreach ($exercises as $exercise) {
449 $event = NULL;
450 $event->name = addslashes($exercise->name);
451 $event->description = addslashes($exercise->description);
452 $event->timestart = $exercise->deadline;
454 if ($event->id = get_field('event', 'id', 'modulename', 'exercise', 'instance', $exercise->id)) {
455 update_event($event);
457 } else {
458 $event->courseid = $exercise->course;
459 $event->groupid = 0;
460 $event->userid = 0;
461 $event->modulename = 'exercise';
462 $event->instance = $exercise->id;
463 $event->eventtype = 'deadline';
464 $event->timeduration = 0;
465 $event->visible = get_field('course_modules', 'visible', 'module', $moduleid, 'instance', $exercise->id);
466 add_event($event);
470 return true;
474 /*******************************************************************/
475 function exercise_update_instance($exercise) {
476 // Given an object containing all the necessary data,
477 // (defined by the form in mod.html) this function
478 // will update an existing instance with new data.
480 $exercise->timemodified = time();
482 // encode password if necessary
483 if (!empty($exercise->password)) {
484 $exercise->password = md5($exercise->password);
485 } else {
486 unset($exercise->password);
489 $exercise->id = $exercise->instance;
491 if ($returnid = update_record("exercise", $exercise)) {
493 $event = NULL;
495 if ($event->id = get_field('event', 'id', 'modulename', 'exercise', 'instance', $exercise->id)) {
497 $event->name = $exercise->name;
498 $event->description = $exercise->description;
499 $event->timestart = $exercise->deadline;
501 update_event($event);
505 return $returnid;
509 /*******************************************************************/
510 function exercise_user_complete($course, $user, $mod, $exercise) {
511 if ($submissions = exercise_get_user_submissions($exercise, $user)) {
512 print_simple_box_start();
513 $table->head = array (get_string("submission", "exercise"), get_string("submitted", "exercise"),
514 get_string("assessed", "exercise"), get_string("grade"));
515 $table->width = "100%";
516 $table->align = array ("left", "left", "left", "center");
517 $table->size = array ("*", "*", "*", "*");
518 $table->cellpadding = 2;
519 $table->cellspacing = 0;
521 foreach ($submissions as $submission) {
522 if ($assessments = exercise_get_assessments($submission)) {
523 // should only be one but we'll loop anyway
524 foreach ($assessments as $assessment) {
525 $table->data[] = array(exercise_print_submission_title($exercise, $submission),
526 userdate($submission->timecreated), userdate($assessment->timecreated),
527 $assessment->grade * $exercise->grade / 100.0);
529 } else {
530 // submission not yet assessed (by teacher)
531 $table->data[] = array(exercise_print_submission_title($exercise, $submission),
532 userdate($submission->timecreated), get_string("notassessedyet", "exercise"), 0);
535 print_table($table);
536 print_simple_box_end();
537 } else {
538 print_string("nosubmissions", "exercise");
543 /*******************************************************************/
544 function exercise_user_outline($course, $user, $mod, $exercise) {
545 if ($submissions = exercise_get_user_submissions($exercise, $user)) {
546 $result->info = count($submissions)." ".get_string("submissions", "exercise");
547 foreach ($submissions as $submission) { // the first one is the most recent one
548 $result->time = $submission->timecreated;
549 break;
551 return $result;
553 return NULL;
557 /*******************************************************************/
558 function exercise_get_participants($exerciseid) {
559 //Returns the users with data in one exercise
560 //(users with records in exercise_submissions and exercise_assessments, students)
562 global $CFG;
564 //Get students from exercise_submissions
565 $st_submissions = get_records_sql("SELECT DISTINCT u.id, u.id
566 FROM {$CFG->prefix}user u,
567 {$CFG->prefix}exercise_submissions s
568 WHERE s.exerciseid = '$exerciseid' and
569 u.id = s.userid");
570 //Get students from exercise_assessments
571 $st_assessments = get_records_sql("SELECT DISTINCT u.id, u.id
572 FROM {$CFG->prefix}user u,
573 {$CFG->prefix}exercise_assessments a
574 WHERE a.exerciseid = '$exerciseid' and
575 u.id = a.userid");
577 //Add st_assessments to st_submissions
578 if ($st_assessments) {
579 foreach ($st_assessments as $st_assessment) {
580 $st_submissions[$st_assessment->id] = $st_assessment;
583 //Return st_submissions array (it contains an array of unique users)
584 return ($st_submissions);
588 ///////////////////////////////////////////////////////////////////////////////////////////////
589 // Non-standard Exercise functions
590 ///////////////////////////////////////////////////////////////////////////////////////////////
591 function exercise_file_area($exercise, $submission) {
592 return make_upload_directory( exercise_file_area_name($exercise, $submission) );
596 ///////////////////////////////////////////////////////////////////////////////////////////////
597 function exercise_file_area_name($exercise, $submission) {
598 // Creates a directory file name, suitable for make_upload_directory()
599 global $CFG;
601 return "$exercise->course/$CFG->moddata/exercise/$submission->id";
605 ///////////////////////////////////////////////////////////////////////////////////////////////
606 function exercise_get_assess_logs($course, $timestart) {
607 // get the "assess" entries for this user and add the first and last names...
608 global $CFG, $USER;
609 if (empty($USER->id)) {
610 return false;
612 $timethen = time() - $CFG->maxeditingtime;
613 return get_records_sql("SELECT l.time, l.url, u.firstname, u.lastname, a.exerciseid, e.name
614 FROM {$CFG->prefix}log l,
615 {$CFG->prefix}exercise e,
616 {$CFG->prefix}exercise_submissions s,
617 {$CFG->prefix}exercise_assessments a,
618 {$CFG->prefix}user u
619 WHERE l.time > $timestart AND l.time < $timethen
620 AND l.course = $course->id AND l.module = 'exercise' AND l.action = 'assess'
621 AND a.id = l.info AND s.id = a.submissionid AND s.userid = $USER->id
622 AND u.id = a.userid AND e.id = a.exerciseid");
626 ///////////////////////////////////////////////////////////////////////////////////////////////
627 function exercise_get_assessments($submission) {
628 // Return all assessments for this submission provided they are after the editing time,
629 // ordered oldest first, newest last
630 global $CFG;
632 $timenow = time();
633 return get_records_select("exercise_assessments", "(submissionid = $submission->id) AND
634 (timecreated < $timenow - $CFG->maxeditingtime)", "timecreated ASC");
638 ///////////////////////////////////////////////////////////////////////////////////////////////
639 function exercise_get_best_grade($submission) {
640 // Returns the best grade of students' submission (there may, occassionally be more than one assessment)
641 global $CFG;
643 return get_record_sql("SELECT MAX(a.grade) AS grade FROM
644 {$CFG->prefix}exercise_assessments a
645 WHERE a.submissionid = $submission->id
646 GROUP BY a.submissionid");
650 ///////////////////////////////////////////////////////////////////////////////////////////////
651 function exercise_get_grade_logs($course, $timestart) {
652 // get the "grade" entries for this user and add the first and last names...
653 global $CFG, $USER;
654 if (empty($USER->id)) {
655 return false;
658 $timethen = time() - $CFG->maxeditingtime;
659 return get_records_sql("SELECT l.time, l.url, u.firstname, u.lastname, a.exerciseid, e.name
660 FROM {$CFG->prefix}log l,
661 {$CFG->prefix}exercise e,
662 {$CFG->prefix}exercise_submissions s,
663 {$CFG->prefix}exercise_assessments a,
664 {$CFG->prefix}user u
665 WHERE l.time > $timestart AND l.time < $timethen
666 AND l.course = $course->id AND l.module = 'exercise' AND l.action = 'grade'
667 AND a.id = l.info AND s.id = a.submissionid AND a.userid = $USER->id
668 AND u.id = s.userid AND e.id = a.exerciseid");
672 ///////////////////////////////////////////////////////////////////////////////////////////////
673 function exercise_get_mean_submission_grades($exercise) {
674 // Returns the mean grades of students' submissions
675 // ignores hot assessments
676 global $CFG;
678 $timenow = time();
679 $grades = get_records_sql("SELECT DISTINCT u.userid, AVG(a.grade) AS grade FROM
680 {$CFG->prefix}exercise_submissions s,
681 {$CFG->prefix}exercise_assessments a
682 WHERE
683 AND s.exerciseid = $exercise->id
684 AND s.late = 0
685 AND a.submissionid = s.id
686 AND a.timecreated < $timenow
687 GROUP BY s.userid");
688 return $grades;
692 ///////////////////////////////////////////////////////////////////////////////////////////////
693 function exercise_get_submit_logs($course, $timestart) {
694 // get the "submit" entries and add the first and last names...
695 global $CFG, $USER;
697 $timethen = time() - $CFG->maxeditingtime;
698 return get_records_sql("SELECT l.time, l.url, u.firstname, u.lastname, l.info as exerciseid, e.name
699 FROM {$CFG->prefix}log l,
700 {$CFG->prefix}exercise e,
701 {$CFG->prefix}user u
702 WHERE l.time > $timestart AND l.time < $timethen
703 AND l.course = $course->id AND l.module = 'exercise'
704 AND l.action = 'submit'
705 AND e.id = l.info
706 AND u.id = l.userid");
710 ///////////////////////////////////////////////////////////////////////////////////////////////
711 function exercise_get_teacher_submission_assessments($exercise) {
712 // Return all assessments on the teacher submissions, order by youngest first, oldest last
713 global $CFG;
715 return get_records_sql("SELECT a.* FROM {$CFG->prefix}exercise_submissions s, {$CFG->prefix}exercise_assessments a
716 WHERE s.isexercise = 1
717 AND s.exerciseid = $exercise->id
718 AND a.submissionid = s.id
719 ORDER BY a.timecreated DESC");
723 ///////////////////////////////////////////////////////////////////////////////////////////////
724 function exercise_get_unmailed_assessments($cutofftime) {
725 /// Return list of (ungraded) assessments that have not been mailed out
726 global $CFG;
727 return get_records_sql("SELECT a.*, e.course, e.name
728 FROM {$CFG->prefix}exercise_assessments a, {$CFG->prefix}exercise e
729 WHERE a.mailed = 0
730 AND a.timecreated < $cutofftime
731 AND e.id = a.exerciseid");
735 ///////////////////////////////////////////////////////////////////////////////////////////////
736 function exercise_get_user_submissions($exercise, $user) {
737 // return submission of user oldest first, newest last
738 // teachers submit "exercises"
739 if (! $course = get_record("course", "id", $exercise->course)) {
740 error("Course is misconfigured");
742 if (isteacher($course->id, $user->id)) {
743 return get_records_select("exercise_submissions",
744 "exerciseid = $exercise->id AND isexercise = 1", "timecreated" );
746 return get_records_select("exercise_submissions",
747 "exerciseid = $exercise->id AND userid = $user->id", "timecreated" );
751 ///////////////////////////////////////////////////////////////////////////////////////////////
752 function exercise_print_submission_title($exercise, $submission) {
753 global $CFG;
755 if (!$submission->timecreated) { // a "no submission"
756 return $submission->title;
759 $filearea = exercise_file_area_name($exercise, $submission);
760 if ($basedir = exercise_file_area($exercise, $submission)) {
761 if (list($file) = get_directory_list($basedir)) {
762 $icon = mimeinfo("icon", $file);
763 if ($CFG->slasharguments) {
764 $ffurl = "file.php/$filearea/$file";
765 } else {
766 $ffurl = "file.php?file=/$filearea/$file";
768 return "<img src=\"$CFG->pixpath/f/$icon\" class=\"icon\" alt=\"".get_string('file')."\" />".
769 "&nbsp;<a target=\"uploadedfile\" href=\"$CFG->wwwroot/$ffurl\">$submission->title</a>";
774 function exercise_get_view_actions() {
775 return array('view','view all','display');
778 function exercise_get_post_actions() {
779 return array('assess','delete','grade','open','set up','submit');