d1290cec |
1 | <?php // $Id$ |
730fd187 |
2 | |
a5e1f35c |
3 | /// Library of function for module quiz |
730fd187 |
4 | |
c4d588cc |
5 | require_once($CFG->libdir.'/pagelib.php'); |
6 | |
a5e1f35c |
7 | /// CONSTANTS /////////////////////////////////////////////////////////////////// |
730fd187 |
8 | |
b2a3cd2d |
9 | define("QUIZ_MAX_EVENT_LENGTH", "432000"); // 5 days maximum |
8966a111 |
10 | |
a5e1f35c |
11 | /// FUNCTIONS /////////////////////////////////////////////////////////////////// |
730fd187 |
12 | |
13 | function quiz_add_instance($quiz) { |
f41e824f |
14 | /// Given an object containing all the necessary data, |
15 | /// (defined by the form in mod.html) this function |
16 | /// will create a new instance and return the id number |
a5e1f35c |
17 | /// of the new instance. |
730fd187 |
18 | |
49dcdd18 |
19 | $quiz->created = time(); |
730fd187 |
20 | $quiz->timemodified = time(); |
f41e824f |
21 | $quiz->timeopen = make_timestamp($quiz->openyear, $quiz->openmonth, $quiz->openday, |
c04c41c7 |
22 | $quiz->openhour, $quiz->openminute, 0); |
f41e824f |
23 | $quiz->timeclose = make_timestamp($quiz->closeyear, $quiz->closemonth, $quiz->closeday, |
c04c41c7 |
24 | $quiz->closehour, $quiz->closeminute, 0); |
6f797013 |
25 | |
56b2152f |
26 | if (empty($quiz->name)) { |
27 | if (empty($quiz->intro)) { |
28 | $quiz->name = get_string('modulename', 'quiz'); |
29 | } else { |
30 | $quiz->name = strip_tags($quiz->intro); |
31 | } |
32 | } |
33 | $quiz->name = trim($quiz->name); |
730fd187 |
34 | |
7bd1aa1d |
35 | if (!$quiz->id = insert_record("quiz", $quiz)) { |
36 | return false; // some error occurred |
37 | } |
6f797013 |
38 | |
34283aa8 |
39 | if (isset($quiz->optionsettingspref)) { |
40 | set_user_preference('quiz_optionsettingspref', $quiz->optionsettingspref); |
41 | } |
7bd1aa1d |
42 | |
565340c6 |
43 | delete_records('event', 'modulename', 'quiz', 'instance', $quiz->id); // Just in case |
44 | |
d2f308c0 |
45 | $event = NULL; |
46 | $event->name = $quiz->name; |
47 | $event->description = $quiz->intro; |
48 | $event->courseid = $quiz->course; |
49 | $event->groupid = 0; |
50 | $event->userid = 0; |
51 | $event->modulename = 'quiz'; |
52 | $event->instance = $quiz->id; |
b2a3cd2d |
53 | $event->eventtype = 'open'; |
d2f308c0 |
54 | $event->timestart = $quiz->timeopen; |
b71213e3 |
55 | $event->visible = instance_is_visible('quiz', $quiz); |
d2f308c0 |
56 | $event->timeduration = ($quiz->timeclose - $quiz->timeopen); |
b2a3cd2d |
57 | |
58 | if ($event->timeduration > QUIZ_MAX_EVENT_LENGTH) { /// Long durations create two events |
59 | $event2 = $event; |
60 | |
61 | $event->name .= ' ('.get_string('quizopens', 'quiz').')'; |
62 | $event->timeduration = 0; |
63 | |
64 | $event2->timestart = $quiz->timeclose; |
65 | $event2->eventtype = 'close'; |
66 | $event2->timeduration = 0; |
67 | $event2->name .= ' ('.get_string('quizcloses', 'quiz').')'; |
68 | |
69 | add_event($event2); |
d2f308c0 |
70 | } |
b2a3cd2d |
71 | |
d2f308c0 |
72 | add_event($event); |
73 | |
7bd1aa1d |
74 | return $quiz->id; |
730fd187 |
75 | } |
76 | |
77 | |
78 | function quiz_update_instance($quiz) { |
f41e824f |
79 | /// Given an object containing all the necessary data, |
34283aa8 |
80 | /// (defined by the form in mod.html or edit.php) this function |
a5e1f35c |
81 | /// will update an existing instance with new data. |
730fd187 |
82 | |
83 | $quiz->timemodified = time(); |
34283aa8 |
84 | if (isset($quiz->openyear)) { // this would not be set if we come from edit.php |
85 | $quiz->timeopen = make_timestamp($quiz->openyear, $quiz->openmonth, $quiz->openday, |
86 | $quiz->openhour, $quiz->openminute, 0); |
87 | $quiz->timeclose = make_timestamp($quiz->closeyear, $quiz->closemonth, $quiz->closeday, |
88 | $quiz->closehour, $quiz->closeminute, 0); |
89 | } |
730fd187 |
90 | $quiz->id = $quiz->instance; |
91 | |
7bd1aa1d |
92 | if (!update_record("quiz", $quiz)) { |
93 | return false; // some error occurred |
94 | } |
730fd187 |
95 | |
34283aa8 |
96 | if (isset($quiz->optionsettingspref)) { |
97 | set_user_preference('quiz_optionsettingspref', $quiz->optionsettingspref); |
98 | } |
7bd1aa1d |
99 | |
78036f78 |
100 | // currently this code deletes all existing events and adds new ones |
101 | // this should be improved to update existing events only |
102 | if ($events = get_records_select('event', "modulename = 'quiz' and instance = '$quiz->id'")) { |
103 | foreach($events as $event) { |
104 | delete_event($event->id); |
105 | } |
106 | } |
6f797013 |
107 | |
78036f78 |
108 | unset($event); |
565340c6 |
109 | $event->description = $quiz->intro; |
110 | $event->courseid = $quiz->course; |
111 | $event->groupid = 0; |
112 | $event->userid = 0; |
113 | $event->modulename = 'quiz'; |
114 | $event->instance = $quiz->id; |
115 | $event->eventtype = 'open'; |
116 | $event->timestart = $quiz->timeopen; |
ba288539 |
117 | $event->visible = instance_is_visible('quiz', $quiz); |
565340c6 |
118 | $event->timeduration = ($quiz->timeclose - $quiz->timeopen); |
d2f308c0 |
119 | |
565340c6 |
120 | if ($event->timeduration > QUIZ_MAX_EVENT_LENGTH) { /// Long durations create two events |
d2f308c0 |
121 | |
78036f78 |
122 | $event->name = $quiz->name.' ('.get_string('quizopens', 'quiz').')'; |
565340c6 |
123 | $event->timeduration = 0; |
78036f78 |
124 | add_event($event); |
565340c6 |
125 | |
78036f78 |
126 | $event->timestart = $quiz->timeclose; |
127 | $event->eventtype = 'close'; |
128 | $event->name = $quiz->name.' ('.get_string('quizcloses', 'quiz').')'; |
129 | unset($event->id); |
130 | add_event($event); |
131 | } else { // single event with duration |
132 | $event->name = $quiz->name; |
133 | add_event($event); |
d2f308c0 |
134 | } |
135 | |
7bd1aa1d |
136 | return true; |
730fd187 |
137 | } |
138 | |
139 | |
140 | function quiz_delete_instance($id) { |
f41e824f |
141 | /// Given an ID of an instance of this module, |
142 | /// this function will permanently delete the instance |
143 | /// and any data that depends on it. |
730fd187 |
144 | |
145 | if (! $quiz = get_record("quiz", "id", "$id")) { |
146 | return false; |
147 | } |
148 | |
149 | $result = true; |
150 | |
464edd6d |
151 | if ($attempts = get_records("quiz_attempts", "quiz", "$quiz->id")) { |
10b9291c |
152 | foreach ($attempts as $attempt) { |
153 | if (! delete_records("quiz_responses", "attempt", "$attempt->id")) { |
154 | $result = false; |
155 | } |
156 | } |
157 | } |
158 | |
159 | if (! delete_records("quiz_attempts", "quiz", "$quiz->id")) { |
160 | $result = false; |
161 | } |
162 | |
163 | if (! delete_records("quiz_grades", "quiz", "$quiz->id")) { |
164 | $result = false; |
165 | } |
166 | |
167 | if (! delete_records("quiz_question_grades", "quiz", "$quiz->id")) { |
168 | $result = false; |
169 | } |
730fd187 |
170 | |
171 | if (! delete_records("quiz", "id", "$quiz->id")) { |
172 | $result = false; |
173 | } |
174 | |
880d8675 |
175 | $pagetypes = page_import_types('mod/quiz/'); |
176 | foreach($pagetypes as $pagetype) { |
177 | if(!delete_records('block_instance', 'pageid', $quiz->id, 'pagetype', $pagetype)) { |
178 | $result = false; |
179 | } |
180 | } |
181 | |
78036f78 |
182 | if ($events = get_records_select('event', "modulename = 'quiz' and instance = '$quiz->id'")) { |
183 | foreach($events as $event) { |
184 | delete_event($event->id); |
185 | } |
b2a3cd2d |
186 | } |
187 | |
730fd187 |
188 | return $result; |
189 | } |
190 | |
b2d594c8 |
191 | function quiz_delete_course($course) { |
192 | /// Given a course object, this function will clean up anything that |
193 | /// would be leftover after all the instances were deleted |
464edd6d |
194 | /// In this case, all non-publish quiz categories and questions |
b2d594c8 |
195 | |
464edd6d |
196 | if ($categories = get_records_select("quiz_categories", "course = '$course->id' AND publish = '0'")) { |
b2d594c8 |
197 | foreach ($categories as $category) { |
198 | if ($questions = get_records("quiz_questions", "category", $category->id)) { |
199 | foreach ($questions as $question) { |
200 | delete_records("quiz_answers", "question", $question->id); |
201 | delete_records("quiz_match", "question", $question->id); |
202 | delete_records("quiz_match_sub", "question", $question->id); |
203 | delete_records("quiz_multianswers", "question", $question->id); |
204 | delete_records("quiz_multichoice", "question", $question->id); |
205 | delete_records("quiz_numerical", "question", $question->id); |
206 | delete_records("quiz_randommatch", "question", $question->id); |
207 | delete_records("quiz_responses", "question", $question->id); |
208 | delete_records("quiz_shortanswer", "question", $question->id); |
209 | delete_records("quiz_truefalse", "question", $question->id); |
210 | } |
211 | delete_records("quiz_questions", "category", $category->id); |
212 | } |
213 | } |
214 | return delete_records("quiz_categories", "course", $course->id); |
215 | } |
216 | return true; |
217 | } |
218 | |
219 | |
730fd187 |
220 | function quiz_user_outline($course, $user, $mod, $quiz) { |
f41e824f |
221 | /// Return a small object with summary information about what a |
a5e1f35c |
222 | /// user has done with a given particular instance of this module |
223 | /// Used for user activity reports. |
224 | /// $return->time = the time they did it |
225 | /// $return->info = a short text description |
9d677360 |
226 | if ($grade = get_record('quiz_grades', 'userid', $user->id, 'quiz', $quiz->id)) { |
f41e824f |
227 | |
090cf95a |
228 | if ((float)$grade->grade) { |
c6e88f10 |
229 | $result->info = get_string('grade').': '.format_float($grade->grade, $quiz->decimalpoints); |
98092498 |
230 | } |
231 | $result->time = $grade->timemodified; |
232 | return $result; |
233 | } |
234 | return NULL; |
730fd187 |
235 | |
730fd187 |
236 | } |
237 | |
238 | function quiz_user_complete($course, $user, $mod, $quiz) { |
f41e824f |
239 | /// Print a detailed representation of what a user has done with |
a5e1f35c |
240 | /// a given particular instance of this module, for user activity reports. |
730fd187 |
241 | |
242 | return true; |
243 | } |
244 | |
730fd187 |
245 | function quiz_cron () { |
a5e1f35c |
246 | /// Function to be run periodically according to the moodle cron |
f41e824f |
247 | /// This function searches for things that need to be done, such |
248 | /// as sending out mail, toggling flags etc ... |
730fd187 |
249 | |
250 | global $CFG; |
251 | |
252 | return true; |
253 | } |
254 | |
d0ac6bc2 |
255 | function quiz_grades($quizid) { |
858deff0 |
256 | /// Must return an array of grades, indexed by user, and a max grade. |
257 | |
d5838a4b |
258 | $quiz = get_record('quiz', 'id', intval($quizid)); |
259 | if (empty($quiz) || empty($quiz->grade)) { |
ed1daaa9 |
260 | return NULL; |
261 | } |
262 | |
d5838a4b |
263 | $return->grades = get_records_menu('quiz_grades', 'quiz', $quiz->id, '', 'userid, grade'); |
264 | $return->maxgrade = get_field('quiz', 'grade', 'id', $quiz->id); |
858deff0 |
265 | return $return; |
d0ac6bc2 |
266 | } |
267 | |
d061d883 |
268 | function quiz_get_participants($quizid) { |
269 | /// Returns an array of users who have data in a given quiz |
270 | /// (users with records in quiz_attempts, students) |
271 | |
272 | global $CFG; |
273 | |
95e72c12 |
274 | return get_records_sql("SELECT DISTINCT u.id, u.id |
d061d883 |
275 | FROM {$CFG->prefix}user u, |
276 | {$CFG->prefix}quiz_attempts a |
f41e824f |
277 | WHERE a.quiz = '$quizid' and |
d061d883 |
278 | u.id = a.userid"); |
279 | } |
730fd187 |
280 | |
d2f308c0 |
281 | function quiz_refresh_events($courseid = 0) { |
282 | // This standard function will check all instances of this module |
283 | // and make sure there are up-to-date events created for each of them. |
b2a3cd2d |
284 | // If courseid = 0, then every quiz event in the site is checked, else |
285 | // only quiz events belonging to the course specified are checked. |
d2f308c0 |
286 | // This function is used, in its new format, by restore_refresh_events() |
287 | |
288 | if ($courseid == 0) { |
289 | if (! $quizzes = get_records("quiz")) { |
290 | return true; |
291 | } |
292 | } else { |
293 | if (! $quizzes = get_records("quiz", "course", $courseid)) { |
294 | return true; |
295 | } |
296 | } |
dcd338ff |
297 | $moduleid = get_field('modules', 'id', 'name', 'quiz'); |
f41e824f |
298 | |
d2f308c0 |
299 | foreach ($quizzes as $quiz) { |
300 | $event = NULL; |
b2a3cd2d |
301 | $event2 = NULL; |
302 | $event2old = NULL; |
303 | |
304 | if ($events = get_records_select('event', "modulename = 'quiz' AND instance = '$quiz->id' ORDER BY timestart")) { |
305 | $event = array_shift($events); |
306 | if (!empty($events)) { |
307 | $event2old = array_shift($events); |
308 | if (!empty($events)) { |
309 | foreach ($events as $badevent) { |
310 | delete_records('event', 'id', $badevent->id); |
311 | } |
312 | } |
313 | } |
314 | } |
315 | |
d2f308c0 |
316 | $event->name = addslashes($quiz->name); |
317 | $event->description = addslashes($quiz->intro); |
b2a3cd2d |
318 | $event->courseid = $quiz->course; |
319 | $event->groupid = 0; |
320 | $event->userid = 0; |
321 | $event->modulename = 'quiz'; |
322 | $event->instance = $quiz->id; |
ba288539 |
323 | $event->visible = instance_is_visible('quiz', $quiz); |
d2f308c0 |
324 | $event->timestart = $quiz->timeopen; |
b2a3cd2d |
325 | $event->eventtype = 'open'; |
d2f308c0 |
326 | $event->timeduration = ($quiz->timeclose - $quiz->timeopen); |
d2f308c0 |
327 | |
b2a3cd2d |
328 | if ($event->timeduration > QUIZ_MAX_EVENT_LENGTH) { /// Set up two events |
d2f308c0 |
329 | |
b2a3cd2d |
330 | $event2 = $event; |
d2f308c0 |
331 | |
b2a3cd2d |
332 | $event->name = addslashes($quiz->name).' ('.get_string('quizopens', 'quiz').')'; |
333 | $event->timeduration = 0; |
334 | |
335 | $event2->name = addslashes($quiz->name).' ('.get_string('quizcloses', 'quiz').')'; |
336 | $event2->timestart = $quiz->timeclose; |
337 | $event2->eventtype = 'close'; |
338 | $event2->timeduration = 0; |
339 | |
340 | if (empty($event2old->id)) { |
341 | unset($event2->id); |
342 | add_event($event2); |
343 | } else { |
344 | $event2->id = $event2old->id; |
345 | update_event($event2); |
346 | } |
347 | } else if (!empty($event2->id)) { |
348 | delete_event($event2->id); |
349 | } |
350 | |
351 | if (empty($event->id)) { |
d2f308c0 |
352 | add_event($event); |
b2a3cd2d |
353 | } else { |
354 | update_event($event); |
d2f308c0 |
355 | } |
b2a3cd2d |
356 | |
d2f308c0 |
357 | } |
358 | return true; |
359 | } |
360 | |
6710ec87 |
361 | |
362 | function quiz_get_recent_mod_activity(&$activities, &$index, $sincetime, $courseid, $quiz="0", $user="", $groupid="") { |
363 | // Returns all quizzes since a given time. If quiz is specified then |
364 | // this restricts the results |
365 | |
366 | global $CFG; |
367 | |
368 | if ($quiz) { |
369 | $quizselect = " AND cm.id = '$quiz'"; |
370 | } else { |
371 | $quizselect = ""; |
372 | } |
373 | if ($user) { |
374 | $userselect = " AND u.id = '$user'"; |
375 | } else { |
376 | $userselect = ""; |
377 | } |
378 | |
379 | $quizzes = get_records_sql("SELECT qa.*, q.name, u.firstname, u.lastname, u.picture, |
380 | q.course, q.sumgrades as maxgrade, cm.instance, cm.section |
381 | FROM {$CFG->prefix}quiz_attempts qa, |
382 | {$CFG->prefix}quiz q, |
383 | {$CFG->prefix}user u, |
384 | {$CFG->prefix}course_modules cm |
385 | WHERE qa.timefinish > '$sincetime' |
386 | AND qa.userid = u.id $userselect |
387 | AND qa.quiz = q.id $quizselect |
388 | AND cm.instance = q.id |
389 | AND cm.course = '$courseid' |
390 | AND q.course = cm.course |
391 | ORDER BY qa.timefinish ASC"); |
392 | |
393 | if (empty($quizzes)) |
394 | return; |
395 | |
396 | foreach ($quizzes as $quiz) { |
397 | if (empty($groupid) || ismember($groupid, $quiz->userid)) { |
398 | |
399 | $tmpactivity->type = "quiz"; |
400 | $tmpactivity->defaultindex = $index; |
401 | $tmpactivity->instance = $quiz->quiz; |
402 | |
403 | $tmpactivity->name = $quiz->name; |
404 | $tmpactivity->section = $quiz->section; |
405 | |
406 | $tmpactivity->content->attemptid = $quiz->id; |
407 | $tmpactivity->content->sumgrades = $quiz->sumgrades; |
408 | $tmpactivity->content->maxgrade = $quiz->maxgrade; |
409 | $tmpactivity->content->attempt = $quiz->attempt; |
410 | |
411 | $tmpactivity->user->userid = $quiz->userid; |
412 | $tmpactivity->user->fullname = fullname($quiz); |
413 | $tmpactivity->user->picture = $quiz->picture; |
414 | |
415 | $tmpactivity->timestamp = $quiz->timefinish; |
416 | |
417 | $activities[] = $tmpactivity; |
418 | |
419 | $index++; |
420 | } |
421 | } |
422 | |
423 | return; |
424 | } |
425 | |
426 | |
427 | function quiz_print_recent_mod_activity($activity, $course, $detail=false) { |
6eaae5bd |
428 | global $CFG; |
6710ec87 |
429 | |
430 | echo '<table border="0" cellpadding="3" cellspacing="0">'; |
431 | |
6f797013 |
432 | echo "<tr><td class=\"forumpostpicture\" width=\"35\" valign=\"top\">"; |
6710ec87 |
433 | print_user_picture($activity->user->userid, $course, $activity->user->picture); |
434 | echo "</td><td width=\"100%\"><font size=\"2\">"; |
435 | |
436 | if ($detail) { |
437 | echo "<img src=\"$CFG->modpixpath/$activity->type/icon.gif\" ". |
438 | "height=\"16\" width=\"16\" alt=\"$activity->type\" /> "; |
439 | echo "<a href=\"$CFG->wwwroot/mod/quiz/view.php?id=" . $activity->instance . "\">" |
440 | . $activity->name . "</a> - "; |
441 | |
442 | } |
443 | |
444 | if (isteacher($course)) { |
445 | $grades = "(" . $activity->content->sumgrades . " / " . $activity->content->maxgrade . ") "; |
446 | echo "<a href=\"$CFG->wwwroot/mod/quiz/review.php?q=" |
447 | . $activity->instance . "&attempt=" |
448 | . $activity->content->attemptid . "\">" . $grades . "</a> "; |
449 | |
450 | echo get_string("attempt", "quiz") . " - " . $activity->content->attempt . "<br />"; |
451 | } |
452 | echo "<a href=\"$CFG->wwwroot/user/view.php?id=" |
453 | . $activity->user->userid . "&course=$course\">" |
454 | . $activity->user->fullname . "</a> "; |
455 | |
456 | echo " - " . userdate($activity->timestamp); |
457 | |
458 | echo "</font></td></tr>"; |
459 | echo "</table>"; |
460 | |
461 | return; |
462 | } |
463 | |
730fd187 |
464 | ?> |