Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
 * Badge assertion library.
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
/**
30
 * Open Badges Assertions specification 1.0 {@link https://github.com/mozilla/openbadges-backpack/wiki/Assertions}
31
 *
32
 * Badge asserion is defined by three parts:
33
 * - Badge Assertion (information regarding a specific badge that was awarded to a badge earner)
34
 * - Badge Class (general information about a badge and what it is intended to represent)
35
 * - Issuer Class (general information of an issuing organisation)
36
 */
37
require_once($CFG->libdir . '/badgeslib.php');
38
require_once($CFG->dirroot . '/badges/renderer.php');
39
 
40
/**
41
 * Class that represents badge assertion.
42
 *
43
 */
44
class core_badges_assertion {
45
    /** @var object Issued badge information from database */
46
    private $_data;
47
 
48
    /** @var moodle_url Issued badge url */
49
    private $_url;
50
 
51
    /** @var int $obversion to control version JSON-LD. */
52
    private $_obversion = OPEN_BADGES_V2;
53
 
54
    /**
55
     * Constructs with issued badge unique hash.
56
     *
57
     * @param string $hash Badge unique hash from badge_issued table.
58
     * @param int $obversion to control version JSON-LD.
59
     */
60
    public function __construct($hash, $obversion = OPEN_BADGES_V2) {
61
        global $DB;
62
 
63
        $this->_data = $DB->get_record_sql('
64
            SELECT
65
                bi.dateissued,
66
                bi.dateexpire,
67
                bi.uniquehash,
68
                u.email,
69
                b.*,
70
                bb.email as backpackemail
71
            FROM
72
                {badge} b
73
                JOIN {badge_issued} bi
74
                    ON b.id = bi.badgeid
75
                JOIN {user} u
76
                    ON u.id = bi.userid
77
                LEFT JOIN {badge_backpack} bb
78
                    ON bb.userid = bi.userid
79
            WHERE ' . $DB->sql_compare_text('bi.uniquehash', 40) . ' = ' . $DB->sql_compare_text(':hash', 40),
80
            array('hash' => $hash), IGNORE_MISSING);
81
 
82
        if ($this->_data) {
83
            $this->_url = new moodle_url('/badges/badge.php', array('hash' => $this->_data->uniquehash));
84
        } else {
85
            $this->_url = new moodle_url('/badges/badge.php');
86
        }
87
        $this->_obversion = $obversion;
88
    }
89
 
90
    /**
91
     * Get the local id for this badge.
92
     *
93
     * @return int
94
     */
95
    public function get_badge_id() {
96
        $badgeid = 0;
97
        if ($this->_data) {
98
            $badgeid = $this->_data->id;
99
        }
100
        return $badgeid;
101
    }
102
 
103
    /**
104
     * Get the local id for this badge assertion.
105
     *
106
     * @return string
107
     */
108
    public function get_assertion_hash() {
109
        $hash = '';
110
        if ($this->_data) {
111
            $hash = $this->_data->uniquehash;
112
        }
113
        return $hash;
114
    }
115
 
116
    /**
117
     * Get badge assertion.
118
     *
119
     * @param boolean $issued Include the nested badge issued information.
120
     * @param boolean $usesalt Hash the identity and include the salt information for the hash.
121
     * @return array Badge assertion.
122
     */
123
    public function get_badge_assertion($issued = true, $usesalt = true) {
124
        global $CFG;
125
        $assertion = array();
126
        if ($this->_data) {
127
            $hash = $this->_data->uniquehash;
128
            $email = empty($this->_data->backpackemail) ? $this->_data->email : $this->_data->backpackemail;
129
            $assertionurl = new moodle_url('/badges/assertion.php', array('b' => $hash, 'obversion' => $this->_obversion));
130
 
131
            if ($this->_obversion >= OPEN_BADGES_V2) {
132
                $classurl = new moodle_url('/badges/badge_json.php', array('id' => $this->get_badge_id()));
133
            } else {
134
                $classurl = new moodle_url('/badges/assertion.php', array('b' => $hash, 'action' => 1));
135
            }
136
 
137
            // Required.
138
            $assertion['uid'] = $hash;
139
            $assertion['recipient'] = array();
140
            if ($usesalt) {
141
                $assertion['recipient']['identity'] = 'sha256$' . hash('sha256', $email . $CFG->badges_badgesalt);
142
            } else {
143
                $assertion['recipient']['identity'] = $email;
144
            }
145
            $assertion['recipient']['type'] = 'email'; // Currently the only supported type.
146
            $assertion['recipient']['hashed'] = true; // We are always hashing recipient.
147
            if ($usesalt) {
148
                $assertion['recipient']['salt'] = $CFG->badges_badgesalt;
149
            }
150
            if ($issued) {
151
                $assertion['badge'] = $classurl->out(false);
152
            }
153
            $assertion['verify'] = array();
154
            $assertion['verify']['type'] = 'hosted'; // 'Signed' is not implemented yet.
155
            $assertion['verify']['url'] = $assertionurl->out(false);
156
            $assertion['issuedOn'] = $this->_data->dateissued;
157
            if ($issued) {
158
                $assertion['evidence'] = $this->_url->out(false); // Currently issued badge URL.
159
            }
160
            // Optional.
161
            if (!empty($this->_data->dateexpire)) {
162
                $assertion['expires'] = $this->_data->dateexpire;
163
            }
164
            $tags = $this->get_tags();
165
            if (is_array($tags) && count($tags) > 0) {
166
                $assertion['tags'] = $tags;
167
            }
168
            $this->embed_data_badge_version2($assertion, OPEN_BADGES_V2_TYPE_ASSERTION);
169
        }
170
        return $assertion;
171
    }
172
 
173
    /**
174
     * Get badge class information.
175
     *
176
     * @param boolean $issued Include the nested badge issuer information.
177
     * @return array Badge Class information.
178
     */
179
    public function get_badge_class($issued = true) {
180
        $class = [];
181
        if ($this->_data) {
182
            if (empty($this->_data->courseid)) {
183
                $context = context_system::instance();
184
            } else {
185
                $context = context_course::instance($this->_data->courseid);
186
            }
187
            // Required.
188
            $class['name'] = $this->_data->name;
189
            $class['description'] = $this->_data->description;
190
            $storage = get_file_storage();
191
            $imagefile = $storage->get_file($context->id, 'badges', 'badgeimage', $this->_data->id, '/', 'f3.png');
192
            if ($imagefile) {
193
                $imagedata = base64_encode($imagefile->get_content());
194
            } else {
195
                if (defined('PHPUNIT_TEST') && PHPUNIT_TEST) {
196
                    // Unit tests the file might not exist yet.
197
                    $imagedata = '';
198
                } else {
199
                    throw new coding_exception('Image file does not exist.');
200
                }
201
            }
202
            $class['image'] = 'data:image/png;base64,' . $imagedata;
203
 
204
            $params = ['id' => $this->get_badge_id()];
205
            $badgeurl = new moodle_url('/badges/badgeclass.php', $params);
206
            $class['criteria'] = $badgeurl->out(false); // Currently badge URL.
207
            if ($issued) {
208
                $params = ['id' => $this->get_badge_id(), 'obversion' => $this->_obversion];
209
                $issuerurl = new moodle_url('/badges/issuer_json.php', $params);
210
                $class['issuer'] = $issuerurl->out(false);
211
            }
212
            $tags = $this->get_tags();
213
            if (is_array($tags) && count($tags) > 0) {
214
                $class['tags'] = $tags;
215
            }
216
            $this->embed_data_badge_version2($class, OPEN_BADGES_V2_TYPE_BADGE);
217
            if (!$issued) {
218
                unset($class['issuer']);
219
            }
220
        }
221
        return $class;
222
    }
223
 
224
    /**
225
     * Get badge issuer information.
226
     *
227
     * @return array Issuer information.
228
     */
229
    public function get_issuer() {
230
        global $CFG;
231
        $issuer = array();
232
        if ($this->_data) {
233
            // Required.
234
            if ($this->_obversion == OPEN_BADGES_V1) {
235
                $issuer['name'] = $this->_data->issuername;
236
                $issuer['url'] = $this->_data->issuerurl;
237
                // Optional.
238
                if (!empty($this->_data->issuercontact)) {
239
                    $issuer['email'] = $this->_data->issuercontact;
240
                } else {
241
                    $issuer['email'] = $CFG->badges_defaultissuercontact;
242
                }
243
            } else {
244
                $badge = new badge($this->get_badge_id());
245
                $issuer = $badge->get_badge_issuer();
246
            }
247
        }
248
        $this->embed_data_badge_version2($issuer, OPEN_BADGES_V2_TYPE_ISSUER);
249
        return $issuer;
250
    }
251
 
252
    /**
253
     * Get related badges of the badge.
254
     *
255
     * @param badge $badge Badge object.
256
     * @return array|bool List related badges.
257
     */
258
    public function get_related_badges(badge $badge) {
259
        global $DB;
260
        $arraybadges = array();
261
        $relatedbadges = $badge->get_related_badges(true);
262
        if ($relatedbadges) {
263
            foreach ($relatedbadges as $rb) {
264
                $url = new moodle_url('/badges/badge_json.php', array('id' => $rb->id));
265
                $arraybadges[] = array(
266
                    'id'        => $url->out(false),
267
                    'version'   => $rb->version,
268
                    '@language' => $rb->language
269
                );
270
            }
271
        }
272
        return $arraybadges;
273
    }
274
 
275
    /**
276
     * Get endorsement of the badge.
277
     *
278
     * @return false|stdClass Endorsement information.
279
     */
280
    public function get_endorsement() {
281
        global $DB;
282
        $endorsement = array();
283
        $record = $DB->get_record_select('badge_endorsement', 'badgeid = ?', array($this->_data->id));
284
        return $record;
285
    }
286
 
287
    /**
288
     * Get criteria of badge class.
289
     *
290
     * @return array|string Criteria information.
291
     */
292
    public function get_criteria_badge_class() {
293
        $badge = new badge($this->_data->id);
294
        $narrative = $badge->markdown_badge_criteria();
295
        $params = ['id' => $this->get_badge_id()];
296
        $badgeurl = new moodle_url('/badges/badgeclass.php', $params);
297
        if (!empty($narrative)) {
298
            $criteria = [];
299
            $criteria['id'] = $badgeurl->out(false);
300
            $criteria['narrative'] = $narrative;
301
            return $criteria;
302
        } else {
303
            return $badgeurl->out(false);
304
        }
305
    }
306
 
307
    /**
308
     * Get alignment of the badge.
309
     *
310
     * @return array information.
311
     */
312
    public function get_alignments() {
313
        global $DB;
314
        $badgeid = $this->_data->id;
315
        $alignments = array();
316
        $items = $DB->get_records_select('badge_alignment', 'badgeid = ?', array($badgeid));
317
        foreach ($items as $item) {
318
            $alignment = array('targetName' => $item->targetname, 'targetUrl' => $item->targeturl);
319
            if ($item->targetdescription) {
320
                $alignment['targetDescription'] = $item->targetdescription;
321
            }
322
            if ($item->targetframework) {
323
                $alignment['targetFramework'] = $item->targetframework;
324
            }
325
            if ($item->targetcode) {
326
                $alignment['targetCode'] = $item->targetcode;
327
            }
328
            $alignments[] = $alignment;
329
        }
330
        return $alignments;
331
    }
332
 
333
    /**
334
     * Embed data of Open Badges Specification Version 2.0 to json.
335
     *
336
     * @param array $json for assertion, badges, issuer.
337
     * @param string $type Content type.
338
     */
339
    protected function embed_data_badge_version2(&$json, $type = OPEN_BADGES_V2_TYPE_ASSERTION) {
340
        // Specification Version 2.0.
341
        if ($this->_obversion >= OPEN_BADGES_V2) {
342
            $badge = new badge($this->_data->id);
343
            if (empty($this->_data->courseid)) {
344
                $context = context_system::instance();
345
            } else {
346
                $context = context_course::instance($this->_data->courseid);
347
            }
348
 
349
            $hash = $this->_data->uniquehash;
350
            $assertionsurl = new moodle_url('/badges/assertion.php', array('b' => $hash, 'obversion' => $this->_obversion));
351
            $classurl = new moodle_url(
352
                '/badges/badge_json.php',
353
                array('id' => $this->get_badge_id())
354
            );
355
            $issuerurl = new moodle_url('/badges/issuer_json.php', ['id' => $this->get_badge_id()]);
356
            // For assertion.
357
            if ($type == OPEN_BADGES_V2_TYPE_ASSERTION) {
358
                $json['@context'] = OPEN_BADGES_V2_CONTEXT;
359
                $json['type'] = OPEN_BADGES_V2_TYPE_ASSERTION;
360
                $json['id'] = $assertionsurl->out(false);
361
                $json['badge'] = $this->get_badge_class();
362
                $json['issuedOn'] = date('c', $this->_data->dateissued);
363
                if (!empty($this->_data->dateexpire)) {
364
                    $json['expires'] = date('c', $this->_data->dateexpire);
365
                }
366
                unset($json['uid']);
367
            }
368
            // For Badge.
369
            if ($type == OPEN_BADGES_V2_TYPE_BADGE) {
370
                $json['@context'] = OPEN_BADGES_V2_CONTEXT;
371
                $json['id'] = $classurl->out(false);
372
                $json['type'] = OPEN_BADGES_V2_TYPE_BADGE;
373
                $json['version'] = $this->_data->version;
374
                $json['criteria'] = $this->get_criteria_badge_class();
375
                $json['issuer'] = $this->get_issuer();
376
                $json['@language'] = $this->_data->language;
377
                if (!empty($relatedbadges = $this->get_related_badges($badge))) {
378
                    $json['related'] = $relatedbadges;
379
                }
380
                if ($endorsement = $this->get_endorsement()) {
381
                    $endorsementurl = new moodle_url('/badges/endorsement_json.php', array('id' => $this->_data->id));
382
                    $json['endorsement'] = $endorsementurl->out(false);
383
                }
384
                if ($alignments = $this->get_alignments()) {
385
                    $json['alignments'] = $alignments;
386
                }
387
                if ($this->_data->imageauthorname ||
388
                        $this->_data->imageauthoremail ||
389
                        $this->_data->imageauthorurl ||
390
                        $this->_data->imagecaption) {
391
                    $storage = get_file_storage();
392
                    $imagefile = $storage->get_file($context->id, 'badges', 'badgeimage', $this->_data->id, '/', 'f3.png');
393
                    if ($imagefile) {
394
                        $imagedata = base64_encode($imagefile->get_content());
395
                    } else {
396
                        // The file might not exist in unit tests.
397
                        if (defined('PHPUNIT_TEST') && PHPUNIT_TEST) {
398
                            $imagedata = '';
399
                        } else {
400
                            throw new coding_exception('Image file does not exist.');
401
                        }
402
                    }
403
                    $json['image'] = 'data:image/png;base64,' . $imagedata;
404
                }
405
            }
406
 
407
            // For issuer.
408
            if ($type == OPEN_BADGES_V2_TYPE_ISSUER) {
409
                $json['@context'] = OPEN_BADGES_V2_CONTEXT;
410
                $json['id'] = $issuerurl->out(false);
411
                $json['type'] = OPEN_BADGES_V2_TYPE_ISSUER;
412
            }
413
        }
414
    }
415
 
416
    /**
417
     * Get tags of the badge.
418
     *
419
     * @return array tags.
420
     */
421
    public function get_tags(): array {
422
        return array_values(\core_tag_tag::get_item_tags_array('core_badges', 'badge', $this->get_badge_id()));
423
    }
424
}