Proyectos de Subversion Moodle

Rev

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