Fix a possible race condition in the PaintWeb DML code.
[moodle/mihaisucan.git] / mod / workshop / lib.php
blob65409e5c84706e27472813d4486ce158a9c6d25d
1 <?php // $Id$
3 // workshop constants and standard Moodle functions plus the workshop functions
4 // called by the standard functions
6 // see also locallib.php for other non-standard workshop functions
8 require_once($CFG->libdir.'/filelib.php');
10 /*** Constants **********************************/
13 $WORKSHOP_EWEIGHTS = array( 0 => -4.0, 1 => -2.0, 2 => -1.5, 3 => -1.0, 4 => -0.75, 5 => -0.5, 6 => -0.25,
14 7 => 0.0, 8 => 0.25, 9 => 0.5, 10 => 0.75, 11=> 1.0, 12 => 1.5, 13=> 2.0,
15 14 => 4.0);
17 $WORKSHOP_FWEIGHTS = array( 0 => 0, 1 => 0.1, 2 => 0.25, 3 => 0.5, 4 => 0.75, 5 => 1.0, 6 => 1.5,
18 7 => 2.0, 8 => 3.0, 9 => 5.0, 10 => 7.5, 11=> 10.0, 12=>50.0);
21 $WORKSHOP_ASSESSMENT_COMPS = array (
22 0 => array('name' => get_string('verylax', 'workshop'), 'value' => 1),
23 1 => array('name' => get_string('lax', 'workshop'), 'value' => 0.6),
24 2 => array('name' => get_string('fair', 'workshop'), 'value' => 0.4),
25 3 => array('name' => get_string('strict', 'workshop'), 'value' => 0.33),
26 4 => array('name' => get_string('verystrict', 'workshop'), 'value' => 0.2) );
29 /*** Moodle 1.7 compatibility functions *****
31 ********************************************/
32 function workshop_context($workshop) {
33 //TODO: add some $cm caching if needed
34 if (is_object($workshop)) {
35 $workshop = $workshop->id;
37 if (! $cm = get_coursemodule_from_instance('workshop', $workshop)) {
38 error('Course Module ID was incorrect');
41 return get_context_instance(CONTEXT_MODULE, $cm->id);
44 function workshop_is_teacher($workshop, $userid=NULL) {
45 return has_capability('mod/workshop:manage', workshop_context($workshop), $userid);
48 function workshop_is_teacheredit($workshop, $userid=NULL) {
49 return has_capability('mod/workshop:manage', workshop_context($workshop), $userid)
50 and has_capability('moodle/site:accessallgroups', workshop_context($workshop), $userid);
53 function workshop_is_student($workshop, $userid=NULL) {
54 return has_capability('mod/workshop:participate', workshop_context($workshop), $userid);
57 function workshop_get_students($workshop, $sort='u.lastaccess', $fields='u.*') {
58 return $users = get_users_by_capability(workshop_context($workshop), 'mod/workshop:participate', $fields, $sort);
61 function workshop_get_teachers($workshop, $sort='u.lastaccess', $fields='u.*') {
62 return $users = get_users_by_capability(workshop_context($workshop), 'mod/workshop:manage', $fields, $sort);
66 /*** Standard Moodle functions ******************
67 workshop_add_instance($workshop)
68 workshop_check_dates($workshop)
69 workshop_cron ()
70 workshop_delete_instance($id)
71 workshop_grades($workshopid)
72 workshop_print_recent_activity(&$logs, $isteacher=false)
73 workshop_refresh_events($workshop)
74 workshop_update_instance($workshop)
75 workshop_user_complete($course, $user, $mod, $workshop)
76 workshop_user_outline($course, $user, $mod, $workshop)
77 **********************************************/
79 ///////////////////////////////////////////////////////////////////////////////
80 function workshop_add_instance($workshop) {
81 // Given an object containing all the necessary data,
82 // (defined by the form in mod.html) this function
83 // will create a new instance and return the id number
84 // of the new instance.
86 $workshop->timemodified = time();
88 $workshop->submissionstart = make_timestamp($workshop->submissionstartyear,
89 $workshop->submissionstartmonth, $workshop->submissionstartday, $workshop->submissionstarthour,
90 $workshop->submissionstartminute);
92 $workshop->assessmentstart = make_timestamp($workshop->assessmentstartyear,
93 $workshop->assessmentstartmonth, $workshop->assessmentstartday, $workshop->assessmentstarthour,
94 $workshop->assessmentstartminute);
96 $workshop->submissionend = make_timestamp($workshop->submissionendyear,
97 $workshop->submissionendmonth, $workshop->submissionendday, $workshop->submissionendhour,
98 $workshop->submissionendminute);
100 $workshop->assessmentend = make_timestamp($workshop->assessmentendyear,
101 $workshop->assessmentendmonth, $workshop->assessmentendday, $workshop->assessmentendhour,
102 $workshop->assessmentendminute);
104 $workshop->releasegrades = make_timestamp($workshop->releaseyear,
105 $workshop->releasemonth, $workshop->releaseday, $workshop->releasehour,
106 $workshop->releaseminute);
108 if (!workshop_check_dates($workshop)) {
109 return get_string('invaliddates', 'workshop');
112 // set the workshop's type
113 $wtype = 0; // 3 phases, no grading grades
114 if ($workshop->includeself or $workshop->ntassessments) $wtype = 1; // 3 phases with grading grades
115 if ($workshop->nsassessments) $wtype = 2; // 5 phases with grading grades
116 $workshop->wtype = $wtype;
118 if ($returnid = insert_record("workshop", $workshop)) {
120 $event = NULL;
121 $event->name = get_string('submissionstartevent','workshop', $workshop->name);
122 $event->description = $workshop->description;
123 $event->courseid = $workshop->course;
124 $event->groupid = 0;
125 $event->userid = 0;
126 $event->modulename = 'workshop';
127 $event->instance = $returnid;
128 $event->eventtype = 'submissionstart';
129 $event->timestart = $workshop->submissionstart;
130 $event->timeduration = 0;
131 add_event($event);
133 $event->name = get_string('submissionendevent','workshop', $workshop->name);
134 $event->eventtype = 'submissionend';
135 $event->timestart = $workshop->submissionend;
136 add_event($event);
138 $event->name = get_string('assessmentstartevent','workshop', $workshop->name);
139 $event->eventtype = 'assessmentstart';
140 $event->timestart = $workshop->assessmentstart;
141 add_event($event);
143 $event->name = get_string('assessmentendevent','workshop', $workshop->name);
144 $event->eventtype = 'assessmentend';
145 $event->timestart = $workshop->assessmentend;
146 add_event($event);
149 return $returnid;
152 ///////////////////////////////////////////////////////////////////////////////
153 // returns true if the dates are valid, false otherwise
154 function workshop_check_dates($workshop) {
155 // allow submission and assessment to start on the same date and to end on the same date
156 // but enforce non-empty submission period and non-empty assessment period.
157 return ($workshop->submissionstart < $workshop->submissionend and
158 $workshop->submissionstart <= $workshop->assessmentstart and
159 $workshop->assessmentstart < $workshop->assessmentend and
160 $workshop->submissionend <= $workshop->assessmentend);
164 ///////////////////////////////////////////////////////////////////////////////
165 function workshop_cron () {
166 // Function to be run periodically according to the moodle cron
168 global $CFG, $USER;
170 // if there any ungraded assessments run the grading routine
171 if ($workshops = get_records("workshop")) {
172 foreach ($workshops as $workshop) {
173 // automatically grade assessments if workshop has examples and/or peer assessments
174 if ($workshop->gradingstrategy and ($workshop->ntassessments or $workshop->nsassessments)) {
175 workshop_grade_assessments($workshop);
179 $timenow = time();
181 // Find all workshop notifications that have yet to be mailed out, and mails them
182 $cutofftime = $timenow - $CFG->maxeditingtime;
184 // look for new assessments
185 if ($assessments = workshop_get_unmailed_assessments($cutofftime)) {
186 foreach ($assessments as $assessment) {
188 echo "Processing workshop assessment $assessment->id\n";
190 // only process the entry once
191 if (! set_field("workshop_assessments", "mailed", "1", "id", "$assessment->id")) {
192 echo "Could not update the mailed field for id $assessment->id\n";
195 if (! $submission = get_record("workshop_submissions", "id", "$assessment->submissionid")) {
196 echo "Could not find submission $assessment->submissionid\n";
197 continue;
199 if (! $workshop = get_record("workshop", "id", $submission->workshopid)) {
200 echo "Could not find workshop id $submission->workshopid\n";
201 continue;
203 if (! $course = get_record("course", "id", $workshop->course)) {
204 error("Could not find course id $workshop->course");
205 continue;
207 if (! $cm = get_coursemodule_from_instance("workshop", $workshop->id, $course->id)) {
208 error("Course Module ID was incorrect");
209 continue;
211 if (! $submissionowner = get_record("user", "id", "$submission->userid")) {
212 echo "Could not find user $submission->userid\n";
213 continue;
215 if (! $assessmentowner = get_record("user", "id", "$assessment->userid")) {
216 echo "Could not find user $assessment->userid\n";
217 continue;
219 if (! workshop_is_student($workshop, $submissionowner->id) and !workshop_is_teacher($workshop,
220 $submissionowner->id)) {
221 continue; // Not an active participant
223 if (! workshop_is_student($workshop, $assessmentowner->id) and !workshop_is_teacher($workshop,
224 $assessmentowner->id)) {
225 continue; // Not an active participant
227 // don't sent self assessment
228 if ($submissionowner->id == $assessmentowner->id) {
229 continue;
231 $strworkshops = get_string("modulenameplural", "workshop");
232 $strworkshop = get_string("modulename", "workshop");
234 // it's an assessment, tell the submission owner
235 $USER->lang = $submissionowner->lang;
236 $sendto = $submissionowner;
237 // "Your assignment \"$submission->title\" has been assessed by"
238 if (workshop_is_student($workshop, $assessmentowner->id)) {
239 $msg = get_string("mail1", "workshop", $submission->title)." a $course->student.\n";
241 else {
242 $msg = get_string("mail1", "workshop", $submission->title).
243 " ".fullname($assessmentowner)."\n";
245 // "The comments and grade can be seen in the workshop assignment '$workshop->name'
246 // I have taken the following line out because the info is repeated below.
247 // $msg .= get_string("mail2", "workshop", $workshop->name)."\n\n";
249 $postsubject = "$course->shortname: $strworkshops: ".format_string($workshop->name,true);
250 $posttext = "$course->shortname -> $strworkshops -> ".format_string($workshop->name,true)."\n";
251 $posttext .= "---------------------------------------------------------------------\n";
252 $posttext .= $msg;
253 // "The comments and grade can be seen in ..."
254 $posttext .= get_string("mail2", "workshop",
255 format_string($workshop->name,true).", $CFG->wwwroot/mod/workshop/view.php?id=$cm->id")."\n";
256 $posttext .= "---------------------------------------------------------------------\n";
257 if ($sendto->mailformat == 1) { // HTML
258 $posthtml = "<p><font face=\"sans-serif\">".
259 "<a href=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</a> ->".
260 "<a href=\"$CFG->wwwroot/mod/workshop/index.php?id=$course->id\">$strworkshops</a> ->".
261 "<a href=\"$CFG->wwwroot/mod/workshop/view.php?id=$cm->id\">".format_string($workshop->name,true)."</a></font></p>";
262 $posthtml .= "<hr><font face=\"sans-serif\">";
263 $posthtml .= "<p>$msg</p>";
264 $posthtml .= "<p>".get_string("mail2", "workshop",
265 " <a href=\"$CFG->wwwroot/mod/workshop/view.php?id=$cm->id\">".format_string($workshop->name,true)."</a>")."</p></font><hr>";
266 } else {
267 $posthtml = "";
270 if (!$teacher = get_teacher($course->id)) {
271 echo "Error: can not find teacher for course $course->id!\n";
274 if (! email_to_user($sendto, $teacher, $postsubject, $posttext, $posthtml)) {
275 echo "Error: workshop cron: Could not send out mail for id $submission->id to
276 user $sendto->id ($sendto->email)\n";
281 // look for new assessments of resubmissions
282 if ($assessments = workshop_get_unmailed_resubmissions($cutofftime)) {
283 $timenow = time();
285 foreach ($assessments as $assessment) {
287 echo "Processing workshop assessment $assessment->id\n";
289 // only process the entry once
290 if (! set_field("workshop_assessments", "mailed", "1", "id", "$assessment->id")) {
291 echo "Could not update the mailed field for id $assessment->id\n";
294 if (! $submission = get_record("workshop_submissions", "id", "$assessment->submissionid")) {
295 echo "Could not find submission $assessment->submissionid\n";
296 continue;
298 if (! $workshop = get_record("workshop", "id", $submission->workshopid)) {
299 echo "Could not find workshop id $submission->workshopid\n";
300 continue;
302 if (! $course = get_record("course", "id", $workshop->course)) {
303 error("Could not find course id $workshop->course");
304 continue;
306 if (! $cm = get_coursemodule_from_instance("workshop", $workshop->id, $course->id)) {
307 error("Course Module ID was incorrect");
308 continue;
310 if (! $submissionowner = get_record("user", "id", "$submission->userid")) {
311 echo "Could not find user $submission->userid\n";
312 continue;
314 if (! $assessmentowner = get_record("user", "id", "$assessment->userid")) {
315 echo "Could not find user $assessment->userid\n";
316 continue;
318 if (! workshop_is_student($workshop, $submissionowner->id) and !workshop_is_teacher($workshop,
319 $submissionowner->id)) {
320 continue; // Not an active participant
322 if (! workshop_is_student($workshop, $assessmentowner->id) and !workshop_is_teacher($workshop,
323 $assessmentowner->id)) {
324 continue; // Not an active participant
327 $strworkshops = get_string("modulenameplural", "workshop");
328 $strworkshop = get_string("modulename", "workshop");
330 // it's a resubission assessment, tell the assessment owner to (re)assess
331 $USER->lang = $assessmentowner->lang;
332 $sendto = $assessmentowner;
333 // "The assignment \"$submission->title\" is a revised piece of work. "
334 $msg = get_string("mail8", "workshop", $submission->title)."\n";
335 // "Please assess it in the workshop assignment '$workshop->name'
336 // $msg .= get_string("mail9", "workshop", $workshop->name)."\n\n";
338 $postsubject = "$course->shortname: $strworkshops: ".format_string($workshop->name,true);
339 $posttext = "$course->shortname -> $strworkshops -> ".format_string($workshop->name,true)."\n";
340 $posttext .= "---------------------------------------------------------------------\n";
341 $posttext .= $msg;
342 // "Please assess it in ..."
343 $posttext .= get_string("mail9", "workshop",
344 format_string($workshop->name,true).", $CFG->wwwroot/mod/workshop/view.php?id=$cm->id")."\n";
345 $posttext .= "---------------------------------------------------------------------\n";
346 if ($sendto->mailformat == 1) { // HTML
347 $posthtml = "<p><font face=\"sans-serif\">".
348 "<a href=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</a> ->".
349 "<a href=\"$CFG->wwwroot/mod/workshop/index.php?id=$course->id\">$strworkshops</a> ->".
350 "<a href=\"$CFG->wwwroot/mod/workshop/view.php?id=$cm->id\">".format_string($workshop->name,true)."</a></font></p>";
351 $posthtml .= "<hr><font face=\"sans-serif\">";
352 $posthtml .= "<p>$msg</p>";
353 $posthtml .= "<p>".get_string("mail9", "workshop",
354 " <a href=\"$CFG->wwwroot/mod/workshop/view.php?id=$cm->id\">".format_string($workshop->name,true)."</a>").'</p></font><hr>';
356 else {
357 $posthtml = "";
360 if (!$teacher = get_teacher($course->id)) {
361 echo "Error: can not find teacher for course $course->id!\n";
364 if (! email_to_user($sendto, $teacher, $postsubject, $posttext, $posthtml)) {
365 echo "Error: workshop cron: Could not send out mail for id $submission->id to
366 user $sendto->id ($sendto->email)\n";
371 // look for new comments
372 if ($comments = workshop_get_unmailed_comments($cutofftime)) {
373 $timenow = time();
375 foreach ($comments as $comment) {
377 echo "Processing workshop comment $comment->id\n";
379 // only process the entry once
380 if (! set_field("workshop_comments", "mailed", "1", "id", "$comment->id")) {
381 echo "Could not update the mailed field for comment id $comment->id\n";
384 if (! $assessment = get_record("workshop_assessments", "id", "$comment->assessmentid")) {
385 echo "Could not find assessment $comment->assessmentid\n";
386 continue;
388 if (! $submission = get_record("workshop_submissions", "id", "$assessment->submissionid")) {
389 echo "Could not find submission $assessment->submissionid\n";
390 continue;
392 if (! $workshop = get_record("workshop", "id", $submission->workshopid)) {
393 echo "Could not find workshop id $submission->workshopid\n";
394 continue;
396 if (! $course = get_record("course", "id", $workshop->course)) {
397 error("Could not find course id $workshop->course");
398 continue;
400 if (! $cm = get_coursemodule_from_instance("workshop", $workshop->id, $course->id)) {
401 error("Course Module ID was incorrect");
402 continue;
404 if (! $submissionowner = get_record("user", "id", "$submission->userid")) {
405 echo "Could not find user $submission->userid\n";
406 continue;
408 if (! $assessmentowner = get_record("user", "id", "$assessment->userid")) {
409 echo "Could not find user $assessment->userid\n";
410 continue;
412 if (! workshop_is_student($workshop, $submissionowner->id) and !workshop_is_teacher($workshop,
413 $submissionowner->id)) {
414 continue; // Not an active participant
416 if (! workshop_is_student($workshop, $assessmentowner->id) and !workshop_is_teacher($workshop,
417 $assessmentowner->id)) {
418 continue; // Not an active participant
421 $strworkshops = get_string("modulenameplural", "workshop");
422 $strworkshop = get_string("modulename", "workshop");
424 // see if the submission owner needs to be told
425 if ($comment->userid != $submission->userid) {
426 $USER->lang = $submissionowner->lang;
427 $sendto = $submissionowner;
428 // "A comment has been added to the assignment \"$submission->title\" by
429 if (workshop_is_student($workshop, $assessmentowner->id)) {
430 $msg = get_string("mail4", "workshop", $submission->title)." a $course->student.\n";
432 else {
433 $msg = get_string("mail4", "workshop", $submission->title)." ".fullname($assessmentowner)."\n";
435 // "The new comment can be seen in the workshop assignment '$workshop->name'
436 // $msg .= get_string("mail5", "workshop", $workshop->name)."\n\n";
438 $postsubject = "$course->shortname: $strworkshops: ".format_string($workshop->name,true);
439 $posttext = "$course->shortname -> $strworkshops -> ".format_string($workshop->name,true)."\n";
440 $posttext .= "---------------------------------------------------------------------\n";
441 $posttext .= $msg;
442 // "The new comment can be seen in ..."
443 $posttext .= get_string("mail5", "workshop",
444 format_string($workshop->name,true).", $CFG->wwwroot/mod/workshop/view.php?id=$cm->id")."\n";
445 $posttext .= "---------------------------------------------------------------------\n";
446 if ($sendto->mailformat == 1) { // HTML
447 $posthtml = "<p><font face=\"sans-serif\">".
448 "<a href=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</a> ->".
449 "<a href=\"$CFG->wwwroot/mod/workshop/index.php?id=$course->id\">$strworkshops</a> ->".
450 "<a href=\"$CFG->wwwroot/mod/workshop/view.php?id=$cm->id\">".format_string($workshop->name,true)."</a></font></p>";
451 $posthtml .= "<hr><font face=\"sans-serif\">";
452 $posthtml .= "<p>$msg</p>";
453 $posthtml .= "<p>".get_string("mail5", "workshop",
454 " <a href=\"$CFG->wwwroot/mod/workshop/view.php?id=$cm->id\">".format_string($workshop->name,true)."</a>")
455 ."</p></font><hr>";
457 else {
458 $posthtml = "";
461 if (!$teacher = get_teacher($course->id)) {
462 echo "Error: can not find teacher for course $course->id!\n";
465 if (! email_to_user($sendto, $teacher, $postsubject, $posttext, $posthtml)) {
466 echo "Error: workshop cron: Could not send out mail for id $submission->id to user
467 $sendto->id ($sendto->email)\n";
470 // see if the assessor needs to to told
471 if ($comment->userid != $assessment->userid) {
472 $USER->lang = $assessmentowner->lang;
473 $sendto = $assessmentowner;
474 // "A comment has been added to the assignment \"$submission->title\" by
475 if (workshop_is_student($workshop, $submissionowner->id)) {
476 $msg = get_string("mail4", "workshop", $submission->title)." a $course->student.\n";
478 else {
479 $msg = get_string("mail4", "workshop", $submission->title).
480 " ".fullname($submissionowner)."\n";
482 // "The new comment can be seen in the workshop assignment '$workshop->name'
483 // $msg .= get_string("mail5", "workshop", $workshop->name)."\n\n";
485 $postsubject = "$course->shortname: $strworkshops: ".format_string($workshop->name,true);
486 $posttext = "$course->shortname -> $strworkshops -> ".format_string($workshop->name,true)."\n";
487 $posttext .= "---------------------------------------------------------------------\n";
488 $posttext .= $msg;
489 // "The new comment can be seen in ..."
490 $posttext .= get_string("mail5", "workshop",
491 format_string($workshop->name,true).", $CFG->wwwroot/mod/workshop/view.php?id=$cm->id")."\n";
492 $posttext .= "---------------------------------------------------------------------\n";
493 if ($sendto->mailformat == 1) { // HTML
494 $posthtml = "<p><font face=\"sans-serif\">".
495 "<a href=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</a> ->".
496 "<a href=\"$CFG->wwwroot/mod/workshop/index.php?id=$course->id\">$strworkshops</a> ->".
497 "<a href=\"$CFG->wwwroot/mod/workshop/view.php?id=$cm->id\">".format_string($workshop->name,true)."</a></font></p>";
498 $posthtml .= "<hr><font face=\"sans-serif\">";
499 $posthtml .= "<p>$msg</p>";
500 $posthtml .= "<p>".get_string("mail5", "workshop",
501 " <a href=\"$CFG->wwwroot/mod/workshop/view.php?id=$cm->id\">".format_string($workshop->name,true)."</a>")
502 ."</p></font><hr>";
504 else {
505 $posthtml = "";
508 if (!$teacher = get_teacher($course->id)) {
509 echo "Error: can not find teacher for course $course->id!\n";
512 if (! email_to_user($sendto, $teacher, $postsubject, $posttext, $posthtml)) {
513 echo "Error: workshop cron: Could not send out mail for id $submission->id to user
514 $sendto->id ($sendto->email)\n";
516 if (! set_field("workshop_comments", "mailed", "1", "id", "$comment->id")) {
517 echo "Could not update the mailed field for comment id $comment->id\n";
522 return true;
526 ///////////////////////////////////////////////////////////////////////////////
527 function workshop_delete_instance($id) {
528 // Given an ID of an instance of this module,
529 // this function will permanently delete the instance
530 // and any data that depends on it.
532 if (! $workshop = get_record("workshop", "id", "$id")) {
533 return false;
536 // delete all the associated records in the workshop tables, start positive...
537 $result = true;
539 if (! delete_records("workshop_comments", "workshopid", "$workshop->id")) {
540 $result = false;
543 if (! delete_records("workshop_stockcomments", "workshopid", "$workshop->id")) {
544 $result = false;
547 if (! delete_records("workshop_grades", "workshopid", "$workshop->id")) {
548 $result = false;
551 if (! delete_records("workshop_elements", "workshopid", "$workshop->id")) {
552 $result = false;
555 if (! delete_records("workshop_assessments", "workshopid", "$workshop->id")) {
556 $result = false;
559 if (! delete_records("workshop_submissions", "workshopid", "$workshop->id")) {
560 $result = false;
563 if (! delete_records("workshop", "id", "$workshop->id")) {
564 $result = false;
567 if (! delete_records('event', 'modulename', 'workshop', 'instance', $workshop->id)) {
568 $result = false;
571 return $result;
575 ///////////////////////////////////////////////////////////////////////////////
576 function workshop_grades($workshopid) {
577 /// Must return an array of grades, indexed by user, and a max grade.
578 /// only returns grades once assessment has started
579 /// returns nothing if workshop is not graded
580 global $CFG;
582 $return = null;
583 if ($workshop = get_record("workshop", "id", $workshopid)) {
584 if (($workshop->assessmentstart < time()) and $workshop->gradingstrategy) {
585 if ($students = workshop_get_students($workshop)) {
586 foreach ($students as $student) {
587 if ($workshop->wtype) {
588 $gradinggrade = workshop_gradinggrade($workshop, $student);
589 } else { // ignore grading grades for simple assignments
590 $gradinggrade = 0;
592 $bestgrade = 0;
593 if ($submissions = workshop_get_user_submissions($workshop, $student)) {
594 foreach ($submissions as $submission) {
595 if (!$submission->late) {
596 $grade = workshop_submission_grade($workshop, $submission);
597 } else {
598 $grade = 0.01;
600 if ($grade > $bestgrade) {
601 $bestgrade = $grade;
605 $return->grades[$student->id] = $gradinggrade + $bestgrade;
609 // set maximum grade if graded
610 if ($workshop->gradingstrategy) {
611 if ($workshop->wtype) {
612 $return->maxgrade = $workshop->grade + $workshop->gradinggrade;
613 } else { // ignore grading grades for simple assignemnts
614 $return->maxgrade = $workshop->grade;
618 return $return;
621 //////////////////////////////////////////////////////////////////////////////////////
622 function workshop_is_recent_activity($course, $isteacher, $timestart) {//jlw1 added for adding mark to courses with activity in My Moodle
623 global $CFG;
625 // have a look for agreed assessments for this user (agree)
626 $agreecontent = false;
627 if (!$isteacher) { // teachers only need to see submissions
628 if ($logs = workshop_get_agree_logs($course, $timestart)) {
629 // got some, see if any belong to a visible module
630 foreach ($logs as $log) {
631 // Create a temp valid module structure (only need courseid, moduleid)
632 $tempmod->course = $course->id;
633 $tempmod->id = $log->workshopid;
634 //Obtain the visible property from the instance
635 if (instance_is_visible("workshop",$tempmod)) {
636 $agreecontent = true;
637 break;
642 return false;
646 ///////////////////////////////////////////////////////////////////////////////
648 // NOTE: $isteacher usage should be converted to use roles.
649 // TODO: Fix this function.
651 function workshop_print_recent_activity($course, $viewfullanmes, $timestart) {
652 global $CFG;
654 $isteacher = has_capability('mod/workshop:manage', get_context_instance(CONTEXT_COURSE, $course->id));
656 $modinfo = get_fast_modinfo($course);
658 // have a look for agreed assessments for this user (agree)
659 $agreecontent = false;
660 if (!$isteacher) { // teachers only need to see submissions
661 if ($logs = workshop_get_agree_logs($course, $timestart)) {
662 $agreecontent = true;
663 print_headline(get_string("workshopagreedassessments", "workshop").":");
664 foreach ($logs as $log) {
665 if (!workshop_is_teacher($workshop, $log->userid)) { // don't break anonymous rule
666 $log->firstname = $course->student;
667 $log->lastname = '';
669 print_recent_activity_note($log->time, $log, $log->name,
670 $CFG->wwwroot.'/mod/workshop/'.$log->url);
675 // have a look for new assessments for this user (assess)
676 $assesscontent = false;
677 if (!$isteacher) { // teachers only need to see submissions
678 if ($logs = workshop_get_assess_logs($course, $timestart)) {
679 // got some, see if any belong to a visible module
680 foreach ($logs as $id=>$log) {
681 $cm = $modinfo->instances['workshop'][$log->workshopid];
682 if (!$cm->uservisible) {
683 unset($logs[$id]);
684 continue;
687 // if we got some "live" ones then output them
688 if ($logs) {
689 $assesscontent = true;
690 print_headline(get_string("workshopassessments", "workshop").":");
691 foreach ($logs as $log) {
692 if (!workshop_is_teacher($tempmod->id, $log->userid)) { // don't break anonymous rule
693 $log->firstname = $course->student; // Keep anonymous
694 $log->lastname = '';
696 print_recent_activity_note($log->time, $log, $log->name,
697 $CFG->wwwroot.'/mod/workshop/'.$log->url);
702 // have a look for new comments for this user (comment)
703 $commentcontent = false;
704 if (!$isteacher) { // teachers only need to see submissions
705 if ($logs = workshop_get_comment_logs($course, $timestart)) {
706 // got some, see if any belong to a visible module
707 foreach ($logs as $id=>$log) {
708 $cm = $modinfo->instances['workshop'][$log->workshopid];
709 if (!$cm->uservisible) {
710 unset($logs[$id]);
711 continue;
714 // if we got some "live" ones then output them
715 if ($logs) {
716 $commentcontent = true;
717 print_headline(get_string("workshopcomments", "workshop").":");
718 foreach ($logs as $log) {
719 $log->firstname = $course->student; // Keep anonymous
720 $log->lastname = '';
721 print_recent_activity_note($log->time, $log, $log->name,
722 $CFG->wwwroot.'/mod/workshop/'.$log->url);
728 // have a look for new assessment gradings for this user (grade)
729 $gradecontent = false;
730 if ($logs = workshop_get_grade_logs($course, $timestart)) {
731 // got some, see if any belong to a visible module
732 foreach ($logs as $id=>$log) {
733 $cm = $modinfo->instances['workshop'][$log->workshopid];
734 if (!$cm->uservisible) {
735 unset($logs[$id]);
736 continue;
739 // if we got some "live" ones then output them
740 if ($logs) {
741 $gradecontent = true;
742 print_headline(get_string("workshopfeedback", "workshop").":");
743 foreach ($logs as $log) {
744 $log->firstname = $course->teacher; // Keep anonymous
745 $log->lastname = '';
746 print_recent_activity_note($log->time, $log, $log->name,
747 $CFG->wwwroot.'/mod/workshop/'.$log->url);
752 // have a look for new submissions (only show to teachers) (submit)
753 $submitcontent = false;
754 if ($isteacher) {
755 if ($logs = workshop_get_submit_logs($course, $timestart)) {
756 // got some, see if any belong to a visible module
757 foreach ($logs as $id=>$log) {
758 $cm = $modinfo->instances['workshop'][$log->workshopid];
759 if (!$cm->uservisible) {
760 unset($logs[$id]);
761 continue;
764 // if we got some "live" ones then output them
765 if ($logs) {
766 $submitcontent = true;
767 print_headline(get_string("workshopsubmissions", "workshop").":");
768 foreach ($logs as $log) {
769 print_recent_activity_note($log->time, $log, $log->name,
770 $CFG->wwwroot.'/mod/workshop/'.$log->url);
776 return $agreecontent or $assesscontent or $commentcontent or $gradecontent or $submitcontent;
780 ///////////////////////////////////////////////////////////////////////////////
781 function workshop_refresh_events($courseid = 0) {
782 // This standard function will check all instances of this module
783 // and make sure there are up-to-date events created for each of them.
784 // If courseid = 0, then every workshop event in the site is checked, else
785 // only workshop events belonging to the course specified are checked.
786 // This function is used, in its new format, by restore_refresh_events()
788 if ($courseid == 0) {
789 if (! $workshops = get_records("workshop")) {
790 return true;
792 } else {
793 if (! $workshops = get_records("workshop", "course", $courseid)) {
794 return true;
797 $moduleid = get_field('modules', 'id', 'name', 'workshop');
799 foreach ($workshops as $workshop) {
801 $dates = array(
802 'submissionstart' => $workshop->submissionstart,
803 'submissionend' => $workshop->submissionend,
804 'assessmentstart' => $workshop->assessmentstart,
805 'assessmentend' => $workshop->assessmentend
808 foreach ($dates as $type => $date) {
810 if ($date) {
811 if ($event = get_record('event', 'modulename', 'workshop', 'instance', $workshop->id, 'eventtype', $type)) {
812 $event->name = addslashes(get_string($type.'event','workshop', $workshop->name));
813 $event->description = addslashes($workshop->description);
814 $event->eventtype = $type;
815 $event->timestart = $date;
816 update_event($event);
817 } else {
818 $event->courseid = $workshop->course;
819 $event->modulename = 'workshop';
820 $event->instance = $workshop->id;
821 $event->name = addslashes(get_string($type.'event','workshop', $workshop->name));
822 $event->description = addslashes($workshop->description);
823 $event->eventtype = $type;
824 $event->timestart = $date;
825 $event->timeduration = 0;
826 $event->visible = get_field('course_modules', 'visible', 'module', $moduleid, 'instance', $workshop->id);
827 add_event($event);
832 return true;
836 ///////////////////////////////////////////////////////////////////////////////
837 function workshop_update_instance($workshop) {
838 // Given an object containing all the necessary data,
839 // (defined by the form in mod.html) this function
840 // will update an existing instance with new data.
841 global $CFG;
843 $workshop->timemodified = time();
845 $workshop->submissionstart = make_timestamp($workshop->submissionstartyear,
846 $workshop->submissionstartmonth, $workshop->submissionstartday, $workshop->submissionstarthour,
847 $workshop->submissionstartminute);
849 $workshop->assessmentstart = make_timestamp($workshop->assessmentstartyear,
850 $workshop->assessmentstartmonth, $workshop->assessmentstartday, $workshop->assessmentstarthour,
851 $workshop->assessmentstartminute);
853 $workshop->submissionend = make_timestamp($workshop->submissionendyear,
854 $workshop->submissionendmonth, $workshop->submissionendday, $workshop->submissionendhour,
855 $workshop->submissionendminute);
857 $workshop->assessmentend = make_timestamp($workshop->assessmentendyear,
858 $workshop->assessmentendmonth, $workshop->assessmentendday, $workshop->assessmentendhour,
859 $workshop->assessmentendminute);
861 $workshop->releasegrades = make_timestamp($workshop->releaseyear,
862 $workshop->releasemonth, $workshop->releaseday, $workshop->releasehour,
863 $workshop->releaseminute);
865 if (!workshop_check_dates($workshop)) {
866 return get_string('invaliddates', 'workshop');
869 // set the workshop's type
870 $wtype = 0; // 3 phases, no grading grades
871 if ($workshop->includeself or $workshop->ntassessments) $wtype = 1; // 3 phases with grading grades
872 if ($workshop->nsassessments) $wtype = 2; // 5 phases with grading grades
873 $workshop->wtype = $wtype;
875 // encode password if necessary
876 if (!empty($workshop->password)) {
877 $workshop->password = md5($workshop->password);
878 } else {
879 unset($workshop->password);
882 $workshop->id = $workshop->instance;
884 if ($returnid = update_record("workshop", $workshop)) {
886 $dates = array(
887 'submissionstart' => $workshop->submissionstart,
888 'submissionend' => $workshop->submissionend,
889 'assessmentstart' => $workshop->assessmentstart,
890 'assessmentend' => $workshop->assessmentend
892 $moduleid = get_field('modules', 'id', 'name', 'workshop');
894 foreach ($dates as $type => $date) {
895 if ($event = get_record('event', 'modulename', 'workshop', 'instance', $workshop->id, 'eventtype', $type)) {
896 $event->name = get_string($type.'event','workshop', $workshop->name);
897 $event->description = $workshop->description;
898 $event->eventtype = $type;
899 $event->timestart = $date;
900 update_event($event);
901 } else if ($date) {
902 $event = NULL;
903 $event->name = get_string($type.'event','workshop', $workshop->name);
904 $event->description = $workshop->description;
905 $event->courseid = $workshop->course;
906 $event->groupid = 0;
907 $event->userid = 0;
908 $event->modulename = 'workshop';
909 $event->instance = $workshop->instance;
910 $event->eventtype = $type;
911 $event->timestart = $date;
912 $event->timeduration = 0;
913 $event->visible = get_field('course_modules', 'visible', 'module', $moduleid, 'instance', $workshop->id);
914 add_event($event);
919 if (time() > $workshop->assessmentstart) {
920 // regrade all the submissions...
921 set_field("workshop_submissions", "nassessments", 0, "workshopid", $workshop->id);
922 workshop_grade_assessments($workshop);
925 return $returnid;
928 ///////////////////////////////////////////////////////////////////////////////
929 function workshop_user_complete($course, $user, $mod, $workshop) {
930 if ($submission = workshop_get_student_submission($workshop, $user)) {
931 if ($basedir = workshop_file_area($workshop, $user)) {
932 if ($files = get_directory_list($basedir)) {
933 $countfiles = count($files).' '.get_string('submissions', 'workshop');
934 foreach ($files as $file) {
935 $countfiles .= "; $file";
940 print_simple_box_start();
942 echo $submission->description.'<br />';
944 if (!empty($countfiles)) {
945 echo $countfiles,'<br />';
948 workshop_print_feedback($course, $submission);
950 print_simple_box_end();
952 } else {
953 print_string('notsubmittedyet', 'workshop');
957 //////////////////////////////////////////////////////////////////////////////////////
958 function workshop_print_feedback($course, $submission) {
959 global $CFG, $RATING;
961 if (! $feedbacks = get_records('workshop_assessments', 'submissionid', $submission->id)) {
962 return;
965 $strgrade = get_string('grade');
966 $strnograde = get_string('nograde');
968 foreach ($feedbacks as $feedback) {
969 if (! $user = get_record('user', 'id', $feedback->userid)) {
970 /// Weird error but we'll just ignore it and continue with other feedback
971 continue;
974 echo '<table cellspacing="0" class="workshop_feedbackbox">';
976 echo '<tr>';
977 echo '<td class="picture left">';
978 print_user_picture($user->id, $course->id, $user->picture);
979 echo '</td>';
980 echo '<td><span class="author">'.fullname($user).'</span>';
981 echo '<span class="time">'.userdate($feedback->timegraded).'</span>';
982 echo '</tr>';
984 echo '<tr><td class="left side">&nbsp;</td>';
985 echo '<td class="content">';
987 if ($feedback->grade) {
988 echo $strgrade.': '.$feedback->grade;
989 } else {
990 echo $strnograde;
993 echo '<span class="comment">'.format_text($feedback->generalcomment).'</span>';
994 echo '<span class="teachercomment">'.format_text($feedback->teachercomment).'</span>';
995 echo '</td></tr></table>';
1003 ///////////////////////////////////////////////////////////////////////////////
1004 function workshop_user_outline($course, $user, $mod, $workshop) {
1005 if ($submissions = workshop_get_user_submissions($workshop, $user)) {
1006 $result->info = count($submissions)." ".get_string("submissions", "workshop");
1007 // workshop_get_user_submissions returns the newest one first
1008 foreach ($submissions as $submission) {
1009 $result->time = $submission->timecreated;
1010 break;
1012 return $result;
1014 return NULL;
1017 //////////////////////////////////////////////////////////////////////////////////////
1018 function workshop_get_participants($workshopid) {
1019 //Returns the users with data in one workshop
1020 //(users with records in workshop_submissions, workshop_assessments and workshop_comments, students)
1022 global $CFG;
1024 //Get students from workshop_submissions
1025 $st_submissions = get_records_sql("SELECT DISTINCT u.id, u.id
1026 FROM {$CFG->prefix}user u,
1027 {$CFG->prefix}workshop_submissions s
1028 WHERE s.workshopid = '$workshopid' and
1029 u.id = s.userid");
1030 //Get students from workshop_assessments
1031 $st_assessments = get_records_sql("SELECT DISTINCT u.id, u.id
1032 FROM {$CFG->prefix}user u,
1033 {$CFG->prefix}workshop_assessments a
1034 WHERE a.workshopid = '$workshopid' and
1035 u.id = a.userid");
1037 //Get students from workshop_comments
1038 $st_comments = get_records_sql("SELECT DISTINCT u.id, u.id
1039 FROM {$CFG->prefix}user u,
1040 {$CFG->prefix}workshop_comments c
1041 WHERE c.workshopid = '$workshopid' and
1042 u.id = c.userid");
1044 //Add st_assessments to st_submissions
1045 if ($st_assessments) {
1046 foreach ($st_assessments as $st_assessment) {
1047 $st_submissions[$st_assessment->id] = $st_assessment;
1050 //Add st_comments to st_submissions
1051 if ($st_comments) {
1052 foreach ($st_comments as $st_comment) {
1053 $st_submissions[$st_comment->id] = $st_comment;
1056 //Return st_submissions array (it contains an array of unique users)
1057 return ($st_submissions);
1060 //////////////////////////////////////////////////////////////////////////////////////
1061 function workshop_get_recent_mod_activity(&$activities, &$index, $sincetime, $courseid,
1062 $workshop="0", $user="", $groupid="") {
1063 // Returns all workshop posts since a given time. If workshop is specified then
1064 // this restricts the results
1066 global $CFG;
1068 if ($workshop) {
1069 $workshopselect = " AND cm.id = '$workshop'";
1070 } else {
1071 $workshopselect = "";
1074 if ($user) {
1075 $userselect = " AND u.id = '$user'";
1076 } else {
1077 $userselect = "";
1080 $posts = get_records_sql("SELECT s.*, u.firstname, u.lastname,
1081 u.picture, cm.instance, w.name, cm.section, cm.groupmode,
1082 cm.course, cm.groupingid, cm.groupmembersonly, cm.id as cmid
1083 FROM {$CFG->prefix}workshop_submissions s,
1084 {$CFG->prefix}user u,
1085 {$CFG->prefix}course_modules cm,
1086 {$CFG->prefix}workshop w
1087 WHERE s.timecreated > '$sincetime' $workshopselect
1088 AND s.userid = u.id $userselect
1089 AND w.course = '$courseid'
1090 AND cm.instance = w.id
1091 AND cm.course = w.course
1092 AND s.workshopid = w.id
1093 ORDER BY s.id");
1096 if (empty($posts)) {
1097 return;
1100 foreach ($posts as $post) {
1101 if ((empty($groupid) || groups_is_member($groupid, $post->userid)) && groups_course_module_visible($post)) {
1103 $tmpactivity = new Object;
1105 $tmpactivity->type = "workshop";
1106 $tmpactivity->defaultindex = $index;
1107 $tmpactivity->instance = $post->instance;
1108 $tmpactivity->name = $post->name;
1109 $tmpactivity->section = $post->section;
1111 $tmpactivity->content->id = $post->id;
1112 $tmpactivity->content->title = $post->title;
1114 $tmpactivity->user->userid = $post->userid;
1115 $tmpactivity->user->fullname = fullname($post);
1116 $tmpactivity->user->picture = $post->picture;
1117 $tmpactivity->cmid = $post->cmid;
1119 $tmpactivity->timestamp = $post->timecreated;
1120 $activities[] = $tmpactivity;
1122 $index++;
1126 return;
1129 //////////////////////////////////////////////////////////////////////////////////////
1130 function workshop_print_recent_mod_activity($activity, $course, $detail=false) {
1132 global $CFG;
1134 echo '<table border="0" cellpadding="3" cellspacing="0">';
1136 if (!empty($activity->content->parent)) {
1137 $openformat = "<font size=\"2\"><i>";
1138 $closeformat = "</i></font>";
1139 } else {
1140 $openformat = "<b>";
1141 $closeformat = "</b>";
1144 echo "<tr><td class=\"workshoppostpicture\" width=\"35\" valign=\"top\">";
1145 print_user_picture($activity->user->userid, $course, $activity->user->picture);
1146 echo "</td><td>$openformat";
1148 if ($detail) {
1149 echo "<img src=\"$CFG->modpixpath/$activity->type/icon.gif\" ".
1150 "class=\"icon\" alt=\"".strip_tags(format_string($activity->name,true))."\" /> ";
1152 echo "<a href=\"$CFG->wwwroot/mod/workshop/submissions.php?"
1153 . "id=" . $activity->cmid . "&action=showsubmission&sid=".$activity->content->id."\">".$activity->content->title;
1154 echo "</a>$closeformat";
1156 echo "<br /><font size=\"2\">";
1157 echo "<a href=\"$CFG->wwwroot/user/view.php?id=" . $activity->user->userid . "&amp;course=" . "$course\">"
1158 . $activity->user->fullname . "</a>";
1159 echo " - " . userdate($activity->timestamp) . "</font></td></tr>";
1160 echo "</table>";
1162 return;
1167 //////////////////////////////////////////////////////////////////////////////////////
1168 // Non-standard workshop functions
1169 ///////////////////////////////////////////////////////////////////////////////////////////////
1170 function workshop_compare_assessments($workshop, $assessment1, $assessment2) {
1171 global $WORKSHOP_ASSESSMENT_COMPS, $WORKSHOP_EWEIGHTS;
1172 // first get the assignment elements for maxscores...
1173 $elementsraw = get_records("workshop_elements", "workshopid", $workshop->id, "elementno ASC");
1174 foreach ($elementsraw as $element) {
1175 $maxscore[] = $element->maxscore; // to renumber index 0,1,2...
1176 $weight[] = $WORKSHOP_EWEIGHTS[$element->weight]; // get real value and renumber index 0,1,2...
1179 $grades = array();
1180 for ($i = 0; $i < 2; $i++) {
1181 if ($i) {
1182 $rawgrades = get_records("workshop_grades", "assessmentid", $assessment1->id, "elementno ASC");
1183 } else {
1184 $rawgrades = get_records("workshop_grades", "assessmentid", $assessment2->id, "elementno ASC");
1186 if ($rawgrades) {
1187 foreach ($rawgrades as $grade) {
1188 $grades[$i][] = $grade->grade;
1192 $sumdiffs = 0;
1193 $sumweights = 0;
1194 switch ($workshop->gradingstrategy) {
1195 case 1 : // accumulative grading and...
1196 case 4 : // ...rubic grading
1197 for ($i=0; $i < $workshop->nelements; $i++) {
1198 $diff = ($grades[0][$i] - $grades[1][$i]) * $weight[$i] / $maxscore[$i];
1199 $sumdiffs += $diff * $diff; // use squared distances
1200 $sumweights += $weight[$i];
1202 break;
1203 case 2 : // error banded grading
1204 // ignore maxscores here, the grades are either 0 or 1,
1205 for ($i=0; $i < $workshop->nelements; $i++) {
1206 $diff = ($grades[0][$i] - $grades[1][$i]) * $weight[$i];
1207 $sumdiffs += $diff * $diff; // use squared distances
1208 $sumweights += $weight[$i];
1210 break;
1211 case 3 : // criterion grading
1212 // here we only need to look at the difference between the "zero" grade elements
1213 $diff = ($grades[0][0] - $grades[1][0]) / (count($elementsraw) - 1);
1214 $sumdiffs = $diff * $diff;
1215 $sumweights = 1;
1216 break;
1218 // convert to a sensible grade (always out of 100)
1219 $COMP = (object)$WORKSHOP_ASSESSMENT_COMPS[$workshop->assessmentcomps];
1220 $factor = $COMP->value;
1221 $gradinggrade = (($factor - ($sumdiffs / $sumweights)) / $factor) * 100;
1222 if ($gradinggrade < 0) {
1223 $gradinggrade = 0;
1225 return $gradinggrade;
1229 //////////////////////////////////////////////////////////////////////////////////////
1230 function workshop_count_assessments($submission) {
1231 // Return the (real) assessments for this submission,
1232 $timenow = time();
1233 return count_records_select("workshop_assessments",
1234 "submissionid = $submission->id AND timecreated < $timenow");
1238 //////////////////////////////////////////////////////////////////////////////////////
1239 function workshop_count_ungraded_assessments($workshop) {
1240 // function returns the number of ungraded assessments by students
1241 global $CFG;
1243 $timenow = time();
1244 $n = 0;
1245 // get all the cold assessments that have not been graded
1246 if ($assessments = get_records_select("workshop_assessments", "workshopid = $workshop->id AND
1247 (timecreated + $CFG->maxeditingtime) < $timenow AND timegraded = 0")) {
1248 foreach ($assessments as $assessment) {
1249 if (workshop_is_student($workshop, $assessment->userid)) {
1250 $n++;
1254 return $n;
1258 //////////////////////////////////////////////////////////////////////////////////////
1259 function workshop_file_area($workshop, $submission) {
1260 return make_upload_directory( workshop_file_area_name($workshop, $submission) );
1264 //////////////////////////////////////////////////////////////////////////////////////
1265 function workshop_file_area_name($workshop, $submission) {
1266 // Creates a directory file name, suitable for make_upload_directory()
1267 global $CFG;
1269 return "$workshop->course/$CFG->moddata/workshop/$submission->id";
1273 ///////////////////////////////////////////////////////////////////////////////////////////////
1274 function workshop_get_agree_logs($course, $timestart) {
1275 // get the "agree" entries for this user (the assessment owner) and add the first and last names
1276 // the last two probably wont be used...
1277 global $CFG, $USER;
1278 if (empty($USER->id)) {
1279 return false;
1282 $timethen = time() - $CFG->maxeditingtime;
1283 return get_records_sql("SELECT l.time, l.url, u.firstname, u.lastname, a.workshopid, a.userid, e.name
1284 FROM {$CFG->prefix}log l,
1285 {$CFG->prefix}workshop e,
1286 {$CFG->prefix}workshop_submissions s,
1287 {$CFG->prefix}workshop_assessments a,
1288 {$CFG->prefix}user u
1289 WHERE l.time > $timestart AND l.time < $timethen
1290 AND l.course = $course->id AND l.module = 'workshop' AND l.action = 'agree'
1291 AND a.id = l.info AND s.id = a.submissionid AND a.userid = $USER->id
1292 AND u.id = s.userid AND e.id = a.workshopid");
1296 ///////////////////////////////////////////////////////////////////////////////////////////////
1297 function workshop_get_assess_logs($course, $timestart) {
1298 // get the "assess" entries for this user and add the first and last names...
1299 global $CFG, $USER;
1300 if (empty($USER->id)) {
1301 return false;
1304 $timethen = time() - $CFG->maxeditingtime;
1305 return get_records_sql("SELECT l.time, l.url, u.firstname, u.lastname, a.workshopid, a.userid, e.name
1306 FROM {$CFG->prefix}log l,
1307 {$CFG->prefix}workshop e,
1308 {$CFG->prefix}workshop_submissions s,
1309 {$CFG->prefix}workshop_assessments a,
1310 {$CFG->prefix}user u
1311 WHERE l.time > $timestart AND l.time < $timethen
1312 AND l.course = $course->id AND l.module = 'workshop' AND l.action = 'assess'
1313 AND a.id = ".sql_cast_char2int('l.info') ." AND s.id = a.submissionid AND s.userid = $USER->id
1314 AND u.id = a.userid AND e.id = a.workshopid");
1318 //////////////////////////////////////////////////////////////////////////////////////
1319 function workshop_get_assessments($submission, $all = '', $order = '') {
1320 // Return assessments for this submission ordered oldest first, newest last
1321 // new assessments made within the editing time are NOT returned unless they
1322 // belong to the user or the second argument is set to ALL
1323 global $CFG, $USER;
1325 $timenow = time();
1326 if (!$order) {
1327 $order = "timecreated DESC";
1329 if ($all != 'ALL') {
1330 return get_records_select("workshop_assessments", "(submissionid = $submission->id) AND
1331 ((timecreated < $timenow - $CFG->maxeditingtime) or
1332 ((timecreated < $timenow) AND (userid = $USER->id)))", $order);
1333 } else {
1334 return get_records_select("workshop_assessments", "submissionid = $submission->id AND
1335 (timecreated < $timenow)", $order);
1340 ///////////////////////////////////////////////////////////////////////////////////////////////
1341 function workshop_get_comment_logs($course, $timestart) {
1342 // get the "comment" entries for this user and add the first and last names (which may not be used)...
1343 global $CFG, $USER;
1344 if (empty($USER->id)) {
1345 return false;
1348 $timethen = time() - $CFG->maxeditingtime;
1349 return get_records_sql("SELECT l.time, l.url, u.firstname, u.lastname, a.workshopid, e.name
1350 FROM {$CFG->prefix}log l,
1351 {$CFG->prefix}workshop e,
1352 {$CFG->prefix}workshop_submissions s,
1353 {$CFG->prefix}workshop_assessments a,
1354 {$CFG->prefix}workshop_comments c,
1355 {$CFG->prefix}user u
1356 WHERE l.time > $timestart AND l.time < $timethen
1357 AND l.course = $course->id AND l.module = 'workshop' AND l.action = 'comment'
1358 AND c.id = l.info AND c.userid != $USER->id AND a.id = c.assessmentid
1359 AND s.id = a.submissionid AND (s.userid = $USER->id OR a.userid = $USER->id)
1360 AND u.id = a.userid AND e.id = a.workshopid");
1364 ///////////////////////////////////////////////////////////////////////////////////////////////
1365 function workshop_get_grade_logs($course, $timestart) {
1366 // get the "grade" entries for this user and add the first and last names (of submission owner,
1367 // better to get name of teacher...
1368 // ...but not available in assessment record...)
1369 global $CFG, $USER;
1370 if (empty($USER->id)) {
1371 return false;
1374 $timethen = time() - $CFG->maxeditingtime;
1375 return get_records_sql("SELECT l.time, l.url, u.firstname, u.lastname, a.workshopid, e.name
1376 FROM {$CFG->prefix}log l,
1377 {$CFG->prefix}workshop e,
1378 {$CFG->prefix}workshop_submissions s,
1379 {$CFG->prefix}workshop_assessments a,
1380 {$CFG->prefix}user u
1381 WHERE l.time > $timestart AND l.time < $timethen
1382 AND l.course = $course->id AND l.module = 'workshop' AND l.action = 'grade'
1383 AND a.id = ".sql_cast_char2int('l.info') ." AND s.id = a.submissionid AND a.userid = $USER->id
1384 AND u.id = s.userid AND e.id = a.workshopid");
1388 //////////////////////////////////////////////////////////////////////////////////////
1389 function workshop_get_student_submission($workshop, $user) {
1390 // Return a submission for a particular user
1391 global $CFG;
1393 $submission = get_record("workshop_submissions", "workshopid", $workshop->id, "userid", $user->id);
1394 if (!empty($submission->timecreated)) {
1395 return $submission;
1397 return NULL;
1401 //////////////////////////////////////////////////////////////////////////////////////
1402 function workshop_get_student_submissions($workshop, $order = "title") {
1403 // Return all ENROLLED student submissions
1404 global $CFG;
1406 if ($order == "title") {
1407 $order = "s.title";
1409 if ($order == "name") {
1410 $order = "a.lastname, a.firstname";
1412 if ($order == "time") {
1413 $order = "s.timecreated ASC";
1416 if (!$students = workshop_get_students($workshop)) {
1417 return false;
1419 $list = "(";
1420 foreach ($students as $student) {
1421 $list .= "$student->id,";
1423 $list = rtrim($list, ',').")";
1425 return get_records_sql("SELECT s.* FROM {$CFG->prefix}workshop_submissions s, {$CFG->prefix}user a
1426 WHERE s.userid IN $list
1427 AND s.workshopid = $workshop->id
1428 AND s.timecreated > 0
1429 AND s.userid = a.id
1430 ORDER BY $order");
1434 ///////////////////////////////////////////////////////////////////////////////////////////////
1435 function workshop_get_submit_logs($course, $timestart) {
1436 // get the "submit" entries and add the first and last names...
1437 global $CFG, $USER;
1439 $timethen = time() - $CFG->maxeditingtime;
1440 return get_records_sql("SELECT l.time, l.url, u.firstname, u.lastname, l.info as workshopid, e.name
1441 FROM {$CFG->prefix}log l,
1442 {$CFG->prefix}workshop e,
1443 {$CFG->prefix}user u
1444 WHERE l.time > $timestart AND l.time < $timethen
1445 AND l.course = $course->id AND l.module = 'workshop'
1446 AND l.action = 'submit'
1447 AND e.id = ".sql_cast_char2int('l.info') ."
1448 AND u.id = l.userid");
1452 //////////////////////////////////////////////////////////////////////////////////////
1453 function workshop_get_unmailed_assessments($cutofftime) {
1454 /// Return list of assessments that have not been mailed out
1455 global $CFG;
1456 return get_records_sql("SELECT a.*, g.course, g.name
1457 FROM {$CFG->prefix}workshop_assessments a, {$CFG->prefix}workshop g
1458 WHERE a.mailed = 0
1459 AND a.timecreated < $cutofftime
1460 AND g.id = a.workshopid
1461 AND g.releasegrades < $cutofftime");
1465 //////////////////////////////////////////////////////////////////////////////////////
1466 function workshop_get_unmailed_comments($cutofftime) {
1467 /// Return list of comments that have not been mailed out
1468 global $CFG;
1469 return get_records_sql("SELECT c.*, g.course, g.name
1470 FROM {$CFG->prefix}workshop_comments c, {$CFG->prefix}workshop g
1471 WHERE c.mailed = 0
1472 AND c.timecreated < $cutofftime
1473 AND g.id = c.workshopid");
1477 //////////////////////////////////////////////////////////////////////////////////////
1478 function workshop_get_unmailed_graded_assessments($cutofftime) {
1479 /// Return list of graded assessments that have not been mailed out
1480 global $CFG;
1481 return get_records_sql("SELECT a.*, g.course, g.name
1482 FROM {$CFG->prefix}workshop_assessments a, {$CFG->prefix}workshop g
1483 WHERE a.mailed = 0
1484 AND a.timegraded < $cutofftime
1485 AND a.timegraded > 0
1486 AND g.id = a.workshopid");
1490 //////////////////////////////////////////////////////////////////////////////////////
1491 function workshop_get_unmailed_resubmissions($cutofftime) {
1492 /// Return list of assessments of resubmissions that have not been mailed out
1493 global $CFG;
1494 return get_records_sql("SELECT a.*, w.course, w.name
1495 FROM {$CFG->prefix}workshop_assessments a, {$CFG->prefix}workshop w
1496 WHERE a.mailed = 0
1497 AND a.resubmission = 1
1498 AND w.id = a.workshopid");
1502 //////////////////////////////////////////////////////////////////////////////////////
1503 function workshop_get_user_assessments($workshop, $user) {
1504 // Return all the user's assessments, newest first, oldest last (hot, warm and cold ones)
1505 return get_records_select("workshop_assessments", "workshopid = $workshop->id AND userid = $user->id",
1506 "timecreated DESC");
1510 //////////////////////////////////////////////////////////////////////////////////////
1511 function workshop_get_user_submissions($workshop, $user) {
1512 // return real submissions of user newest first, oldest last. Ignores the dummy submissions
1513 // which get created to hold the final grades for users that make no submissions
1514 return get_records_select("workshop_submissions", "workshopid = $workshop->id AND
1515 userid = $user->id AND timecreated > 0", "timecreated DESC" );
1519 //////////////////////////////////////////////////////////////////////////////////////
1520 function workshop_grade_assessments($workshop, $verbose=false) {
1521 global $WORKSHOP_EWEIGHTS;
1523 // timeout after 10 minutes
1524 @set_time_limit(600);
1526 $timenow = time();
1528 // set minumim value for the variance (of the elements)
1529 $minvar = 0.05;
1531 // check when the standard deviations were calculated
1532 $oldtotalassessments = get_field("workshop_elements", "totalassessments", "workshopid", $workshop->id,
1533 "elementno", 0);
1534 $totalassessments = count_records("workshop_assessments", "workshopid", $workshop->id);
1535 // calculate the std. devs every 10 assessments for low numbers of assessments, thereafter every 100 new assessments
1536 if ((($totalassessments < 100) and (($totalassessments - $oldtotalassessments) > 10)) or
1537 (($totalassessments - $oldtotalassessments) > 100)) {
1538 // calculate the means for each submission using just the "good" assessments
1539 if ($submissions = get_records("workshop_submissions", "workshopid", $workshop->id)) {
1540 foreach ($submissions as $submission) {
1541 $nassessments[$submission->id] = 0;
1542 if ($assessments = workshop_get_assessments($submission)) {
1543 foreach ($assessments as $assessment) {
1544 // test if assessment is "good", a teacher assessment always "good", but may be weighted out
1545 if (workshop_is_teacher($workshop, $assessment->userid)) {
1546 if (!$workshop->teacherweight) {
1547 // drop teacher's assessment as weight is zero
1548 continue;
1550 } elseif ((!$assessment->gradinggrade and $assessment->timegraded) or
1551 ($workshop->agreeassessments and !$assessment->timeagreed)) {
1552 // it's a duff assessment, or it's not been agreed
1553 continue;
1555 if (isset($num[$submission->id])) {
1556 if (workshop_is_teacher($workshop, $assessment->userid)) {
1557 $num[$submission->id] += $workshop->teacherweight; // weight teacher's assessment
1558 } else {
1559 $num[$submission->id]++; // number of assessments
1561 $nassessments[$submission->id]++;
1562 } else {
1563 if (workshop_is_teacher($workshop, $assessment->userid)) {
1564 $num[$submission->id] = $workshop->teacherweight;
1565 } else {
1566 $num[$submission->id] = 1;
1568 $nassessments[$submission->id] = 1;
1570 for ($i = 0; $i < $workshop->nelements; $i++) {
1571 $grade = get_field("workshop_grades", "grade",
1572 "assessmentid", $assessment->id, "elementno", $i);
1573 if (isset($sum[$submission->id][$i])) {
1574 if (workshop_is_teacher($workshop, $assessment->userid)) {
1575 $sum[$submission->id][$i] += $workshop->teacherweight * $grade; // teacher's grade
1576 } else {
1577 $sum[$submission->id][$i] += $grade; // student's grade
1579 } else {
1580 if (workshop_is_teacher($workshop, $assessment->userid)) {
1581 $sum[$submission->id][$i] = $workshop->teacherweight * $grade; // teacher's grade
1582 } else {
1583 $sum[$submission->id][$i] = $grade; // students's grade
1591 if (!isset($num)) {
1592 // no assessments yet
1593 return;
1595 reset($num);
1596 // calculate the means for each submission
1597 $total = 0;
1598 foreach ($num as $submissionid => $n) {
1599 if ($n) { // stop division by zero
1600 for ($i = 0; $i < $workshop->nelements; $i++) {
1601 $mean[$submissionid][$i] = $sum[$submissionid][$i] / $n;
1602 // echo "Submission: $submissionid; Element: $i; Mean: {$mean[$submissionid][$i]}<br />\n";
1604 $total += $n; // weighted total
1607 if ($verbose) {
1608 echo "<p style=\"text-align:center\">".get_string("numberofsubmissions", "workshop", count($num))."<br />\n";
1609 echo get_string("numberofassessmentsweighted", "workshop", $total)."</p>\n";
1612 // now get an estimate of the standard deviation of each element in the assessment
1613 // this is just a rough measure, all assessments are included and teacher's assesments are not weighted
1614 $n = 0;
1615 for ($i = 0; $i < $workshop->nelements; $i++) {
1616 $var[$i] = 0;
1618 foreach ($submissions as $submission) {
1619 if ($assessments = workshop_get_assessments($submission)) {
1620 foreach ($assessments as $assessment) {
1621 $n++;
1622 for ($i = 0; $i < $workshop->nelements; $i++) {
1623 $grade = get_field("workshop_grades", "grade",
1624 "assessmentid", $assessment->id, "elementno", $i);
1625 $temp = $mean[$submission->id][$i] - $grade;
1626 $var[$i] += $temp * $temp;
1631 for ($i = 0; $i < $workshop->nelements; $i++) {
1632 if ($n > 1) {
1633 $sd[$i] = sqrt($var[$i] / ($n - 1));
1634 } else {
1635 $sd[$i] = 0;
1637 set_field("workshop_elements", "stddev", $sd[$i], "workshopid", $workshop->id, "elementno", $i);
1638 set_field("workshop_elements", "totalassessments", $totalassessments, "workshopid", $workshop->id,
1639 "elementno", $i);
1640 if ($verbose) {
1641 echo get_string("standarddeviationofelement", "workshop", $i+1)." $sd[$i]<br />";
1642 if ($sd[$i] <= $minvar) {
1643 print_string("standarddeviationnote", "workshop")."<br />\n";
1650 // this section looks at each submission if the number of assessments made has increased it recalculates the
1651 // grading grades for those assessments
1652 // first get the assignment elements for the weights and the stddevs...
1653 if ($elementsraw = get_records("workshop_elements", "workshopid", $workshop->id, "elementno ASC")) {
1654 foreach ($elementsraw as $element) {
1655 $weight[] = $element->weight; // to renumber index 0,1,2...
1656 $sd[] = $element->stddev; // to renumber index 0,1,2...
1660 unset($num); // may have been used in calculating stddevs
1661 unset($sum); // ditto
1662 if ($submissions = get_records("workshop_submissions", "workshopid", $workshop->id)) {
1663 foreach ($submissions as $submission) {
1664 // see if the number of assessments has changed
1665 $nassessments = workshop_count_assessments($submission);
1666 if ($submission->nassessments <> $nassessments) {
1667 // ...if there are three or more assessments calculate the variance of each assessment.
1668 // Use the variance to find the "best" assessment. (When there is only one or two assessments they
1669 // are not altered by this routine.)
1670 if ($verbose) {
1671 echo "Processing submission $submission->id ($nassessments asessments)...\n";
1673 if ($nassessments > 2) {
1674 $num = 0; // weighted number of assessments
1675 for ($i = 0; $i < $workshop->nelements; $i++) {
1676 $sum[$i] = 0; // weighted sum of grades
1678 if ($assessments = workshop_get_assessments($submission)) {
1679 // first calculate the mean grades for each element
1680 foreach ($assessments as $assessment) {
1681 // test if assessment is "good", a teacher assessment always "good", but may be weighted out
1682 if (workshop_is_teacher($workshop, $assessment->userid)) {
1683 if (!$workshop->teacherweight) {
1684 // drop teacher's assessment as weight is zero
1685 continue;
1687 } else if ((!$assessment->gradinggrade and $assessment->timegraded) or
1688 ($workshop->agreeassessments and !$assessment->timeagreed)) {
1689 // it's a duff assessment, or it's not been agreed
1690 continue;
1692 if (workshop_is_teacher($workshop, $assessment->userid)) {
1693 $num += $workshop->teacherweight; // weight teacher's assessment
1694 } else {
1695 $num++; // student assessment just add one
1697 for ($i = 0; $i < $workshop->nelements; $i++) {
1698 $grade = get_field("workshop_grades", "grade",
1699 "assessmentid", $assessment->id, "elementno", $i);
1700 if (workshop_is_teacher($workshop, $assessment->userid)) {
1701 $sum[$i] += $workshop->teacherweight * $grade; // teacher's grade
1702 } else {
1703 $sum[$i] += $grade; // student's grade
1707 if ($num) { // could all the assessments be duff?
1708 for ($i = 0; $i < $workshop->nelements; $i++) {
1709 $mean[$i] = $sum[$i] / $num;
1710 if ($verbose) echo "Submission: $submission->id; Element: $i; Mean: {$mean[$i]}\n";
1712 } else {
1713 continue; // move to the next submission
1715 // run through the assessments again to see which is the "best" one (the one
1716 // closest to the mean)
1717 $lowest = 10e9;
1718 foreach ($assessments as $assessment) {
1719 if ($workshop->agreeassessments and !$assessment->timeagreed) {
1720 // ignore assessments that have not been agreed
1721 continue;
1723 $var = 0;
1724 for ($i = 0; $i < $workshop->nelements; $i++) {
1725 $grade = get_field("workshop_grades", "grade",
1726 "assessmentid", $assessment->id, "elementno", $i);
1727 if ($sd[$i] > $minvar) {
1728 $temp = ($mean[$i] - $grade) *
1729 $WORKSHOP_EWEIGHTS[$weight[$i]] / $sd[$i];
1730 } else {
1731 $temp = 0;
1733 $var += $temp * $temp;
1735 // find the "best" assessment of this submission
1736 if ($lowest > $var) {
1737 $lowest = $var;
1738 $bestassessmentid = $assessment->id;
1742 if (!$best = get_record("workshop_assessments", "id", $bestassessmentid)) {
1743 notify("Workshop grade assessments: cannot find best assessment");
1744 continue;
1746 if ($verbose) {
1747 echo "Best assessment is $bestassessmentid;\n";
1749 foreach ($assessments as $assessment) {
1750 // don't overwrite teacher's grade
1751 if ($assessment->teachergraded) {
1752 continue;
1754 if ($assessment->id == $bestassessmentid) {
1755 // it's the best one, set the grading grade to the maximum
1756 set_field("workshop_assessments", "gradinggrade", 100, "id", $assessment->id);
1757 set_field("workshop_assessments", "timegraded", $timenow, "id", $assessment->id);
1758 } else {
1759 // it's one of the pack, compare with the best...
1760 $gradinggrade = round(workshop_compare_assessments($workshop, $best, $assessment));
1761 // ...and save the grade for the assessment
1762 set_field("workshop_assessments", "gradinggrade", $gradinggrade, "id", $assessment->id);
1763 set_field("workshop_assessments", "timegraded", $timenow, "id", $assessment->id);
1767 } else {
1768 // there are less than 3 assessments for this submission
1769 if ($assessments = workshop_get_assessments($submission)) {
1770 foreach ($assessments as $assessment) {
1771 if (!$assessment->timegraded and !$assessment->teachergraded) {
1772 // set the grading grade to the maximum and say it's been graded
1773 set_field("workshop_assessments", "gradinggrade", 100, "id", $assessment->id);
1774 set_field("workshop_assessments", "timegraded", $timenow, "id", $assessment->id);
1779 // set the number of assessments for this submission
1780 set_field("workshop_submissions", "nassessments", $nassessments, "id", $submission->id);
1784 return;
1788 //////////////////////////////////////////////////////////////////////////////////////
1789 function workshop_gradinggrade($workshop, $student) {
1790 // returns the current (external) grading grade of the based on their (cold) assessments
1791 // (needed as it's called by grade)
1792 global $CFG;
1793 require_once(dirname(__FILE__) . '/locallib.php');
1795 $gradinggrade = 0;
1796 if ($assessments = workshop_get_user_assessments_done($workshop, $student)) {
1797 $n = 0;
1798 foreach ($assessments as $assessment) {
1799 $gradinggrade += $assessment->gradinggrade;
1800 $n++;
1802 if ($n < ($workshop->ntassessments + $workshop->nsassessments)) { // the minimum students should do
1803 $n = $workshop->ntassessments + $workshop->nsassessments;
1805 $gradinggrade = $gradinggrade / $n;
1807 return number_format($gradinggrade * $workshop->gradinggrade / 100, 1);
1811 //////////////////////////////////////////////////////////////////////////////////////
1812 function workshop_submission_grade($workshop, $submission) {
1813 // returns the current (external) grade of the submission based on the "good" (cold) assessments
1814 // (needed as it's called by grade)
1816 $grade = 0;
1817 if ($assessments = workshop_get_assessments($submission)) {
1818 $n = 0;
1819 foreach ($assessments as $assessment) {
1820 if ($workshop->agreeassessments and !$assessment->timeagreed) {
1821 // ignore assessments which have not been agreed
1822 continue;
1824 if ($assessment->gradinggrade or !$assessment->timegraded) {
1825 // a good assessment (or one that has not been graded yet)
1826 if (workshop_is_teacher($workshop, $assessment->userid)) {
1827 $timenow = time();
1828 if ($timenow > $workshop->releasegrades) {
1829 // teacher's grade is available
1830 $grade += $workshop->teacherweight * $assessment->grade;
1831 $n += $workshop->teacherweight;
1833 } else {
1834 $grade += $assessment->grade;
1835 $n++;
1839 if ($n) { // stop division by zero
1840 $grade = $grade / $n;
1843 return number_format($grade * $workshop->grade / 100, 1);
1847 /////////////////////////////////////////////////////////////////////////////
1848 function workshop_fullname($userid, $courseid) {
1849 global $CFG;
1850 if (!$user = get_record('user', 'id', $userid)) {
1851 return '';
1853 return '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.$courseid.'">'.
1854 fullname($user).'</a>';
1857 function workshop_get_view_actions() {
1858 return array('view','view all');
1861 function workshop_get_post_actions() {
1862 return array('agree','assess','comment','grade','newattachment','removeattachments','resubmit','submit');
1866 * Returns all other caps used in module
1868 function workshop_get_extra_capabilities() {
1869 return array('moodle/site:accessallgroups', 'moodle/site:viewfullnames');