e4aa175a |
1 | <?php // $Id$ |
2 | |
9528568b |
3 | define('SCORM_TYPE_LOCAL', 'local'); |
4 | define('SCORM_TYPE_LOCALSYNC', 'localsync'); |
5 | define('SCORM_TYPE_EXTERNAL', 'external'); |
6 | define('SCORM_TYPE_IMSREPOSITORY', 'imsrepository'); |
7 | |
8 | |
e4aa175a |
9 | /** |
10 | * Given an object containing all the necessary data, |
7cac0c4b |
11 | * (defined by the form in mod_form.php) this function |
e4aa175a |
12 | * will create a new instance and return the id number |
13 | * of the new instance. |
14 | * |
9528568b |
15 | * @param object $scorm Form data |
16 | * @param object $mform |
17 | * @return int new instance id |
e4aa175a |
18 | */ |
9528568b |
19 | |
20 | function scorm_add_instance($scorm, $mform=null) { |
c18269c7 |
21 | global $CFG, $DB; |
a679d64d |
22 | |
23 | require_once('locallib.php'); |
24 | |
d54e2145 |
25 | if (empty($scorm->timerestrict)) { |
26 | $scorm->timeopen = 0; |
27 | $scorm->timeclose = 0; |
28 | } |
29 | |
9528568b |
30 | $cmid = $scorm->coursemodule; |
31 | $cmidnumber = $scorm->cmidnumber; |
32 | $courseid = $scorm->course; |
76ea4fb4 |
33 | |
9528568b |
34 | $context = get_context_instance(CONTEXT_MODULE, $cmid); |
a679d64d |
35 | |
9528568b |
36 | $scorm = scorm_option2text($scorm); |
37 | $scorm->width = (int)str_replace('%', '', $scorm->width); |
38 | $scorm->height = (int)str_replace('%', '', $scorm->height); |
e4aa175a |
39 | |
9528568b |
40 | if (!isset($scorm->whatgrade)) { |
41 | $scorm->whatgrade = 0; |
42 | } |
43 | $scorm->grademethod = ($scorm->whatgrade * 10) + $scorm->grademethod; |
b3659259 |
44 | |
9528568b |
45 | if (!$id = $DB->insert_record('scorm', $scorm)) { |
46 | return false; |
47 | } |
e4aa175a |
48 | |
9528568b |
49 | /// update course module record - from now on this instance properly exists and all function may be used |
50 | if (!$DB->set_field('course_modules', 'instance', $id, array('id'=>$cmid))) { |
51 | print_error('cannotaddcoursemodule'); |
52 | } |
e4aa175a |
53 | |
9528568b |
54 | /// reload scorm instance |
55 | $scorm = $DB->get_record('scorm', array('id'=>$id)); |
56 | |
57 | /// store the package and verify |
58 | if ($scorm->scormtype === SCORM_TYPE_LOCAL) { |
59 | if ($mform) { |
60 | $filename = $mform->get_new_filename('packagefile'); |
61 | if ($filename !== false) { |
62 | $fs = get_file_storage(); |
63 | $fs->delete_area_files($context->id, 'scorm_package'); |
64 | $mform->save_stored_file('packagefile', $context->id, 'scorm_package', 0, '/', $filename); |
65 | $scorm->reference = $filename; |
8ba4f1e0 |
66 | } |
e4aa175a |
67 | } |
68 | |
9528568b |
69 | } else if ($scorm->scormtype === SCORM_TYPE_LOCALSYNC) { |
70 | $scorm->reference = $scorm->packageurl; |
e4aa175a |
71 | |
9528568b |
72 | } else if ($scorm->scormtype === SCORM_TYPE_EXTERNAL) { |
73 | $scorm->reference = $scorm->packageurl; |
74 | |
75 | } else if ($scorm->scormtype === SCORM_TYPE_IMSREPOSITORY) { |
76 | $scorm->reference = $scorm->packageurl; |
531fa830 |
77 | |
a679d64d |
78 | } else { |
9528568b |
79 | return false; |
e4aa175a |
80 | } |
9528568b |
81 | |
82 | // save reference |
83 | $DB->update_record('scorm', $scorm); |
84 | |
85 | |
86 | /// extra fields required in grade related functions |
87 | $scorm->course = $courseid; |
88 | $scorm->cmidnumber = $cmidnumber; |
89 | $scorm->cmid = $cmid; |
90 | |
91 | scorm_parse($scorm, true); |
92 | |
93 | scorm_grade_item_update($scorm); |
94 | |
95 | return $scorm->id; |
e4aa175a |
96 | } |
97 | |
98 | /** |
99 | * Given an object containing all the necessary data, |
7cac0c4b |
100 | * (defined by the form in mod_form.php) this function |
e4aa175a |
101 | * will update an existing instance with new data. |
102 | * |
9528568b |
103 | * @param object $scorm Form data |
104 | * @param object $mform |
105 | * @return bool success |
e4aa175a |
106 | */ |
9528568b |
107 | function scorm_update_instance($scorm, $mform=null) { |
c18269c7 |
108 | global $CFG, $DB; |
e4aa175a |
109 | |
a679d64d |
110 | require_once('locallib.php'); |
76ea4fb4 |
111 | |
d54e2145 |
112 | if (empty($scorm->timerestrict)) { |
113 | $scorm->timeopen = 0; |
114 | $scorm->timeclose = 0; |
115 | } |
116 | |
9528568b |
117 | $cmid = $scorm->coursemodule; |
118 | $cmidnumber = $scorm->cmidnumber; |
119 | $courseid = $scorm->course; |
120 | |
121 | $scorm->id = $scorm->instance; |
122 | |
123 | $context = get_context_instance(CONTEXT_MODULE, $cmid); |
124 | |
125 | if ($scorm->scormtype === SCORM_TYPE_LOCAL) { |
126 | if ($mform) { |
127 | $filename = $mform->get_new_filename('packagefile'); |
128 | if ($filename !== false) { |
129 | $scorm->reference = $filename; |
130 | $fs = get_file_storage(); |
131 | $fs->delete_area_files($context->id, 'scorm_package'); |
132 | $mform->save_stored_file('packagefile', $context->id, 'scorm_package', 0, '/', $filename); |
a679d64d |
133 | } |
76ea4fb4 |
134 | } |
76ea4fb4 |
135 | |
9528568b |
136 | } else if ($scorm->scormtype === SCORM_TYPE_LOCALSYNC) { |
137 | $scorm->reference = $scorm->packageurl; |
138 | |
139 | } else if ($scorm->scormtype === SCORM_TYPE_EXTERNAL) { |
140 | $scorm->reference = $scorm->packageurl; |
141 | |
142 | } else if ($scorm->scormtype === SCORM_TYPE_IMSREPOSITORY) { |
143 | $scorm->reference = $scorm->packageurl; |
144 | |
145 | } else { |
146 | return false; |
147 | } |
bfe8c2f0 |
148 | |
e4aa175a |
149 | $scorm = scorm_option2text($scorm); |
9528568b |
150 | $scorm->width = (int)str_replace('%','',$scorm->width); |
151 | $scorm->height = (int)str_replace('%','',$scorm->height); |
152 | $scorm->timemodified = time(); |
e4aa175a |
153 | |
b3659259 |
154 | if (!isset($scorm->whatgrade)) { |
155 | $scorm->whatgrade = 0; |
156 | } |
9528568b |
157 | $scorm->grademethod = ($scorm->whatgrade * 10) + $scorm->grademethod; |
a30b6819 |
158 | |
9528568b |
159 | if (!$DB->update_record('scorm', $scorm)) { |
160 | return false; |
531fa830 |
161 | } |
162 | |
9528568b |
163 | $scorm = $DB->get_record('scorm', array('id'=>$scorm->id)); |
164 | |
165 | /// extra fields required in grade related functions |
166 | $scorm->course = $courseid; |
167 | $scorm->idnumber = $cmidnumber; |
168 | $scorm->cmid = $cmid; |
169 | |
170 | scorm_parse($scorm, (bool)$scorm->updatefreq); |
171 | |
172 | scorm_grade_item_update($scorm); |
173 | |
174 | return true; |
e4aa175a |
175 | } |
176 | |
177 | /** |
178 | * Given an ID of an instance of this module, |
179 | * this function will permanently delete the instance |
180 | * and any data that depends on it. |
181 | * |
182 | * @param int $id Scorm instance id |
183 | * @return boolean |
184 | */ |
185 | function scorm_delete_instance($id) { |
c18269c7 |
186 | global $CFG, $DB; |
e4aa175a |
187 | |
c18269c7 |
188 | if (! $scorm = $DB->get_record('scorm', array('id'=>$id))) { |
e4aa175a |
189 | return false; |
190 | } |
191 | |
192 | $result = true; |
193 | |
e4aa175a |
194 | // Delete any dependent records |
c18269c7 |
195 | if (! $DB->delete_records('scorm_scoes_track', array('scormid'=>$scorm->id))) { |
e4aa175a |
196 | $result = false; |
197 | } |
c18269c7 |
198 | if ($scoes = $DB->get_records('scorm_scoes', array('scorm'=>$scorm->id))) { |
b3659259 |
199 | foreach ($scoes as $sco) { |
c18269c7 |
200 | if (! $DB->delete_records('scorm_scoes_data', array('scoid'=>$sco->id))) { |
b3659259 |
201 | $result = false; |
202 | } |
9528568b |
203 | } |
c18269c7 |
204 | $DB->delete_records('scorm_scoes', array('scorm'=>$scorm->id)); |
b3659259 |
205 | } else { |
e4aa175a |
206 | $result = false; |
207 | } |
c18269c7 |
208 | if (! $DB->delete_records('scorm', array('id'=>$scorm->id))) { |
e4aa175a |
209 | $result = false; |
210 | } |
a30b6819 |
211 | |
c18269c7 |
212 | /*if (! $DB->delete_records('scorm_sequencing_controlmode', array('scormid'=>$scorm->id))) { |
e4aa175a |
213 | $result = false; |
214 | } |
c18269c7 |
215 | if (! $DB->delete_records('scorm_sequencing_rolluprules', array('scormid'=>$scorm->id))) { |
e4aa175a |
216 | $result = false; |
217 | } |
c18269c7 |
218 | if (! $DB->delete_records('scorm_sequencing_rolluprule', array('scormid'=>$scorm->id))) { |
e4aa175a |
219 | $result = false; |
220 | } |
c18269c7 |
221 | if (! $DB->delete_records('scorm_sequencing_rollupruleconditions', array('scormid'=>$scorm->id))) { |
e4aa175a |
222 | $result = false; |
223 | } |
c18269c7 |
224 | if (! $DB->delete_records('scorm_sequencing_rolluprulecondition', array('scormid'=>$scorm->id))) { |
e4aa175a |
225 | $result = false; |
226 | } |
c18269c7 |
227 | if (! $DB->delete_records('scorm_sequencing_rulecondition', array('scormid'=>$scorm->id))) { |
e4aa175a |
228 | $result = false; |
229 | } |
c18269c7 |
230 | if (! $DB->delete_records('scorm_sequencing_ruleconditions', array('scormid'=>$scorm->id))) { |
e4aa175a |
231 | $result = false; |
9528568b |
232 | }*/ |
531fa830 |
233 | |
c18269c7 |
234 | scorm_grade_item_delete($scorm); |
9528568b |
235 | |
e4aa175a |
236 | return $result; |
237 | } |
238 | |
239 | /** |
240 | * Return a small object with summary information about what a |
241 | * user has done with a given particular instance of this module |
242 | * Used for user activity reports. |
243 | * |
244 | * @param int $course Course id |
245 | * @param int $user User id |
9528568b |
246 | * @param int $mod |
e4aa175a |
247 | * @param int $scorm The scorm id |
248 | * @return mixed |
249 | */ |
9528568b |
250 | function scorm_user_outline($course, $user, $mod, $scorm) { |
531fa830 |
251 | global $CFG; |
a30b6819 |
252 | require_once('locallib.php'); |
253 | |
254 | $return = scorm_grade_user($scorm, $user->id, true); |
255 | |
e4aa175a |
256 | return $return; |
257 | } |
258 | |
259 | /** |
260 | * Print a detailed representation of what a user has done with |
261 | * a given particular instance of this module, for user activity reports. |
262 | * |
263 | * @param int $course Course id |
264 | * @param int $user User id |
9528568b |
265 | * @param int $mod |
e4aa175a |
266 | * @param int $scorm The scorm id |
267 | * @return boolean |
268 | */ |
269 | function scorm_user_complete($course, $user, $mod, $scorm) { |
bf347041 |
270 | global $CFG, $DB; |
e4aa175a |
271 | |
272 | $liststyle = 'structlist'; |
273 | $scormpixdir = $CFG->modpixpath.'/scorm/pix'; |
274 | $now = time(); |
275 | $firstmodify = $now; |
276 | $lastmodify = 0; |
277 | $sometoreport = false; |
278 | $report = ''; |
9528568b |
279 | |
bf347041 |
280 | if ($orgs = $DB->get_records('scorm_scoes', array('scorm'=>$scorm->id, 'organization'=>'', 'launch'=>''),'id','id,identifier,title')) { |
e4aa175a |
281 | if (count($orgs) <= 1) { |
282 | unset($orgs); |
283 | $orgs[]->identifier = ''; |
284 | } |
285 | $report .= '<div class="mod-scorm">'."\n"; |
286 | foreach ($orgs as $org) { |
bf347041 |
287 | $conditions = array(); |
e4aa175a |
288 | $currentorg = ''; |
289 | if (!empty($org->identifier)) { |
290 | $report .= '<div class="orgtitle">'.$org->title.'</div>'; |
291 | $currentorg = $org->identifier; |
bf347041 |
292 | $conditions['organization'] = $currentorg; |
e4aa175a |
293 | } |
294 | $report .= "<ul id='0' class='$liststyle'>"; |
bf347041 |
295 | $conditions['scorm'] = $scorm->id; |
296 | if ($scoes = $DB->get_records('scorm_scoes', $conditions, "id ASC")){ |
9fb2de4e |
297 | // drop keys so that we can access array sequentially |
9528568b |
298 | $scoes = array_values($scoes); |
e4aa175a |
299 | $level=0; |
300 | $sublist=1; |
301 | $parents[$level]='/'; |
9fb2de4e |
302 | foreach ($scoes as $pos=>$sco) { |
e4aa175a |
303 | if ($parents[$level]!=$sco->parent) { |
304 | if ($level>0 && $parents[$level-1]==$sco->parent) { |
305 | $report .= "\t\t</ul></li>\n"; |
306 | $level--; |
307 | } else { |
308 | $i = $level; |
309 | $closelist = ''; |
310 | while (($i > 0) && ($parents[$level] != $sco->parent)) { |
311 | $closelist .= "\t\t</ul></li>\n"; |
312 | $i--; |
313 | } |
314 | if (($i == 0) && ($sco->parent != $currentorg)) { |
315 | $report .= "\t\t<li><ul id='$sublist' class='$liststyle'>\n"; |
316 | $level++; |
317 | } else { |
318 | $report .= $closelist; |
319 | $level = $i; |
320 | } |
321 | $parents[$level]=$sco->parent; |
322 | } |
323 | } |
324 | $report .= "\t\t<li>"; |
9fb2de4e |
325 | if (isset($scoes[$pos+1])) { |
326 | $nextsco = $scoes[$pos+1]; |
327 | } else { |
328 | $nextsco = false; |
329 | } |
e4aa175a |
330 | if (($nextsco !== false) && ($sco->parent != $nextsco->parent) && (($level==0) || (($level>0) && ($nextsco->parent == $sco->identifier)))) { |
331 | $sublist++; |
332 | } else { |
7150b8ae |
333 | $report .= '<img src="'.$scormpixdir.'/spacer.gif" alt="" />'; |
e4aa175a |
334 | } |
335 | |
336 | if ($sco->launch) { |
337 | require_once('locallib.php'); |
338 | $score = ''; |
339 | $totaltime = ''; |
340 | if ($usertrack=scorm_get_tracks($sco->id,$user->id)) { |
341 | if ($usertrack->status == '') { |
342 | $usertrack->status = 'notattempted'; |
343 | } |
344 | $strstatus = get_string($usertrack->status,'scorm'); |
345 | $report .= "<img src='".$scormpixdir.'/'.$usertrack->status.".gif' alt='$strstatus' title='$strstatus' />"; |
346 | if ($usertrack->timemodified != 0) { |
347 | if ($usertrack->timemodified > $lastmodify) { |
348 | $lastmodify = $usertrack->timemodified; |
349 | } |
350 | if ($usertrack->timemodified < $firstmodify) { |
351 | $firstmodify = $usertrack->timemodified; |
352 | } |
353 | } |
354 | } else { |
355 | if ($sco->scormtype == 'sco') { |
356 | $report .= '<img src="'.$scormpixdir.'/'.'notattempted.gif" alt="'.get_string('notattempted','scorm').'" title="'.get_string('notattempted','scorm').'" />'; |
357 | } else { |
358 | $report .= '<img src="'.$scormpixdir.'/'.'asset.gif" alt="'.get_string('asset','scorm').'" title="'.get_string('asset','scorm').'" />'; |
359 | } |
360 | } |
361 | $report .= " $sco->title $score$totaltime</li>\n"; |
362 | if ($usertrack !== false) { |
363 | $sometoreport = true; |
364 | $report .= "\t\t\t<li><ul class='$liststyle'>\n"; |
365 | foreach($usertrack as $element => $value) { |
366 | if (substr($element,0,3) == 'cmi') { |
367 | $report .= '<li>'.$element.' => '.$value.'</li>'; |
368 | } |
369 | } |
370 | $report .= "\t\t\t</ul></li>\n"; |
9528568b |
371 | } |
e4aa175a |
372 | } else { |
373 | $report .= " $sco->title</li>\n"; |
374 | } |
375 | } |
376 | for ($i=0;$i<$level;$i++) { |
377 | $report .= "\t\t</ul></li>\n"; |
378 | } |
379 | } |
380 | $report .= "\t</ul><br />\n"; |
381 | } |
382 | $report .= "</div>\n"; |
383 | } |
384 | if ($sometoreport) { |
385 | if ($firstmodify < $now) { |
386 | $timeago = format_time($now - $firstmodify); |
387 | echo get_string('firstaccess','scorm').': '.userdate($firstmodify).' ('.$timeago.")<br />\n"; |
388 | } |
389 | if ($lastmodify > 0) { |
390 | $timeago = format_time($now - $lastmodify); |
391 | echo get_string('lastaccess','scorm').': '.userdate($lastmodify).' ('.$timeago.")<br />\n"; |
392 | } |
393 | echo get_string('report','scorm').":<br />\n"; |
394 | echo $report; |
395 | } else { |
dabfd0ed |
396 | print_string('noactivity','scorm'); |
e4aa175a |
397 | } |
398 | |
399 | return true; |
400 | } |
401 | |
e4aa175a |
402 | /** |
403 | * Function to be run periodically according to the moodle cron |
404 | * This function searches for things that need to be done, such |
405 | * as sending out mail, toggling flags etc ... |
406 | * |
407 | * @return boolean |
408 | */ |
409 | function scorm_cron () { |
bf347041 |
410 | global $CFG, $DB; |
a679d64d |
411 | |
412 | require_once('locallib.php'); |
413 | |
414 | $sitetimezone = $CFG->timezone; |
9528568b |
415 | /// Now see if there are any scorm updates to be done |
416 | |
bfe8c2f0 |
417 | if (!isset($CFG->scorm_updatetimelast)) { // To catch the first time |
418 | set_config('scorm_updatetimelast', 0); |
419 | } |
420 | |
a679d64d |
421 | $timenow = time(); |
8f54becc |
422 | $updatetime = usergetmidnight($timenow, $sitetimezone) + ($CFG->scorm_updatetimelast * 3600); |
a679d64d |
423 | |
424 | if ($CFG->scorm_updatetimelast < $updatetime and $timenow > $updatetime) { |
425 | |
bfe8c2f0 |
426 | set_config('scorm_updatetimelast', $timenow); |
e4aa175a |
427 | |
376c9c70 |
428 | mtrace('Updating scorm packages which require daily update');//We are updating |
bfe8c2f0 |
429 | |
bf347041 |
430 | $scormsupdate = $DB->get_records('scorm', array('updatefreq'=>UPDATE_EVERYDAY)); |
9528568b |
431 | foreach($scormsupdate as $scormupdate) { |
432 | scorm_parse($scormupdate, true); |
a679d64d |
433 | } |
434 | } |
435 | |
e4aa175a |
436 | return true; |
437 | } |
438 | |
439 | /** |
531fa830 |
440 | * Return grade for given user or all users. |
441 | * |
442 | * @param int $scormid id of scorm |
443 | * @param int $userid optional user id, 0 means all users |
444 | * @return array array of grades, false if none |
445 | */ |
446 | function scorm_get_user_grades($scorm, $userid=0) { |
bf347041 |
447 | global $CFG, $DB; |
531fa830 |
448 | require_once('locallib.php'); |
449 | |
450 | $grades = array(); |
451 | if (empty($userid)) { |
bf347041 |
452 | if ($scousers = $DB->get_records_select('scorm_scoes_track', "scormid=? GROUP BY userid", array($scorm->id), "", "userid,null")) { |
531fa830 |
453 | foreach ($scousers as $scouser) { |
454 | $grades[$scouser->userid] = new object(); |
455 | $grades[$scouser->userid]->id = $scouser->userid; |
456 | $grades[$scouser->userid]->userid = $scouser->userid; |
457 | $grades[$scouser->userid]->rawgrade = scorm_grade_user($scorm, $scouser->userid); |
458 | } |
459 | } else { |
460 | return false; |
461 | } |
e4aa175a |
462 | |
531fa830 |
463 | } else { |
bf347041 |
464 | if (!$DB->get_records_select('scorm_scoes_track', "scormid=? AND userid=? GROUP BY userid", array($scorm->id, $userid), "", "userid,null")) { |
531fa830 |
465 | return false; //no attempt yet |
466 | } |
467 | $grades[$userid] = new object(); |
468 | $grades[$userid]->id = $userid; |
469 | $grades[$userid]->userid = $userid; |
470 | $grades[$userid]->rawgrade = scorm_grade_user($scorm, $userid); |
e4aa175a |
471 | } |
e4aa175a |
472 | |
531fa830 |
473 | return $grades; |
474 | } |
475 | |
476 | /** |
477 | * Update grades in central gradebook |
478 | * |
775f811a |
479 | * @param object $scorm |
531fa830 |
480 | * @param int $userid specific user only, 0 mean all |
481 | */ |
775f811a |
482 | function scorm_update_grades($scorm, $userid=0, $nullifnone=true) { |
bf347041 |
483 | global $CFG, $DB; |
775f811a |
484 | require_once($CFG->libdir.'/gradelib.php'); |
531fa830 |
485 | |
775f811a |
486 | if ($grades = scorm_get_user_grades($scorm, $userid)) { |
487 | scorm_grade_item_update($scorm, $grades); |
531fa830 |
488 | |
775f811a |
489 | } else if ($userid and $nullifnone) { |
490 | $grade = new object(); |
491 | $grade->userid = $userid; |
492 | $grade->rawgrade = NULL; |
493 | scorm_grade_item_update($scorm, $grade); |
531fa830 |
494 | |
e4aa175a |
495 | } else { |
775f811a |
496 | scorm_grade_item_update($scorm); |
497 | } |
498 | } |
499 | |
500 | /** |
501 | * Update all grades in gradebook. |
502 | */ |
503 | function scorm_upgrade_grades() { |
504 | global $DB; |
505 | |
506 | $sql = "SELECT COUNT('x') |
507 | FROM {scorm} s, {course_modules} cm, {modules} m |
508 | WHERE m.name='scorm' AND m.id=cm.module AND cm.instance=s.id"; |
509 | $count = $DB->count_records_sql($sql); |
510 | |
511 | $sql = "SELECT s.*, cm.idnumber AS cmidnumber, s.course AS courseid |
512 | FROM {scorm} s, {course_modules} cm, {modules} m |
513 | WHERE m.name='scorm' AND m.id=cm.module AND cm.instance=s.id"; |
514 | if ($rs = $DB->get_recordset_sql($sql)) { |
775f811a |
515 | $pbar = new progress_bar('scormupgradegrades', 500, true); |
516 | $i=0; |
517 | foreach ($rs as $scorm) { |
518 | $i++; |
519 | upgrade_set_timeout(60*5); // set up timeout, may also abort execution |
520 | scorm_update_grades($scorm, 0, false); |
521 | $pbar->update($i, $count, "Updating Scorm grades ($i/$count)."); |
531fa830 |
522 | } |
775f811a |
523 | $rs->close(); |
e4aa175a |
524 | } |
531fa830 |
525 | } |
e4aa175a |
526 | |
531fa830 |
527 | /** |
528 | * Update/create grade item for given scorm |
529 | * |
530 | * @param object $scorm object with extra cmidnumber |
0b5a80a1 |
531 | * @param mixed optional array/object of grade(s); 'reset' means reset grades in gradebook |
531fa830 |
532 | * @return object grade_item |
533 | */ |
0b5a80a1 |
534 | function scorm_grade_item_update($scorm, $grades=NULL) { |
bf347041 |
535 | global $CFG, $DB; |
531fa830 |
536 | if (!function_exists('grade_update')) { //workaround for buggy PHP versions |
537 | require_once($CFG->libdir.'/gradelib.php'); |
538 | } |
539 | |
7ef16bf9 |
540 | $params = array('itemname'=>$scorm->name); |
541 | if (isset($scorm->cmidnumber)) { |
542 | $params['idnumber'] = $scorm->cmidnumber; |
543 | } |
9528568b |
544 | |
531fa830 |
545 | if (($scorm->grademethod % 10) == 0) { // GRADESCOES |
5b4b959b |
546 | if ($maxgrade = $DB->count_records_select('scorm_scoes', 'scorm = ? AND launch <> ?', array($scorm->id, $DB->sql_empty()))) { |
531fa830 |
547 | $params['gradetype'] = GRADE_TYPE_VALUE; |
548 | $params['grademax'] = $maxgrade; |
549 | $params['grademin'] = 0; |
550 | } else { |
551 | $params['gradetype'] = GRADE_TYPE_NONE; |
e4aa175a |
552 | } |
531fa830 |
553 | } else { |
554 | $params['gradetype'] = GRADE_TYPE_VALUE; |
555 | $params['grademax'] = $scorm->maxgrade; |
556 | $params['grademin'] = 0; |
e4aa175a |
557 | } |
531fa830 |
558 | |
0b5a80a1 |
559 | if ($grades === 'reset') { |
560 | $params['reset'] = true; |
561 | $grades = NULL; |
562 | } |
563 | |
564 | return grade_update('mod/scorm', $scorm->course, 'mod', 'scorm', $scorm->id, 0, $grades, $params); |
531fa830 |
565 | } |
566 | |
567 | /** |
568 | * Delete grade item for given scorm |
569 | * |
570 | * @param object $scorm object |
571 | * @return object grade_item |
572 | */ |
573 | function scorm_grade_item_delete($scorm) { |
574 | global $CFG; |
575 | require_once($CFG->libdir.'/gradelib.php'); |
576 | |
577 | return grade_update('mod/scorm', $scorm->course, 'mod', 'scorm', $scorm->id, 0, NULL, array('deleted'=>1)); |
e4aa175a |
578 | } |
579 | |
580 | function scorm_get_view_actions() { |
581 | return array('pre-view','view','view all','report'); |
582 | } |
583 | |
584 | function scorm_get_post_actions() { |
585 | return array(); |
586 | } |
587 | |
e4aa175a |
588 | function scorm_option2text($scorm) { |
1adc77e6 |
589 | $scorm_popoup_options = scorm_get_popup_options_array(); |
590 | |
e4aa175a |
591 | if (isset($scorm->popup)) { |
76ea4fb4 |
592 | if ($scorm->popup == 1) { |
e4aa175a |
593 | $optionlist = array(); |
1adc77e6 |
594 | foreach ($scorm_popoup_options as $name => $option) { |
e4aa175a |
595 | if (isset($scorm->$name)) { |
596 | $optionlist[] = $name.'='.$scorm->$name; |
597 | } else { |
598 | $optionlist[] = $name.'=0'; |
599 | } |
9528568b |
600 | } |
e4aa175a |
601 | $scorm->options = implode(',', $optionlist); |
602 | } else { |
603 | $scorm->options = ''; |
9528568b |
604 | } |
e4aa175a |
605 | } else { |
606 | $scorm->popup = 0; |
607 | $scorm->options = ''; |
608 | } |
609 | return $scorm; |
610 | } |
611 | |
0b5a80a1 |
612 | /** |
613 | * Implementation of the function for printing the form elements that control |
614 | * whether the course reset functionality affects the scorm. |
615 | * @param $mform form passed by reference |
616 | */ |
617 | function scorm_reset_course_form_definition(&$mform) { |
618 | $mform->addElement('header', 'scormheader', get_string('modulenameplural', 'scorm')); |
619 | $mform->addElement('advcheckbox', 'reset_scorm', get_string('deleteallattempts','scorm')); |
620 | } |
621 | |
622 | /** |
623 | * Course reset form defaults. |
624 | */ |
625 | function scorm_reset_course_form_defaults($course) { |
626 | return array('reset_scorm'=>1); |
627 | } |
628 | |
629 | /** |
630 | * Removes all grades from gradebook |
631 | * @param int $courseid |
632 | * @param string optional type |
633 | */ |
634 | function scorm_reset_gradebook($courseid, $type='') { |
bf347041 |
635 | global $CFG, $DB; |
0b5a80a1 |
636 | |
637 | $sql = "SELECT s.*, cm.idnumber as cmidnumber, s.course as courseid |
bf347041 |
638 | FROM {scorm} s, {course_modules} cm, {modules} m |
639 | WHERE m.name='scorm' AND m.id=cm.module AND cm.instance=s.id AND s.course=?"; |
0b5a80a1 |
640 | |
bf347041 |
641 | if ($scorms = $DB->get_records_sql($sql, array($courseid))) { |
0b5a80a1 |
642 | foreach ($scorms as $scorm) { |
643 | scorm_grade_item_update($scorm, 'reset'); |
644 | } |
645 | } |
646 | } |
647 | |
648 | /** |
649 | * Actual implementation of the rest coures functionality, delete all the |
650 | * scorm attempts for course $data->courseid. |
651 | * @param $data the data submitted from the reset course. |
652 | * @return array status array |
653 | */ |
654 | function scorm_reset_userdata($data) { |
bf347041 |
655 | global $CFG, $DB; |
0b5a80a1 |
656 | |
657 | $componentstr = get_string('modulenameplural', 'scorm'); |
658 | $status = array(); |
659 | |
660 | if (!empty($data->reset_scorm)) { |
661 | $scormssql = "SELECT s.id |
bf347041 |
662 | FROM {scorm} s |
663 | WHERE s.course=?"; |
0b5a80a1 |
664 | |
bf347041 |
665 | $DB->delete_records_select('scorm_scoes_track', "scormid IN ($scormssql)", array($data->courseid)); |
0b5a80a1 |
666 | |
667 | // remove all grades from gradebook |
668 | if (empty($data->reset_gradebook_grades)) { |
669 | scorm_reset_gradebook($data->courseid); |
670 | } |
671 | |
672 | $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallattempts', 'scorm'), 'error'=>false); |
673 | } |
674 | |
675 | // no dates to shift here |
676 | |
677 | return $status; |
678 | } |
679 | |
f432bebf |
680 | /** |
681 | * Returns all other caps used in module |
682 | */ |
683 | function scorm_get_extra_capabilities() { |
684 | return array('moodle/site:accessallgroups'); |
685 | } |
686 | |
9528568b |
687 | /** |
688 | * Lists all file areas current user may browse |
689 | */ |
690 | function scorm_get_file_areas($course, $cm, $context) { |
691 | $areas = array(); |
692 | if (has_capability('moodle/course:managefiles', $context)) { |
693 | $areas['scorm_intro'] = get_string('areaintro', 'scorm'); |
694 | $areas['scorm_content'] = get_string('areacontent', 'scorm'); |
695 | $areas['scorm_package'] = get_string('areapackage', 'scorm'); |
696 | } |
697 | return $areas; |
698 | } |
699 | |
700 | /** |
701 | * File browsing support |
702 | */ |
703 | function scorm_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) { |
704 | global $CFG; |
705 | |
706 | if (!has_capability('moodle/course:managefiles', $context)) { |
707 | return null; |
708 | } |
709 | |
710 | // no writing for now! |
711 | |
712 | $fs = get_file_storage(); |
713 | |
714 | if ($filearea === 'scorm_content') { |
715 | |
716 | $filepath = is_null($filepath) ? '/' : $filepath; |
717 | $filename = is_null($filename) ? '.' : $filename; |
718 | |
719 | $urlbase = $CFG->wwwroot.'/pluginfile.php'; |
720 | if (!$storedfile = $fs->get_file($context->id, $filearea, 0, $filepath, $filename)) { |
721 | if ($filepath === '/' and $filename === '.') { |
722 | $storedfile = new virtual_root_file($context->id, $filearea, 0); |
723 | } else { |
724 | // not found |
725 | return null; |
726 | } |
727 | } |
728 | class scorm_package_file_info extends file_info_stored { |
729 | public function get_parent() { |
730 | if ($this->lf->get_filepath() === '/' and $this->lf->get_filename() === '.') { |
731 | return $this->browser->get_file_info($this->context); |
732 | } |
733 | return parent::get_parent(); |
734 | } |
735 | public function get_visible_name() { |
736 | if ($this->lf->get_filepath() === '/' and $this->lf->get_filename() === '.') { |
3156b8ca |
737 | return $this->topvisiblename; |
9528568b |
738 | } |
739 | return parent::get_visible_name(); |
740 | } |
741 | } |
8546def3 |
742 | return new scorm_package_file_info($browser, $context, $storedfile, $urlbase, $areas[$filearea], true, true, false, false); |
9528568b |
743 | |
744 | } else if ($filearea === 'scorm_package') { |
745 | $filepath = is_null($filepath) ? '/' : $filepath; |
746 | $filename = is_null($filename) ? '.' : $filename; |
747 | |
748 | $urlbase = $CFG->wwwroot.'/pluginfile.php'; |
749 | if (!$storedfile = $fs->get_file($context->id, $filearea, 0, $filepath, $filename)) { |
750 | if ($filepath === '/' and $filename === '.') { |
751 | $storedfile = new virtual_root_file($context->id, $filearea, 0); |
752 | } else { |
753 | // not found |
754 | return null; |
755 | } |
756 | } |
757 | return new file_info_stored($browser, $context, $storedfile, $urlbase, $areas[$filearea], false, true, false); |
758 | } |
759 | |
760 | // scorm_intro handled in file_browser |
761 | |
762 | return false; |
763 | } |
764 | |
765 | /** |
766 | * Serves scorm content, introduction images and packages. Implements needed access control ;-) |
767 | */ |
768 | function scorm_pluginfile($course, $cminfo, $context, $filearea, $args) { |
769 | global $CFG; |
770 | |
771 | if (!$cminfo->uservisible) { |
772 | return false; // probably hidden |
773 | } |
774 | |
775 | $lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400; |
776 | |
777 | if ($filearea === 'scorm_intro') { |
778 | // all users may access it |
779 | $relativepath = '/'.implode('/', $args); |
780 | $fullpath = $context->id.'scorm_intro0'.$relativepath; |
781 | |
782 | $fs = get_file_storage(); |
783 | if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { |
784 | return false; |
785 | } |
786 | |
787 | } else if ($filearea === 'scorm_content') { |
788 | $revision = (int)array_shift($args); // prevents caching problems - ignored here |
789 | $relativepath = '/'.implode('/', $args); |
790 | $fullpath = $context->id.'scorm_content0'.$relativepath; |
791 | // TODO: add any other access restrictions here if needed! |
792 | |
793 | } else if ($filearea === 'scorm_package') { |
794 | if (!has_capability('moodle/course:manageactivities', $context)) { |
795 | return false; |
796 | } |
797 | $relativepath = '/'.implode('/', $args); |
798 | $fullpath = $context->id.'scorm_package0'.$relativepath; |
799 | $lifetime = 0; // no caching here |
800 | |
801 | } else { |
802 | return false; |
803 | } |
804 | |
805 | $fs = get_file_storage(); |
806 | if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { |
807 | return false; |
808 | } |
809 | |
810 | // finally send the file |
811 | send_stored_file($file, $lifetime, 0, false); |
812 | } |
813 | |
5c1ac70c |
814 | ?> |