Commit | Line | Data |
---|---|---|
27806552 YB |
1 | <?php |
2 | // This file is part of Moodle - http://moodle.org/ | |
3 | // | |
4 | // Moodle is free software: you can redistribute it and/or modify | |
5 | // it under the terms of the GNU General Public License as published by | |
6 | // the Free Software Foundation, either version 3 of the License, or | |
7 | // (at your option) any later version. | |
8 | // | |
9 | // Moodle is distributed in the hope that it will be useful, | |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | // GNU General Public License for more details. | |
13 | // | |
14 | // You should have received a copy of the GNU General Public License | |
15 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
16 | ||
17 | /** | |
18 | * Contains classes, functions and constants used in badges. | |
19 | * | |
20 | * @package core | |
21 | * @subpackage badges | |
22 | * @copyright 2012 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/} | |
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
24 | * @author Yuliya Bozhko <yuliya.bozhko@totaralms.com> | |
25 | */ | |
26 | ||
27 | defined('MOODLE_INTERNAL') || die(); | |
28 | ||
29 | /* Include required award criteria library. */ | |
30 | require_once($CFG->dirroot . '/badges/criteria/award_criteria.php'); | |
31 | ||
32 | /* | |
33 | * Number of records per page. | |
34 | */ | |
35 | define('BADGE_PERPAGE', 50); | |
36 | ||
37 | /* | |
38 | * Badge award criteria aggregation method. | |
39 | */ | |
40 | define('BADGE_CRITERIA_AGGREGATION_ALL', 1); | |
41 | ||
42 | /* | |
43 | * Badge award criteria aggregation method. | |
44 | */ | |
45 | define('BADGE_CRITERIA_AGGREGATION_ANY', 2); | |
46 | ||
47 | /* | |
48 | * Inactive badge means that this badge cannot be earned and has not been awarded | |
49 | * yet. Its award criteria can be changed. | |
50 | */ | |
51 | define('BADGE_STATUS_INACTIVE', 0); | |
52 | ||
53 | /* | |
54 | * Active badge means that this badge can we earned, but it has not been awarded | |
55 | * yet. Can be deactivated for the purpose of changing its criteria. | |
56 | */ | |
57 | define('BADGE_STATUS_ACTIVE', 1); | |
58 | ||
59 | /* | |
60 | * Inactive badge can no longer be earned, but it has been awarded in the past and | |
61 | * therefore its criteria cannot be changed. | |
62 | */ | |
63 | define('BADGE_STATUS_INACTIVE_LOCKED', 2); | |
64 | ||
65 | /* | |
66 | * Active badge means that it can be earned and has already been awarded to users. | |
67 | * Its criteria cannot be changed any more. | |
68 | */ | |
69 | define('BADGE_STATUS_ACTIVE_LOCKED', 3); | |
70 | ||
71 | /* | |
72 | * Archived badge is considered deleted and can no longer be earned and is not | |
73 | * displayed in the list of all badges. | |
74 | */ | |
75 | define('BADGE_STATUS_ARCHIVED', 4); | |
76 | ||
77 | /* | |
78 | * Badge type for site badges. | |
79 | */ | |
80 | define('BADGE_TYPE_SITE', 1); | |
81 | ||
82 | /* | |
83 | * Badge type for course badges. | |
84 | */ | |
85 | define('BADGE_TYPE_COURSE', 2); | |
86 | ||
87 | /* | |
88 | * Badge messaging schedule options. | |
89 | */ | |
90 | define('BADGE_MESSAGE_NEVER', 0); | |
91 | define('BADGE_MESSAGE_ALWAYS', 1); | |
92 | define('BADGE_MESSAGE_DAILY', 2); | |
93 | define('BADGE_MESSAGE_WEEKLY', 3); | |
94 | define('BADGE_MESSAGE_MONTHLY', 4); | |
95 | ||
96 | /** | |
97 | * Class that represents badge. | |
98 | * | |
99 | */ | |
100 | class badge { | |
101 | /** @var int Badge id */ | |
102 | public $id; | |
103 | ||
104 | /** Values from the table 'badge' */ | |
105 | public $name; | |
106 | public $description; | |
107 | public $timecreated; | |
108 | public $timemodified; | |
109 | public $usercreated; | |
110 | public $usermodified; | |
27806552 YB |
111 | public $issuername; |
112 | public $issuerurl; | |
113 | public $issuercontact; | |
114 | public $expiredate; | |
115 | public $expireperiod; | |
116 | public $type; | |
117 | public $courseid; | |
118 | public $message; | |
119 | public $messagesubject; | |
120 | public $attachment; | |
121 | public $notification; | |
122 | public $status = 0; | |
123 | public $nextcron; | |
124 | ||
125 | /** @var array Badge criteria */ | |
126 | public $criteria = array(); | |
127 | ||
128 | /** | |
129 | * Constructs with badge details. | |
130 | * | |
131 | * @param int $badgeid badge ID. | |
132 | */ | |
133 | public function __construct($badgeid) { | |
134 | global $DB; | |
135 | $this->id = $badgeid; | |
136 | ||
137 | $data = $DB->get_record('badge', array('id' => $badgeid)); | |
138 | ||
139 | if (empty($data)) { | |
140 | print_error('error:nosuchbadge', 'badges', $badgeid); | |
141 | } | |
142 | ||
143 | foreach ((array)$data as $field => $value) { | |
144 | if (property_exists($this, $field)) { | |
145 | $this->{$field} = $value; | |
146 | } | |
147 | } | |
148 | ||
149 | $this->criteria = self::get_criteria(); | |
150 | } | |
151 | ||
152 | /** | |
153 | * Use to get context instance of a badge. | |
154 | * @return context instance. | |
155 | */ | |
156 | public function get_context() { | |
157 | if ($this->type == BADGE_TYPE_SITE) { | |
158 | return context_system::instance(); | |
159 | } else if ($this->type == BADGE_TYPE_COURSE) { | |
160 | return context_course::instance($this->courseid); | |
161 | } else { | |
162 | debugging('Something is wrong...'); | |
163 | } | |
164 | } | |
165 | ||
166 | /** | |
167 | * Return array of aggregation methods | |
168 | * @return array | |
169 | */ | |
170 | public static function get_aggregation_methods() { | |
171 | return array( | |
172 | BADGE_CRITERIA_AGGREGATION_ALL => get_string('all', 'badges'), | |
173 | BADGE_CRITERIA_AGGREGATION_ANY => get_string('any', 'badges'), | |
174 | ); | |
175 | } | |
176 | ||
177 | /** | |
178 | * Return array of accepted criteria types for this badge | |
179 | * @return array | |
180 | */ | |
181 | public function get_accepted_criteria() { | |
182 | $criteriatypes = array(); | |
183 | ||
184 | if ($this->type == BADGE_TYPE_COURSE) { | |
185 | $criteriatypes = array( | |
186 | BADGE_CRITERIA_TYPE_OVERALL, | |
187 | BADGE_CRITERIA_TYPE_MANUAL, | |
188 | BADGE_CRITERIA_TYPE_COURSE, | |
189 | BADGE_CRITERIA_TYPE_ACTIVITY | |
190 | ); | |
191 | } else if ($this->type == BADGE_TYPE_SITE) { | |
192 | $criteriatypes = array( | |
193 | BADGE_CRITERIA_TYPE_OVERALL, | |
194 | BADGE_CRITERIA_TYPE_MANUAL, | |
195 | BADGE_CRITERIA_TYPE_COURSESET, | |
196 | BADGE_CRITERIA_TYPE_PROFILE, | |
197 | ); | |
198 | } | |
199 | ||
200 | return $criteriatypes; | |
201 | } | |
202 | ||
203 | /** | |
204 | * Save/update badge information in 'badge' table only. | |
205 | * Cannot be used for updating awards and criteria settings. | |
206 | * | |
207 | * @return bool Returns true on success. | |
208 | */ | |
209 | public function save() { | |
210 | global $DB; | |
211 | ||
212 | $fordb = new stdClass(); | |
213 | foreach (get_object_vars($this) as $k => $v) { | |
214 | $fordb->{$k} = $v; | |
215 | } | |
216 | unset($fordb->criteria); | |
217 | ||
218 | $fordb->timemodified = time(); | |
219 | if ($DB->update_record_raw('badge', $fordb)) { | |
220 | return true; | |
221 | } else { | |
222 | throw new moodle_exception('error:save', 'badges'); | |
223 | return false; | |
224 | } | |
225 | } | |
226 | ||
227 | /** | |
228 | * Creates and saves a clone of badge with all its properties. | |
229 | * Clone is not active by default and has 'Copy of' attached to its name. | |
230 | * | |
231 | * @return int ID of new badge. | |
232 | */ | |
233 | public function make_clone() { | |
234 | global $DB, $USER; | |
235 | ||
236 | $fordb = new stdClass(); | |
237 | foreach (get_object_vars($this) as $k => $v) { | |
238 | $fordb->{$k} = $v; | |
239 | } | |
240 | ||
241 | $fordb->name = get_string('copyof', 'badges', $this->name); | |
242 | $fordb->status = BADGE_STATUS_INACTIVE; | |
27806552 YB |
243 | $fordb->usercreated = $USER->id; |
244 | $fordb->usermodified = $USER->id; | |
245 | $fordb->timecreated = time(); | |
246 | $fordb->timemodified = time(); | |
247 | unset($fordb->id); | |
248 | ||
249 | if ($fordb->notification > 1) { | |
250 | $fordb->nextcron = badges_calculate_message_schedule($fordb->notification); | |
251 | } | |
252 | ||
253 | $criteria = $fordb->criteria; | |
254 | unset($fordb->criteria); | |
255 | ||
256 | if ($new = $DB->insert_record('badge', $fordb, true)) { | |
257 | $newbadge = new badge($new); | |
258 | ||
259 | // Copy badge image. | |
260 | $fs = get_file_storage(); | |
261 | if ($file = $fs->get_file($this->get_context()->id, 'badges', 'badgeimage', $this->id, '/', 'f1.png')) { | |
262 | if ($imagefile = $file->copy_content_to_temp()) { | |
263 | badges_process_badge_image($newbadge, $imagefile); | |
264 | } | |
265 | } | |
266 | ||
267 | // Copy badge criteria. | |
268 | foreach ($this->criteria as $crit) { | |
269 | $crit->make_clone($new); | |
270 | } | |
271 | ||
272 | return $new; | |
273 | } else { | |
274 | throw new moodle_exception('error:clone', 'badges'); | |
275 | return false; | |
276 | } | |
277 | } | |
278 | ||
279 | /** | |
280 | * Checks if badges is active. | |
281 | * Used in badge award. | |
282 | * | |
283 | * @return bool A status indicating badge is active | |
284 | */ | |
285 | public function is_active() { | |
286 | if (($this->status == BADGE_STATUS_ACTIVE) || | |
287 | ($this->status == BADGE_STATUS_ACTIVE_LOCKED)) { | |
288 | return true; | |
289 | } | |
290 | return false; | |
291 | } | |
292 | ||
293 | /** | |
294 | * Use to get the name of badge status. | |
295 | * | |
296 | */ | |
297 | public function get_status_name() { | |
298 | return get_string('badgestatus_' . $this->status, 'badges'); | |
299 | } | |
300 | ||
301 | /** | |
302 | * Use to set badge status. | |
303 | * Only active badges can be earned/awarded/issued. | |
304 | * | |
305 | * @param int $status Status from BADGE_STATUS constants | |
306 | */ | |
307 | public function set_status($status = 0) { | |
308 | $this->status = $status; | |
309 | $this->save(); | |
310 | } | |
311 | ||
312 | /** | |
313 | * Checks if badges is locked. | |
314 | * Used in badge award and editing. | |
315 | * | |
316 | * @return bool A status indicating badge is locked | |
317 | */ | |
318 | public function is_locked() { | |
319 | if (($this->status == BADGE_STATUS_ACTIVE_LOCKED) || | |
320 | ($this->status == BADGE_STATUS_INACTIVE_LOCKED)) { | |
321 | return true; | |
322 | } | |
323 | return false; | |
324 | } | |
325 | ||
326 | /** | |
327 | * Checks if badge has been awarded to users. | |
328 | * Used in badge editing. | |
329 | * | |
330 | * @return bool A status indicating badge has been awarded at least once | |
331 | */ | |
332 | public function has_awards() { | |
333 | global $DB; | |
334 | if ($DB->record_exists('badge_issued', array('badgeid' => $this->id))) { | |
335 | return true; | |
336 | } | |
337 | return false; | |
338 | } | |
339 | ||
340 | /** | |
341 | * Gets list of users who have earned an instance of this badge. | |
342 | * | |
343 | * @return array An array of objects with information about badge awards. | |
344 | */ | |
345 | public function get_awards() { | |
346 | global $DB; | |
347 | ||
348 | $awards = $DB->get_records_sql( | |
349 | 'SELECT b.userid, b.dateissued, b.uniquehash, u.firstname, u.lastname | |
350 | FROM {badge_issued} b INNER JOIN {user} u | |
351 | ON b.userid = u.id | |
352 | WHERE b.badgeid = :badgeid', array('badgeid' => $this->id)); | |
353 | ||
354 | return $awards; | |
355 | } | |
356 | ||
357 | /** | |
358 | * Indicates whether badge has already been issued to a user. | |
359 | * | |
360 | */ | |
361 | public function is_issued($userid) { | |
362 | global $DB; | |
363 | return $DB->record_exists('badge_issued', array('badgeid' => $this->id, 'userid' => $userid)); | |
364 | } | |
365 | ||
366 | /** | |
367 | * Issue a badge to user. | |
368 | * | |
369 | * @param int $userid User who earned the badge | |
370 | * @param bool $nobake Not baking actual badges (for testing purposes) | |
371 | */ | |
372 | public function issue($userid, $nobake = false) { | |
373 | global $DB, $CFG; | |
374 | ||
375 | $now = time(); | |
376 | $issued = new stdClass(); | |
377 | $issued->badgeid = $this->id; | |
378 | $issued->userid = $userid; | |
379 | $issued->uniquehash = sha1(rand() . $userid . $this->id . $now); | |
380 | $issued->dateissued = $now; | |
381 | ||
382 | if ($this->can_expire()) { | |
383 | $issued->dateexpire = $this->calculate_expiry($now); | |
384 | } else { | |
385 | $issued->dateexpire = null; | |
386 | } | |
387 | ||
e2805314 YB |
388 | // Take into account user badges privacy settings. |
389 | // If none set, badges default visibility is set to public. | |
390 | $issued->visible = get_user_preferences('badgeprivacysetting', 1, $userid); | |
27806552 YB |
391 | |
392 | $result = $DB->insert_record('badge_issued', $issued, true); | |
393 | ||
394 | if ($result) { | |
395 | // Lock the badge, so that its criteria could not be changed any more. | |
396 | if ($this->status == BADGE_STATUS_ACTIVE) { | |
397 | $this->set_status(BADGE_STATUS_ACTIVE_LOCKED); | |
398 | } | |
399 | ||
400 | // Update details in criteria_met table. | |
401 | $compl = $this->get_criteria_completions($userid); | |
402 | foreach ($compl as $c) { | |
403 | $obj = new stdClass(); | |
404 | $obj->id = $c->id; | |
405 | $obj->issuedid = $result; | |
406 | $DB->update_record('badge_criteria_met', $obj, true); | |
407 | } | |
408 | ||
409 | if (!$nobake) { | |
410 | // Bake a badge image. | |
411 | $pathhash = badges_bake($issued->uniquehash, $this->id, $userid, true); | |
412 | ||
413 | // Notify recipients and badge creators. | |
f007e899 | 414 | badges_notify_badge_award($this, $userid, $issued->uniquehash, $pathhash); |
27806552 YB |
415 | } |
416 | } | |
417 | } | |
418 | ||
419 | /** | |
420 | * Reviews all badge criteria and checks if badge can be instantly awarded. | |
421 | * | |
422 | * @return int Number of awards | |
423 | */ | |
424 | public function review_all_criteria() { | |
425 | global $DB, $CFG; | |
426 | $awards = 0; | |
427 | ||
428 | // Raise timelimit as this could take a while for big web sites. | |
3ef7279f | 429 | core_php_time_limit::raise(); |
27806552 YB |
430 | raise_memory_limit(MEMORY_HUGE); |
431 | ||
432 | // For site level badges, get all active site users who can earn this badge and haven't got it yet. | |
433 | if ($this->type == BADGE_TYPE_SITE) { | |
434 | $sql = 'SELECT DISTINCT u.id, bi.badgeid | |
435 | FROM {user} u | |
436 | LEFT JOIN {badge_issued} bi | |
437 | ON u.id = bi.userid AND bi.badgeid = :badgeid | |
438 | WHERE bi.badgeid IS NULL AND u.id != :guestid AND u.deleted = 0'; | |
439 | $toearn = $DB->get_fieldset_sql($sql, array('badgeid' => $this->id, 'guestid' => $CFG->siteguest)); | |
440 | } else { | |
441 | // For course level badges, get users who can earn this badge in the course. | |
442 | // These are all enrolled users with capability moodle/badges:earnbadge. | |
443 | $earned = $DB->get_fieldset_select('badge_issued', 'userid AS id', 'badgeid = :badgeid', array('badgeid' => $this->id)); | |
444 | $users = get_enrolled_users($this->get_context(), 'moodle/badges:earnbadge', 0, 'u.id'); | |
445 | $toearn = array_diff(array_keys($users), $earned); | |
446 | } | |
447 | ||
448 | foreach ($toearn as $uid) { | |
449 | $toreview = false; | |
450 | foreach ($this->criteria as $crit) { | |
451 | if ($crit->criteriatype != BADGE_CRITERIA_TYPE_OVERALL) { | |
452 | if ($crit->review($uid)) { | |
453 | $crit->mark_complete($uid); | |
454 | if ($this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->method == BADGE_CRITERIA_AGGREGATION_ANY) { | |
455 | $this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($uid); | |
456 | $this->issue($uid); | |
457 | $awards++; | |
458 | break; | |
459 | } else { | |
460 | $toreview = true; | |
461 | continue; | |
462 | } | |
463 | } else { | |
464 | if ($this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->method == BADGE_CRITERIA_AGGREGATION_ANY) { | |
465 | continue; | |
466 | } else { | |
467 | break; | |
468 | } | |
469 | } | |
470 | } | |
471 | } | |
472 | // Review overall if it is required. | |
473 | if ($toreview && $this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($uid)) { | |
474 | $this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($uid); | |
475 | $this->issue($uid); | |
476 | $awards++; | |
477 | } | |
478 | } | |
479 | ||
480 | return $awards; | |
481 | } | |
482 | ||
483 | /** | |
484 | * Gets an array of completed criteria from 'badge_criteria_met' table. | |
485 | * | |
486 | * @param int $userid Completions for a user | |
487 | * @return array Records of criteria completions | |
488 | */ | |
489 | public function get_criteria_completions($userid) { | |
490 | global $DB; | |
491 | $completions = array(); | |
492 | $sql = "SELECT bcm.id, bcm.critid | |
493 | FROM {badge_criteria_met} bcm | |
494 | INNER JOIN {badge_criteria} bc ON bcm.critid = bc.id | |
495 | WHERE bc.badgeid = :badgeid AND bcm.userid = :userid "; | |
496 | $completions = $DB->get_records_sql($sql, array('badgeid' => $this->id, 'userid' => $userid)); | |
497 | ||
498 | return $completions; | |
499 | } | |
500 | ||
501 | /** | |
502 | * Checks if badges has award criteria set up. | |
503 | * | |
504 | * @return bool A status indicating badge has at least one criterion | |
505 | */ | |
506 | public function has_criteria() { | |
507 | if (count($this->criteria) > 0) { | |
508 | return true; | |
509 | } | |
510 | return false; | |
511 | } | |
512 | ||
513 | /** | |
514 | * Returns badge award criteria | |
515 | * | |
516 | * @return array An array of badge criteria | |
517 | */ | |
518 | public function get_criteria() { | |
519 | global $DB; | |
520 | $criteria = array(); | |
521 | ||
522 | if ($records = (array)$DB->get_records('badge_criteria', array('badgeid' => $this->id))) { | |
523 | foreach ($records as $record) { | |
524 | $criteria[$record->criteriatype] = award_criteria::build((array)$record); | |
525 | } | |
526 | } | |
527 | ||
528 | return $criteria; | |
529 | } | |
530 | ||
531 | /** | |
532 | * Get aggregation method for badge criteria | |
533 | * | |
534 | * @param int $criteriatype If none supplied, get overall aggregation method (optional) | |
535 | * @return int One of BADGE_CRITERIA_AGGREGATION_ALL or BADGE_CRITERIA_AGGREGATION_ANY | |
536 | */ | |
537 | public function get_aggregation_method($criteriatype = 0) { | |
538 | global $DB; | |
539 | $params = array('badgeid' => $this->id, 'criteriatype' => $criteriatype); | |
540 | $aggregation = $DB->get_field('badge_criteria', 'method', $params, IGNORE_MULTIPLE); | |
541 | ||
542 | if (!$aggregation) { | |
543 | return BADGE_CRITERIA_AGGREGATION_ALL; | |
544 | } | |
545 | ||
546 | return $aggregation; | |
547 | } | |
548 | ||
549 | /** | |
550 | * Checks if badge has expiry period or date set up. | |
551 | * | |
552 | * @return bool A status indicating badge can expire | |
553 | */ | |
554 | public function can_expire() { | |
555 | if ($this->expireperiod || $this->expiredate) { | |
556 | return true; | |
557 | } | |
558 | return false; | |
559 | } | |
560 | ||
561 | /** | |
562 | * Calculates badge expiry date based on either expirydate or expiryperiod. | |
563 | * | |
564 | * @param int $timestamp Time of badge issue | |
565 | * @return int A timestamp | |
566 | */ | |
567 | public function calculate_expiry($timestamp) { | |
568 | $expiry = null; | |
569 | ||
570 | if (isset($this->expiredate)) { | |
571 | $expiry = $this->expiredate; | |
572 | } else if (isset($this->expireperiod)) { | |
573 | $expiry = $timestamp + $this->expireperiod; | |
574 | } | |
575 | ||
576 | return $expiry; | |
577 | } | |
578 | ||
579 | /** | |
580 | * Checks if badge has manual award criteria set. | |
581 | * | |
582 | * @return bool A status indicating badge can be awarded manually | |
583 | */ | |
584 | public function has_manual_award_criteria() { | |
585 | foreach ($this->criteria as $criterion) { | |
586 | if ($criterion->criteriatype == BADGE_CRITERIA_TYPE_MANUAL) { | |
587 | return true; | |
588 | } | |
589 | } | |
590 | return false; | |
591 | } | |
592 | ||
593 | /** | |
594 | * Marks the badge as archived. | |
595 | * For reporting and historical purposed we cannot completely delete badges. | |
596 | * We will just change their status to BADGE_STATUS_ARCHIVED. | |
597 | */ | |
598 | public function delete() { | |
599 | $this->status = BADGE_STATUS_ARCHIVED; | |
600 | $this->save(); | |
601 | } | |
602 | } | |
603 | ||
604 | /** | |
605 | * Sends notifications to users about awarded badges. | |
606 | * | |
607 | * @param badge $badge Badge that was issued | |
608 | * @param int $userid Recipient ID | |
609 | * @param string $issued Unique hash of an issued badge | |
610 | * @param string $filepathhash File path hash of an issued badge for attachments | |
611 | */ | |
612 | function badges_notify_badge_award(badge $badge, $userid, $issued, $filepathhash) { | |
613 | global $CFG, $DB; | |
614 | ||
615 | $admin = get_admin(); | |
616 | $userfrom = new stdClass(); | |
617 | $userfrom->id = $admin->id; | |
618 | $userfrom->email = !empty($CFG->badges_defaultissuercontact) ? $CFG->badges_defaultissuercontact : $admin->email; | |
a327f25e AG |
619 | foreach (get_all_user_name_fields() as $addname) { |
620 | $userfrom->$addname = !empty($CFG->badges_defaultissuername) ? '' : $admin->$addname; | |
621 | } | |
27806552 | 622 | $userfrom->firstname = !empty($CFG->badges_defaultissuername) ? $CFG->badges_defaultissuername : $admin->firstname; |
27806552 YB |
623 | $userfrom->maildisplay = true; |
624 | ||
625 | $issuedlink = html_writer::link(new moodle_url('/badges/badge.php', array('hash' => $issued)), $badge->name); | |
626 | $userto = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST); | |
627 | ||
628 | $params = new stdClass(); | |
629 | $params->badgename = $badge->name; | |
630 | $params->username = fullname($userto); | |
631 | $params->badgelink = $issuedlink; | |
632 | $message = badge_message_from_template($badge->message, $params); | |
633 | $plaintext = format_text_email($message, FORMAT_HTML); | |
634 | ||
f5d17c14 YB |
635 | // Notify recipient. |
636 | $eventdata = new stdClass(); | |
637 | $eventdata->component = 'moodle'; | |
638 | $eventdata->name = 'badgerecipientnotice'; | |
639 | $eventdata->userfrom = $userfrom; | |
640 | $eventdata->userto = $userto; | |
641 | $eventdata->notification = 1; | |
642 | $eventdata->subject = $badge->messagesubject; | |
643 | $eventdata->fullmessage = $plaintext; | |
644 | $eventdata->fullmessageformat = FORMAT_PLAIN; | |
645 | $eventdata->fullmessagehtml = $message; | |
646 | $eventdata->smallmessage = $plaintext; | |
647 | ||
648 | // Attach badge image if possible. | |
649 | if (!empty($CFG->allowattachments) && $badge->attachment && is_string($filepathhash)) { | |
27806552 YB |
650 | $fs = get_file_storage(); |
651 | $file = $fs->get_file_by_hash($filepathhash); | |
f5d17c14 YB |
652 | $eventdata->attachment = $file; |
653 | $eventdata->attachname = str_replace(' ', '_', $badge->name) . ".png"; | |
654 | ||
655 | message_send($eventdata); | |
27806552 | 656 | } else { |
f5d17c14 | 657 | message_send($eventdata); |
27806552 YB |
658 | } |
659 | ||
660 | // Notify badge creator about the award if they receive notifications every time. | |
661 | if ($badge->notification == 1) { | |
f5d17c14 YB |
662 | $userfrom = core_user::get_noreply_user(); |
663 | $userfrom->maildisplay = true; | |
664 | ||
27806552 YB |
665 | $creator = $DB->get_record('user', array('id' => $badge->usercreated), '*', MUST_EXIST); |
666 | $a = new stdClass(); | |
667 | $a->user = fullname($userto); | |
668 | $a->link = $issuedlink; | |
669 | $creatormessage = get_string('creatorbody', 'badges', $a); | |
670 | $creatorsubject = get_string('creatorsubject', 'badges', $badge->name); | |
671 | ||
672 | $eventdata = new stdClass(); | |
673 | $eventdata->component = 'moodle'; | |
f5d17c14 | 674 | $eventdata->name = 'badgecreatornotice'; |
27806552 YB |
675 | $eventdata->userfrom = $userfrom; |
676 | $eventdata->userto = $creator; | |
677 | $eventdata->notification = 1; | |
678 | $eventdata->subject = $creatorsubject; | |
f5d17c14 | 679 | $eventdata->fullmessage = format_text_email($creatormessage, FORMAT_HTML); |
27806552 | 680 | $eventdata->fullmessageformat = FORMAT_PLAIN; |
f5d17c14 YB |
681 | $eventdata->fullmessagehtml = $creatormessage; |
682 | $eventdata->smallmessage = $creatorsubject; | |
27806552 YB |
683 | |
684 | message_send($eventdata); | |
685 | $DB->set_field('badge_issued', 'issuernotified', time(), array('badgeid' => $badge->id, 'userid' => $userid)); | |
686 | } | |
687 | } | |
688 | ||
689 | /** | |
690 | * Caclulates date for the next message digest to badge creators. | |
691 | * | |
692 | * @param in $schedule Type of message schedule BADGE_MESSAGE_DAILY|BADGE_MESSAGE_WEEKLY|BADGE_MESSAGE_MONTHLY. | |
693 | * @return int Timestamp for next cron | |
694 | */ | |
695 | function badges_calculate_message_schedule($schedule) { | |
696 | $nextcron = 0; | |
697 | ||
698 | switch ($schedule) { | |
699 | case BADGE_MESSAGE_DAILY: | |
700 | $nextcron = time() + 60 * 60 * 24; | |
701 | break; | |
702 | case BADGE_MESSAGE_WEEKLY: | |
703 | $nextcron = time() + 60 * 60 * 24 * 7; | |
704 | break; | |
705 | case BADGE_MESSAGE_MONTHLY: | |
706 | $nextcron = time() + 60 * 60 * 24 * 7 * 30; | |
707 | break; | |
708 | } | |
709 | ||
710 | return $nextcron; | |
711 | } | |
712 | ||
713 | /** | |
714 | * Replaces variables in a message template and returns text ready to be emailed to a user. | |
715 | * | |
716 | * @param string $message Message body. | |
717 | * @return string Message with replaced values | |
718 | */ | |
719 | function badge_message_from_template($message, $params) { | |
720 | $msg = $message; | |
721 | foreach ($params as $key => $value) { | |
722 | $msg = str_replace("%$key%", $value, $msg); | |
723 | } | |
724 | ||
725 | return $msg; | |
726 | } | |
727 | ||
728 | /** | |
729 | * Get all badges. | |
730 | * | |
731 | * @param int Type of badges to return | |
732 | * @param int Course ID for course badges | |
733 | * @param string $sort An SQL field to sort by | |
734 | * @param string $dir The sort direction ASC|DESC | |
735 | * @param int $page The page or records to return | |
736 | * @param int $perpage The number of records to return per page | |
737 | * @param int $user User specific search | |
738 | * @return array $badge Array of records matching criteria | |
739 | */ | |
740 | function badges_get_badges($type, $courseid = 0, $sort = '', $dir = '', $page = 0, $perpage = BADGE_PERPAGE, $user = 0) { | |
741 | global $DB; | |
742 | $records = array(); | |
743 | $params = array(); | |
744 | $where = "b.status != :deleted AND b.type = :type "; | |
745 | $params['deleted'] = BADGE_STATUS_ARCHIVED; | |
746 | ||
747 | $userfields = array('b.id, b.name, b.status'); | |
748 | $usersql = ""; | |
749 | if ($user != 0) { | |
750 | $userfields[] = 'bi.dateissued'; | |
751 | $userfields[] = 'bi.uniquehash'; | |
752 | $usersql = " LEFT JOIN {badge_issued} bi ON b.id = bi.badgeid AND bi.userid = :userid "; | |
753 | $params['userid'] = $user; | |
754 | $where .= " AND (b.status = 1 OR b.status = 3) "; | |
755 | } | |
756 | $fields = implode(', ', $userfields); | |
757 | ||
758 | if ($courseid != 0 ) { | |
759 | $where .= "AND b.courseid = :courseid "; | |
760 | $params['courseid'] = $courseid; | |
761 | } | |
762 | ||
763 | $sorting = (($sort != '' && $dir != '') ? 'ORDER BY ' . $sort . ' ' . $dir : ''); | |
764 | $params['type'] = $type; | |
765 | ||
766 | $sql = "SELECT $fields FROM {badge} b $usersql WHERE $where $sorting"; | |
767 | $records = $DB->get_records_sql($sql, $params, $page * $perpage, $perpage); | |
768 | ||
769 | $badges = array(); | |
770 | foreach ($records as $r) { | |
771 | $badge = new badge($r->id); | |
772 | $badges[$r->id] = $badge; | |
773 | if ($user != 0) { | |
774 | $badges[$r->id]->dateissued = $r->dateissued; | |
775 | $badges[$r->id]->uniquehash = $r->uniquehash; | |
776 | } else { | |
777 | $badges[$r->id]->awards = $DB->count_records('badge_issued', array('badgeid' => $badge->id)); | |
778 | $badges[$r->id]->statstring = $badge->get_status_name(); | |
779 | } | |
780 | } | |
781 | return $badges; | |
782 | } | |
783 | ||
784 | /** | |
785 | * Get badges for a specific user. | |
786 | * | |
787 | * @param int $userid User ID | |
788 | * @param int $courseid Badges earned by a user in a specific course | |
789 | * @param int $page The page or records to return | |
790 | * @param int $perpage The number of records to return per page | |
791 | * @param string $search A simple string to search for | |
792 | * @param bool $onlypublic Return only public badges | |
793 | * @return array of badges ordered by decreasing date of issue | |
794 | */ | |
795 | function badges_get_user_badges($userid, $courseid = 0, $page = 0, $perpage = 0, $search = '', $onlypublic = false) { | |
796 | global $DB; | |
797 | $badges = array(); | |
798 | ||
799 | $params[] = $userid; | |
800 | $sql = 'SELECT | |
801 | bi.uniquehash, | |
802 | bi.dateissued, | |
803 | bi.dateexpire, | |
804 | bi.id as issuedid, | |
805 | bi.visible, | |
806 | u.email, | |
807 | b.* | |
808 | FROM | |
809 | {badge} b, | |
810 | {badge_issued} bi, | |
811 | {user} u | |
812 | WHERE b.id = bi.badgeid | |
813 | AND u.id = bi.userid | |
814 | AND bi.userid = ?'; | |
815 | ||
816 | if (!empty($search)) { | |
817 | $sql .= ' AND (' . $DB->sql_like('b.name', '?', false) . ') '; | |
818 | $params[] = "%$search%"; | |
819 | } | |
820 | if ($onlypublic) { | |
821 | $sql .= ' AND (bi.visible = 1) '; | |
822 | } | |
823 | ||
824 | if ($courseid != 0) { | |
825 | $sql .= ' AND (b.courseid = ' . $courseid . ') '; | |
826 | } | |
827 | $sql .= ' ORDER BY bi.dateissued DESC'; | |
828 | $badges = $DB->get_records_sql($sql, $params, $page * $perpage, $perpage); | |
829 | ||
830 | return $badges; | |
831 | } | |
832 | ||
27806552 YB |
833 | /** |
834 | * Extends the course administration navigation with the Badges page | |
835 | * | |
836 | * @param navigation_node $coursenode | |
837 | * @param object $course | |
838 | */ | |
839 | function badges_add_course_navigation(navigation_node $coursenode, stdClass $course) { | |
840 | global $CFG, $SITE; | |
841 | ||
842 | $coursecontext = context_course::instance($course->id); | |
843 | $isfrontpage = (!$coursecontext || $course->id == $SITE->id); | |
a72c2cd6 YB |
844 | $canmanage = has_any_capability(array('moodle/badges:viewawarded', |
845 | 'moodle/badges:createbadge', | |
846 | 'moodle/badges:awardbadge', | |
847 | 'moodle/badges:configurecriteria', | |
848 | 'moodle/badges:configuremessages', | |
849 | 'moodle/badges:configuredetails', | |
850 | 'moodle/badges:deletebadge'), $coursecontext); | |
27806552 | 851 | |
a72c2cd6 YB |
852 | if (!empty($CFG->enablebadges) && !empty($CFG->badges_allowcoursebadges) && !$isfrontpage && $canmanage) { |
853 | $coursenode->add(get_string('coursebadges', 'badges'), null, | |
854 | navigation_node::TYPE_CONTAINER, null, 'coursebadges', | |
855 | new pix_icon('i/badge', get_string('coursebadges', 'badges'))); | |
27806552 | 856 | |
a72c2cd6 | 857 | $url = new moodle_url('/badges/index.php', array('type' => BADGE_TYPE_COURSE, 'id' => $course->id)); |
27806552 | 858 | |
a72c2cd6 YB |
859 | $coursenode->get('coursebadges')->add(get_string('managebadges', 'badges'), $url, |
860 | navigation_node::TYPE_SETTING, null, 'coursebadges'); | |
19a9f2ea | 861 | |
a72c2cd6 YB |
862 | if (has_capability('moodle/badges:createbadge', $coursecontext)) { |
863 | $url = new moodle_url('/badges/newbadge.php', array('type' => BADGE_TYPE_COURSE, 'id' => $course->id)); | |
19a9f2ea | 864 | |
a72c2cd6 YB |
865 | $coursenode->get('coursebadges')->add(get_string('newbadge', 'badges'), $url, |
866 | navigation_node::TYPE_SETTING, null, 'newbadge'); | |
27806552 YB |
867 | } |
868 | } | |
869 | } | |
870 | ||
27806552 YB |
871 | /** |
872 | * Triggered when badge is manually awarded. | |
873 | * | |
874 | * @param object $data | |
875 | * @return boolean | |
876 | */ | |
877 | function badges_award_handle_manual_criteria_review(stdClass $data) { | |
878 | $criteria = $data->crit; | |
879 | $userid = $data->userid; | |
880 | $badge = new badge($criteria->badgeid); | |
881 | ||
882 | if (!$badge->is_active() || $badge->is_issued($userid)) { | |
883 | return true; | |
884 | } | |
885 | ||
886 | if ($criteria->review($userid)) { | |
887 | $criteria->mark_complete($userid); | |
888 | ||
889 | if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) { | |
890 | $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid); | |
891 | $badge->issue($userid); | |
892 | } | |
893 | } | |
894 | ||
895 | return true; | |
896 | } | |
897 | ||
898 | /** | |
899 | * Process badge image from form data | |
900 | * | |
901 | * @param badge $badge Badge object | |
902 | * @param string $iconfile Original file | |
903 | */ | |
904 | function badges_process_badge_image(badge $badge, $iconfile) { | |
905 | global $CFG, $USER; | |
906 | require_once($CFG->libdir. '/gdlib.php'); | |
907 | ||
908 | if (!empty($CFG->gdversion)) { | |
e50220f8 | 909 | process_new_icon($badge->get_context(), 'badges', 'badgeimage', $badge->id, $iconfile); |
27806552 YB |
910 | @unlink($iconfile); |
911 | ||
912 | // Clean up file draft area after badge image has been saved. | |
913 | $context = context_user::instance($USER->id, MUST_EXIST); | |
914 | $fs = get_file_storage(); | |
915 | $fs->delete_area_files($context->id, 'user', 'draft'); | |
916 | } | |
917 | } | |
918 | ||
919 | /** | |
920 | * Print badge image. | |
921 | * | |
922 | * @param badge $badge Badge object | |
923 | * @param stdClass $context | |
924 | * @param string $size | |
925 | */ | |
926 | function print_badge_image(badge $badge, stdClass $context, $size = 'small') { | |
927 | $fsize = ($size == 'small') ? 'f2' : 'f1'; | |
928 | ||
929 | $imageurl = moodle_url::make_pluginfile_url($context->id, 'badges', 'badgeimage', $badge->id, '/', $fsize, false); | |
930 | // Appending a random parameter to image link to forse browser reload the image. | |
b143259e YB |
931 | $imageurl->param('refresh', rand(1, 10000)); |
932 | $attributes = array('src' => $imageurl, 'alt' => s($badge->name), 'class' => 'activatebadge'); | |
27806552 YB |
933 | |
934 | return html_writer::empty_tag('img', $attributes); | |
935 | } | |
936 | ||
937 | /** | |
938 | * Bake issued badge. | |
939 | * | |
940 | * @param string $hash Unique hash of an issued badge. | |
941 | * @param int $badgeid ID of the original badge. | |
942 | * @param int $userid ID of badge recipient (optional). | |
943 | * @param boolean $pathhash Return file pathhash instead of image url (optional). | |
944 | * @return string|url Returns either new file path hash or new file URL | |
945 | */ | |
946 | function badges_bake($hash, $badgeid, $userid = 0, $pathhash = false) { | |
947 | global $CFG, $USER; | |
948 | require_once(dirname(dirname(__FILE__)) . '/badges/lib/bakerlib.php'); | |
949 | ||
950 | $badge = new badge($badgeid); | |
951 | $badge_context = $badge->get_context(); | |
952 | $userid = ($userid) ? $userid : $USER->id; | |
953 | $user_context = context_user::instance($userid); | |
954 | ||
955 | $fs = get_file_storage(); | |
956 | if (!$fs->file_exists($user_context->id, 'badges', 'userbadge', $badge->id, '/', $hash . '.png')) { | |
957 | if ($file = $fs->get_file($badge_context->id, 'badges', 'badgeimage', $badge->id, '/', 'f1.png')) { | |
958 | $contents = $file->get_content(); | |
959 | ||
960 | $filehandler = new PNG_MetaDataHandler($contents); | |
961 | $assertion = new moodle_url('/badges/assertion.php', array('b' => $hash)); | |
962 | if ($filehandler->check_chunks("tEXt", "openbadges")) { | |
963 | // Add assertion URL tExt chunk. | |
964 | $newcontents = $filehandler->add_chunks("tEXt", "openbadges", $assertion->out(false)); | |
965 | $fileinfo = array( | |
966 | 'contextid' => $user_context->id, | |
967 | 'component' => 'badges', | |
968 | 'filearea' => 'userbadge', | |
969 | 'itemid' => $badge->id, | |
970 | 'filepath' => '/', | |
971 | 'filename' => $hash . '.png', | |
972 | ); | |
973 | ||
974 | // Create a file with added contents. | |
975 | $newfile = $fs->create_file_from_string($fileinfo, $newcontents); | |
976 | if ($pathhash) { | |
977 | return $newfile->get_pathnamehash(); | |
978 | } | |
979 | } | |
980 | } else { | |
be2b37cf Y |
981 | debugging('Error baking badge image!', DEBUG_DEVELOPER); |
982 | return; | |
27806552 YB |
983 | } |
984 | } | |
985 | ||
f5d17c14 YB |
986 | // If file exists and we just need its path hash, return it. |
987 | if ($pathhash) { | |
988 | $file = $fs->get_file($user_context->id, 'badges', 'userbadge', $badge->id, '/', $hash . '.png'); | |
989 | return $file->get_pathnamehash(); | |
990 | } | |
991 | ||
27806552 YB |
992 | $fileurl = moodle_url::make_pluginfile_url($user_context->id, 'badges', 'userbadge', $badge->id, '/', $hash, true); |
993 | return $fileurl; | |
994 | } | |
995 | ||
996 | /** | |
e2805314 | 997 | * Returns external backpack settings and badges from this backpack. |
27806552 | 998 | * |
2d3c0fae YB |
999 | * This function first checks if badges for the user are cached and |
1000 | * tries to retrieve them from the cache. Otherwise, badges are obtained | |
1001 | * through curl request to the backpack. | |
1002 | * | |
27806552 | 1003 | * @param int $userid Backpack user ID. |
2d3c0fae | 1004 | * @param boolean $refresh Refresh badges collection in cache. |
27806552 YB |
1005 | * @return null|object Returns null is there is no backpack or object with backpack settings. |
1006 | */ | |
2d3c0fae | 1007 | function get_backpack_settings($userid, $refresh = false) { |
27806552 YB |
1008 | global $DB; |
1009 | require_once(dirname(dirname(__FILE__)) . '/badges/lib/backpacklib.php'); | |
1010 | ||
2d3c0fae YB |
1011 | // Try to get badges from cache first. |
1012 | $badgescache = cache::make('core', 'externalbadges'); | |
1013 | $out = $badgescache->get($userid); | |
1014 | if ($out !== false && !$refresh) { | |
1015 | return $out; | |
1016 | } | |
1017 | // Get badges through curl request to the backpack. | |
e2805314 | 1018 | $record = $DB->get_record('badge_backpack', array('userid' => $userid)); |
27806552 YB |
1019 | if ($record) { |
1020 | $backpack = new OpenBadgesBackpackHandler($record); | |
1021 | $out = new stdClass(); | |
1022 | $out->backpackurl = $backpack->get_url(); | |
e2805314 YB |
1023 | |
1024 | if ($collections = $DB->get_records('badge_external', array('backpackid' => $record->id))) { | |
1025 | $out->totalcollections = count($collections); | |
1026 | $out->totalbadges = 0; | |
1027 | $out->badges = array(); | |
1028 | foreach ($collections as $collection) { | |
1029 | $badges = $backpack->get_badges($collection->collectionid); | |
1030 | if (isset($badges->badges)) { | |
1031 | $out->badges = array_merge($out->badges, $badges->badges); | |
1032 | $out->totalbadges += count($out->badges); | |
1033 | } else { | |
1034 | $out->badges = array_merge($out->badges, array()); | |
1035 | } | |
1036 | } | |
1037 | } else { | |
1038 | $out->totalbadges = 0; | |
1039 | $out->totalcollections = 0; | |
1040 | } | |
1041 | ||
2d3c0fae | 1042 | $badgescache->set($userid, $out); |
27806552 YB |
1043 | return $out; |
1044 | } | |
1045 | ||
1046 | return null; | |
1047 | } | |
1048 | ||
1049 | /** | |
1050 | * Download all user badges in zip archive. | |
1051 | * | |
1052 | * @param int $userid ID of badge owner. | |
1053 | */ | |
1054 | function badges_download($userid) { | |
1055 | global $CFG, $DB; | |
1056 | $context = context_user::instance($userid); | |
1057 | $records = $DB->get_records('badge_issued', array('userid' => $userid)); | |
1058 | ||
1059 | // Get list of files to download. | |
1060 | $fs = get_file_storage(); | |
1061 | $filelist = array(); | |
1062 | foreach ($records as $issued) { | |
1063 | $badge = new badge($issued->badgeid); | |
1064 | // Need to make image name user-readable and unique using filename safe characters. | |
1065 | $name = $badge->name . ' ' . userdate($issued->dateissued, '%d %b %Y') . ' ' . hash('crc32', $badge->id); | |
1066 | $name = str_replace(' ', '_', $name); | |
1067 | if ($file = $fs->get_file($context->id, 'badges', 'userbadge', $issued->badgeid, '/', $issued->uniquehash . '.png')) { | |
1068 | $filelist[$name . '.png'] = $file; | |
1069 | } | |
1070 | } | |
1071 | ||
1072 | // Zip files and sent them to a user. | |
1073 | $tempzip = tempnam($CFG->tempdir.'/', 'mybadges'); | |
1074 | $zipper = new zip_packer(); | |
1075 | if ($zipper->archive_to_pathname($filelist, $tempzip)) { | |
1076 | send_temp_file($tempzip, 'badges.zip'); | |
1077 | } else { | |
1078 | debugging("Problems with archiving the files."); | |
1079 | } | |
1080 | } | |
1081 | ||
1082 | /** | |
1083 | * Print badges on user profile page. | |
1084 | * | |
1085 | * @param int $userid User ID. | |
1086 | * @param int $courseid Course if we need to filter badges (optional). | |
1087 | */ | |
1088 | function profile_display_badges($userid, $courseid = 0) { | |
1089 | global $CFG, $PAGE, $USER, $SITE; | |
1090 | require_once($CFG->dirroot . '/badges/renderer.php'); | |
1091 | ||
497c676f YB |
1092 | // Determine context. |
1093 | if (isloggedin()) { | |
1094 | $context = context_user::instance($USER->id); | |
1095 | } else { | |
1096 | $context = context_system::instance(); | |
1097 | } | |
1098 | ||
1099 | if ($USER->id == $userid || has_capability('moodle/badges:viewotherbadges', $context)) { | |
27806552 YB |
1100 | $records = badges_get_user_badges($userid, $courseid, null, null, null, true); |
1101 | $renderer = new core_badges_renderer($PAGE, ''); | |
1102 | ||
1103 | // Print local badges. | |
1104 | if ($records) { | |
497c676f | 1105 | $left = get_string('localbadgesp', 'badges', format_string($SITE->fullname)); |
27806552 YB |
1106 | $right = $renderer->print_badges_list($records, $userid, true); |
1107 | echo html_writer::tag('dt', $left); | |
1108 | echo html_writer::tag('dd', $right); | |
1109 | } | |
1110 | ||
1111 | // Print external badges. | |
60d72efb | 1112 | if ($courseid == 0 && !empty($CFG->badges_allowexternalbackpack)) { |
27806552 YB |
1113 | $backpack = get_backpack_settings($userid); |
1114 | if (isset($backpack->totalbadges) && $backpack->totalbadges !== 0) { | |
1115 | $left = get_string('externalbadgesp', 'badges'); | |
1116 | $right = $renderer->print_badges_list($backpack->badges, $userid, true, true); | |
1117 | echo html_writer::tag('dt', $left); | |
1118 | echo html_writer::tag('dd', $right); | |
1119 | } | |
1120 | } | |
1121 | } | |
1122 | } | |
1123 | ||
1124 | /** | |
1125 | * Checks if badges can be pushed to external backpack. | |
1126 | * | |
1127 | * @return string Code of backpack accessibility status. | |
1128 | */ | |
1129 | function badges_check_backpack_accessibility() { | |
1130 | global $CFG; | |
1131 | include_once $CFG->libdir . '/filelib.php'; | |
1132 | ||
1133 | // Using fake assertion url to check whether backpack can access the web site. | |
1134 | $fakeassertion = new moodle_url('/badges/assertion.php', array('b' => 'abcd1234567890')); | |
1135 | ||
1136 | // Curl request to http://backpack.openbadges.org/baker. | |
1137 | $curl = new curl(); | |
1138 | $options = array( | |
1139 | 'FRESH_CONNECT' => true, | |
1140 | 'RETURNTRANSFER' => true, | |
27806552 | 1141 | 'HEADER' => 0, |
dd4a197e | 1142 | 'CONNECTTIMEOUT' => 2, |
27806552 YB |
1143 | ); |
1144 | $location = 'http://backpack.openbadges.org/baker'; | |
1145 | $out = $curl->get($location, array('assertion' => $fakeassertion->out(false)), $options); | |
1146 | ||
1147 | $data = json_decode($out); | |
1148 | if (!empty($curl->error)) { | |
1149 | return 'curl-request-timeout'; | |
1150 | } else { | |
1151 | if (isset($data->code) && $data->code == 'http-unreachable') { | |
1152 | return 'http-unreachable'; | |
1153 | } else { | |
1154 | return 'available'; | |
1155 | } | |
1156 | } | |
1157 | ||
1158 | return false; | |
1159 | } | |
e2805314 YB |
1160 | |
1161 | /** | |
1162 | * Checks if user has external backpack connected. | |
1163 | * | |
1164 | * @param int $userid ID of a user. | |
1165 | * @return bool True|False whether backpack connection exists. | |
1166 | */ | |
1167 | function badges_user_has_backpack($userid) { | |
1168 | global $DB; | |
1169 | return $DB->record_exists('badge_backpack', array('userid' => $userid)); | |
1170 | } | |
7deff81f YB |
1171 | |
1172 | /** | |
1173 | * Handles what happens to the course badges when a course is deleted. | |
1174 | * | |
1175 | * @param int $courseid course ID. | |
1176 | * @return void. | |
1177 | */ | |
1178 | function badges_handle_course_deletion($courseid) { | |
1179 | global $CFG, $DB; | |
1180 | include_once $CFG->libdir . '/filelib.php'; | |
1181 | ||
1182 | $systemcontext = context_system::instance(); | |
1183 | $coursecontext = context_course::instance($courseid); | |
1184 | $fs = get_file_storage(); | |
1185 | ||
1186 | // Move badges images to the system context. | |
1187 | $fs->move_area_files_to_new_context($coursecontext->id, $systemcontext->id, 'badges', 'badgeimage'); | |
1188 | ||
1189 | // Get all course badges. | |
1190 | $badges = $DB->get_records('badge', array('type' => BADGE_TYPE_COURSE, 'courseid' => $courseid)); | |
1191 | foreach ($badges as $badge) { | |
1192 | // Archive badges in this course. | |
1193 | $toupdate = new stdClass(); | |
1194 | $toupdate->id = $badge->id; | |
1195 | $toupdate->type = BADGE_TYPE_SITE; | |
1196 | $toupdate->courseid = null; | |
1197 | $toupdate->status = BADGE_STATUS_ARCHIVED; | |
1198 | $DB->update_record('badge', $toupdate); | |
1199 | } | |
1200 | } | |
2c910861 YB |
1201 | |
1202 | /** | |
1203 | * Loads JS files required for backpack support. | |
1204 | * | |
1205 | * @uses $CFG, $PAGE | |
1206 | * @return void | |
1207 | */ | |
1208 | function badges_setup_backpack_js() { | |
1209 | global $CFG, $PAGE; | |
1210 | if (!empty($CFG->badges_allowexternalbackpack)) { | |
1211 | $PAGE->requires->string_for_js('error:backpackproblem', 'badges'); | |
1212 | $protocol = (strpos($CFG->wwwroot, 'https://') === 0) ? 'https://' : 'http://'; | |
1213 | $PAGE->requires->js(new moodle_url($protocol . 'backpack.openbadges.org/issuer.js'), true); | |
1214 | $PAGE->requires->js('/badges/backpack.js', true); | |
1215 | } | |
1216 | } |