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
 * Extends the IMS Tool provider library data connector for moodle.
19
 *
20
 * @package    enrol_lti
21
 * @copyright  2016 John Okely <john@moodle.com>
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
namespace enrol_lti;
26
 
27
defined('MOODLE_INTERNAL') || die;
28
 
29
use IMSGlobal\LTI\ToolProvider;
30
use IMSGlobal\LTI\ToolProvider\ConsumerNonce;
31
use IMSGlobal\LTI\ToolProvider\Context;
32
use IMSGlobal\LTI\ToolProvider\DataConnector\DataConnector;
33
use IMSGlobal\LTI\ToolProvider\ResourceLink;
34
use IMSGlobal\LTI\ToolProvider\ResourceLinkShare;
35
use IMSGlobal\LTI\ToolProvider\ResourceLinkShareKey;
36
use IMSGlobal\LTI\ToolProvider\ToolConsumer;
37
use IMSGlobal\LTI\ToolProvider\ToolProxy;
38
use IMSGlobal\LTI\ToolProvider\User;
39
use stdClass;
40
 
41
/**
42
 * Extends the IMS Tool provider library data connector for moodle.
43
 *
44
 * @package    enrol_lti
45
 * @copyright  2016 John Okely <john@moodle.com>
46
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
47
 */
48
class data_connector extends DataConnector {
49
 
50
    /** @var string Tool consumer table name. */
51
    protected $consumertable;
52
    /** @var string Context table name. */
53
    protected $contexttable;
54
    /** @var string Consumer nonce table name. */
55
    protected $noncetable;
56
    /** @var string Resource link table name. */
57
    protected $resourcelinktable;
58
    /** @var string Resource link share key table name. */
59
    protected $sharekeytable;
60
    /** @var string Tool proxy table name. */
61
    protected $toolproxytable;
62
    /** @var string User result table name. */
63
    protected $userresulttable;
64
 
65
    /**
66
     * data_connector constructor.
67
     */
68
    public function __construct() {
69
        parent::__construct(null, 'enrol_lti_');
70
 
71
        // Set up table names.
72
        $this->consumertable = $this->dbTableNamePrefix . DataConnector::CONSUMER_TABLE_NAME;
73
        $this->contexttable = $this->dbTableNamePrefix . DataConnector::CONTEXT_TABLE_NAME;
74
        $this->noncetable = $this->dbTableNamePrefix . DataConnector::NONCE_TABLE_NAME;
75
        $this->resourcelinktable = $this->dbTableNamePrefix . DataConnector::RESOURCE_LINK_TABLE_NAME;
76
        $this->sharekeytable = $this->dbTableNamePrefix . DataConnector::RESOURCE_LINK_SHARE_KEY_TABLE_NAME;
77
        $this->toolproxytable = $this->dbTableNamePrefix . DataConnector::TOOL_PROXY_TABLE_NAME;
78
        $this->userresulttable = $this->dbTableNamePrefix . DataConnector::USER_RESULT_TABLE_NAME;
79
    }
80
 
81
    /**
82
     * Load tool consumer object.
83
     *
84
     * @param ToolConsumer $consumer ToolConsumer object
85
     * @return boolean True if the tool consumer object was successfully loaded
86
     */
87
    public function loadToolConsumer($consumer) {
88
        global $DB;
89
 
90
        $id = $consumer->getRecordId();
91
        $key = $consumer->getKey();
92
        $result = false;
93
 
94
        if (!empty($id)) {
95
            $result = $DB->get_record($this->consumertable, ['id' => $id]);
96
        } else if (!empty($key)) {
97
            $key256 = DataConnector::getConsumerKey($key);
98
            $result = $DB->get_record($this->consumertable, ['consumerkey256' => $key256]);
99
        }
100
 
101
        if ($result) {
102
            if (empty($key256) || empty($result->consumerkey) || ($key === $result->consumerkey)) {
103
                $this->build_tool_consumer_object($result, $consumer);
104
                return true;
105
            }
106
        }
107
 
108
        return false;
109
    }
110
 
111
    /**
112
     * Save tool consumer object.
113
     *
114
     * @param ToolConsumer $consumer Consumer object
115
     * @return boolean True if the tool consumer object was successfully saved
116
     */
117
    public function saveToolConsumer($consumer) {
118
        global $DB;
119
 
120
        $key = $consumer->getKey();
121
        $key256 = DataConnector::getConsumerKey($key);
122
        if ($key === $key256) {
123
            $key = null;
124
        }
125
        $protected = ($consumer->protected) ? 1 : 0;
126
        $enabled = ($consumer->enabled) ? 1 : 0;
127
        $profile = (!empty($consumer->profile)) ? json_encode($consumer->profile) : null;
128
        $settingsvalue = serialize($consumer->getSettings());
129
        $now = time();
130
        $consumer->updated = $now;
131
        $data = [
132
            'consumerkey256' => $key256,
133
            'consumerkey' => $key,
134
            'name' => $consumer->name,
135
            'secret' => $consumer->secret,
136
            'ltiversion' => $consumer->ltiVersion,
137
            'consumername' => $consumer->consumerName,
138
            'consumerversion' => $consumer->consumerVersion,
139
            'consumerguid' => $consumer->consumerGuid,
140
            'profile' => $profile,
141
            'toolproxy' => $consumer->toolProxy,
142
            'settings' => $settingsvalue,
143
            'protected' => $protected,
144
            'enabled' => $enabled,
145
            'enablefrom' => $consumer->enableFrom,
146
            'enableuntil' => $consumer->enableUntil,
147
            'lastaccess' => $consumer->lastAccess,
148
            'updated' => $consumer->updated,
149
        ];
150
 
151
        $id = $consumer->getRecordId();
152
 
153
        if (empty($id)) {
154
            $consumer->created = $now;
155
            $data['created'] = $consumer->created;
156
            $id = $DB->insert_record($this->consumertable, (object) $data);
157
            if ($id) {
158
                $consumer->setRecordId($id);
159
                return true;
160
            }
161
        } else {
162
            $data['id'] = $id;
163
            return $DB->update_record($this->consumertable, (object) $data);
164
        }
165
 
166
        return false;
167
    }
168
 
169
    /**
170
     * Delete tool consumer object and related records.
171
     *
172
     * @param ToolConsumer $consumer Consumer object
173
     * @return boolean True if the tool consumer object was successfully deleted
174
     */
175
    public function deleteToolConsumer($consumer) {
176
        global $DB;
177
 
178
        $consumerpk = $consumer->getRecordId();
179
        $deletecondition = ['consumerid' => $consumerpk];
180
 
181
        // Delete any nonce values for this consumer.
182
        $DB->delete_records($this->noncetable, $deletecondition);
183
 
184
        // Delete any outstanding share keys for resource links for this consumer.
185
        $where = "resourcelinkid IN (
186
                      SELECT rl.id
187
                        FROM {{$this->resourcelinktable}} rl
188
                       WHERE rl.consumerid = :consumerid
189
                  )";
190
        $DB->delete_records_select($this->sharekeytable, $where, $deletecondition);
191
 
192
        // Delete any outstanding share keys for resource links for contexts in this consumer.
193
        $where = "resourcelinkid IN (
194
                      SELECT rl.id
195
                        FROM {{$this->resourcelinktable}} rl
196
                  INNER JOIN {{$this->contexttable}} c
197
                          ON rl.contextid = c.id
198
                       WHERE c.consumerid = :consumerid
199
                )";
200
        $DB->delete_records_select($this->sharekeytable, $where, $deletecondition);
201
 
202
        // Delete any users in resource links for this consumer.
203
        $where = "resourcelinkid IN (
204
                    SELECT rl.id
205
                      FROM {{$this->resourcelinktable}} rl
206
                     WHERE rl.consumerid = :consumerid
207
                )";
208
        $DB->delete_records_select($this->userresulttable, $where, $deletecondition);
209
 
210
        // Delete any users in resource links for contexts in this consumer.
211
        $where = "resourcelinkid IN (
212
                         SELECT rl.id
213
                           FROM {{$this->resourcelinktable}} rl
214
                     INNER JOIN {{$this->contexttable}} c
215
                             ON rl.contextid = c.id
216
                          WHERE c.consumerid = :consumerid
217
                )";
218
        $DB->delete_records_select($this->userresulttable, $where, $deletecondition);
219
 
220
        // Update any resource links for which this consumer is acting as a primary resource link.
221
        $where = "primaryresourcelinkid IN (
222
                    SELECT rl.id
223
                      FROM {{$this->resourcelinktable}} rl
224
                     WHERE rl.consumerid = :consumerid
225
                )";
226
        $updaterecords = $DB->get_records_select($this->resourcelinktable, $where, $deletecondition);
227
        foreach ($updaterecords as $record) {
228
            $record->primaryresourcelinkid = null;
229
            $record->shareapproved = null;
230
            $DB->update_record($this->resourcelinktable, $record);
231
        }
232
 
233
        // Update any resource links for contexts in which this consumer is acting as a primary resource link.
234
        $where = "primaryresourcelinkid IN (
235
                        SELECT rl.id
236
                          FROM {{$this->resourcelinktable}} rl
237
                    INNER JOIN {{$this->contexttable}} c
238
                            ON rl.contextid = c.id
239
                         WHERE c.consumerid = :consumerid
240
                )";
241
        $updaterecords = $DB->get_records_select($this->resourcelinktable, $where, $deletecondition);
242
        foreach ($updaterecords as $record) {
243
            $record->primaryresourcelinkid = null;
244
            $record->shareapproved = null;
245
            $DB->update_record($this->resourcelinktable, $record);
246
        }
247
 
248
        // Delete any resource links for contexts in this consumer.
249
        $where = "contextid IN (
250
                      SELECT c.id
251
                        FROM {{$this->contexttable}} c
252
                       WHERE c.consumerid = :consumerid
253
                )";
254
        $DB->delete_records_select($this->resourcelinktable, $where, $deletecondition);
255
 
256
        // Delete any resource links for this consumer.
257
        $DB->delete_records($this->resourcelinktable, $deletecondition);
258
 
259
        // Delete any contexts for this consumer.
260
        $DB->delete_records($this->contexttable, $deletecondition);
261
 
262
        // Delete consumer.
263
        $DB->delete_records($this->consumertable, ['id' => $consumerpk]);
264
 
265
        $consumer->initialize();
266
 
267
        return true;
268
    }
269
 
270
    /**
271
     * Load all tool consumers from the database.
272
     * @return array
273
     */
274
    public function getToolConsumers() {
275
        global $DB;
276
        $consumers = [];
277
 
278
        $rsconsumers = $DB->get_recordset($this->consumertable, null, 'name');
279
        foreach ($rsconsumers as $row) {
280
            $consumer = new ToolProvider\ToolConsumer($row->consumerkey, $this);
281
            $this->build_tool_consumer_object($row, $consumer);
282
            $consumers[] = $consumer;
283
        }
284
        $rsconsumers->close();
285
 
286
        return $consumers;
287
    }
288
 
289
    /*
290
     * ToolProxy methods.
291
     */
292
 
293
    /**
294
     * Load the tool proxy from the database.
295
     *
296
     * @param ToolProxy $toolproxy
297
     * @return bool
298
     */
299
    public function loadToolProxy($toolproxy) {
300
        return false;
301
    }
302
 
303
    /**
304
     * Save the tool proxy to the database.
305
     *
306
     * @param ToolProxy $toolproxy
307
     * @return bool
308
     */
309
    public function saveToolProxy($toolproxy) {
310
        return false;
311
    }
312
 
313
    /**
314
     * Delete the tool proxy from the database.
315
     *
316
     * @param ToolProxy $toolproxy
317
     * @return bool
318
     */
319
    public function deleteToolProxy($toolproxy) {
320
        return false;
321
    }
322
 
323
    /*
324
     * Context methods.
325
     */
326
 
327
    /**
328
     * Load context object.
329
     *
330
     * @param Context $context Context object
331
     * @return boolean True if the context object was successfully loaded
332
     */
333
    public function loadContext($context) {
334
        global $DB;
335
 
336
        if (!empty($context->getRecordId())) {
337
            $params = ['id' => $context->getRecordId()];
338
        } else {
339
            $params = [
340
                'consumerid' => $context->getConsumer()->getRecordId(),
341
                'lticontextkey' => $context->ltiContextId
342
            ];
343
        }
344
        if ($row = $DB->get_record($this->contexttable, $params)) {
345
            $context->setRecordId($row->id);
346
            $context->setConsumerId($row->consumerid);
347
            $context->ltiContextId = $row->lticontextkey;
348
            $context->type = $row->type;
349
            $settings = unserialize($row->settings);
350
            if (!is_array($settings)) {
351
                $settings = array();
352
            }
353
            $context->setSettings($settings);
354
            $context->created = $row->created;
355
            $context->updated = $row->updated;
356
            return true;
357
        }
358
 
359
        return false;
360
    }
361
 
362
    /**
363
     * Save context object.
364
     *
365
     * @param Context $context Context object
366
     * @return boolean True if the context object was successfully saved
367
     */
368
    public function saveContext($context) {
369
        global $DB;
370
        $now = time();
371
        $context->updated = $now;
372
        $settingsvalue = serialize($context->getSettings());
373
        $id = $context->getRecordId();
374
        $consumerpk = $context->getConsumer()->getRecordId();
375
 
376
        $isinsert = empty($id);
377
        if ($isinsert) {
378
            $context->created = $now;
379
            $params = [
380
                'consumerid' => $consumerpk,
381
                'lticontextkey' => $context->ltiContextId,
382
                'type' => $context->type,
383
                'settings' => $settingsvalue,
384
                'created' => $context->created,
385
                'updated' => $context->updated,
386
            ];
387
            $id = $DB->insert_record($this->contexttable, (object) $params);
388
            if ($id) {
389
                $context->setRecordId($id);
390
                return true;
391
            }
392
        } else {
393
            $data = (object) [
394
                'id' => $id,
395
                'contextid' => $consumerpk,
396
                'lticontextkey' => $context->ltiContextId,
397
                'type' => $context->type,
398
                'settings' => $settingsvalue,
399
                'updated' => $context->updated,
400
            ];
401
            return $DB->update_record($this->contexttable, $data);
402
        }
403
 
404
        return false;
405
    }
406
 
407
    /**
408
     * Delete context object.
409
     *
410
     * @param Context $context Context object
411
     * @return boolean True if the Context object was successfully deleted
412
     */
413
    public function deleteContext($context) {
414
        global $DB;
415
 
416
        $contextid = $context->getRecordId();
417
 
418
        $params = ['id' => $contextid];
419
 
420
        // Delete any outstanding share keys for resource links for this context.
421
        $where = "resourcelinkid IN (
422
                    SELECT rl.id
423
                      FROM {{$this->resourcelinktable}} rl
424
                     WHERE rl.contextid = :id
425
               )";
426
        $DB->delete_records_select($this->sharekeytable, $where, $params);
427
 
428
        // Delete any users in resource links for this context.
429
        $DB->delete_records_select($this->userresulttable, $where, $params);
430
 
431
        // Update any resource links for which this consumer is acting as a primary resource link.
432
        $where = "primaryresourcelinkid IN (
433
                    SELECT rl.id
434
                      FROM {{$this->resourcelinktable}} rl
435
                     WHERE rl.contextid = :id
436
               )";
437
        $updaterecords = $DB->get_records_select($this->resourcelinktable, $where, $params);
438
        foreach ($updaterecords as $record) {
439
            $record->primaryresourcelinkid = null;
440
            $record->shareapproved = null;
441
            $DB->update_record($this->resourcelinktable, $record);
442
        }
443
 
444
        // Delete any resource links for this context.
445
        $DB->delete_records($this->resourcelinktable, ['contextid' => $contextid]);
446
 
447
        // Delete context.
448
        $DB->delete_records($this->contexttable, $params);
449
 
450
        $context->initialize();
451
 
452
        return true;
453
    }
454
 
455
    /*
456
     * ResourceLink methods
457
     */
458
 
459
    /**
460
     * Load resource link object.
461
     *
462
     * @param ResourceLink $resourcelink ResourceLink object
463
     * @return boolean True if the resource link object was successfully loaded
464
     */
465
    public function loadResourceLink($resourcelink) {
466
        global $DB;
467
 
468
        $resourceid = $resourcelink->getRecordId();
469
        if (!empty($resourceid)) {
470
            $params = ['id' => $resourceid];
471
            $row = $DB->get_record($this->resourcelinktable, $params);
472
        } else if (!empty($resourcelink->getContext())) {
473
            $params = [
474
                'contextid' => $resourcelink->getContext()->getRecordId(),
475
                'ltiresourcelinkkey' => $resourcelink->getId()
476
            ];
477
            $row = $DB->get_record($this->resourcelinktable, $params);
478
        } else {
479
            $sql = "SELECT r.*
480
                      FROM {{$this->resourcelinktable}} r
481
           LEFT OUTER JOIN {{$this->contexttable}} c
482
                        ON r.contextid = c.id
483
                     WHERE (r.consumerid = ? OR c.consumerid = ?)
484
                           AND ltiresourcelinkkey = ?";
485
            $params = [
486
                $resourcelink->getConsumer()->getRecordId(),
487
                $resourcelink->getConsumer()->getRecordId(),
488
                $resourcelink->getId()
489
            ];
490
            $row = $DB->get_record_sql($sql, $params);
491
        }
492
        if ($row) {
493
            $resourcelink->setRecordId($row->id);
494
            if (!is_null($row->contextid)) {
495
                $resourcelink->setContextId($row->contextid);
496
            } else {
497
                $resourcelink->setContextId(null);
498
            }
499
            if (!is_null($row->consumerid)) {
500
                $resourcelink->setConsumerId($row->consumerid);
501
            } else {
502
                $resourcelink->setConsumerId(null);
503
            }
504
            $resourcelink->ltiResourceLinkId = $row->ltiresourcelinkkey;
505
            $settings = unserialize($row->settings);
506
            if (!is_array($settings)) {
507
                $settings = array();
508
            }
509
            $resourcelink->setSettings($settings);
510
            if (!is_null($row->primaryresourcelinkid)) {
511
                $resourcelink->primaryResourceLinkId = $row->primaryresourcelinkid;
512
            } else {
513
                $resourcelink->primaryResourceLinkId = null;
514
            }
515
            $resourcelink->shareApproved = (is_null($row->shareapproved)) ? null : ($row->shareapproved == 1);
516
            $resourcelink->created = $row->created;
517
            $resourcelink->updated = $row->updated;
518
            return true;
519
        }
520
 
521
        return false;
522
    }
523
 
524
    /**
525
     * Save resource link object.
526
     *
527
     * @param ResourceLink $resourcelink Resource_Link object
528
     * @return boolean True if the resource link object was successfully saved
529
     */
530
    public function saveResourceLink($resourcelink) {
531
        global $DB;
532
 
533
        if (is_null($resourcelink->shareApproved)) {
534
            $approved = null;
535
        } else if ($resourcelink->shareApproved) {
536
            $approved = 1;
537
        } else {
538
            $approved = 0;
539
        }
540
        if (empty($resourcelink->primaryResourceLinkId)) {
541
            $primaryresourcelinkid = null;
542
        } else {
543
            $primaryresourcelinkid = $resourcelink->primaryResourceLinkId;
544
        }
545
        $now = time();
546
        $resourcelink->updated = $now;
547
        $settingsvalue = serialize($resourcelink->getSettings());
548
        if (!empty($resourcelink->getContext())) {
549
            $consumerid = null;
550
            $contextid = $resourcelink->getContext()->getRecordId();
551
        } else if (!empty($resourcelink->getContextId())) {
552
            $consumerid = null;
553
            $contextid = $resourcelink->getContextId();
554
        } else {
555
            $consumerid = $resourcelink->getConsumer()->getRecordId();
556
            $contextid = null;
557
        }
558
        $id = $resourcelink->getRecordId();
559
 
560
        $data = [
561
            'consumerid' => $consumerid,
562
            'contextid' => $contextid,
563
            'ltiresourcelinkkey' => $resourcelink->getId(),
564
            'settings' => $settingsvalue,
565
            'primaryresourcelinkid' => $primaryresourcelinkid,
566
            'shareapproved' => $approved,
567
            'updated' => $resourcelink->updated,
568
        ];
569
 
570
        $returnid = null;
571
 
572
        if (empty($id)) {
573
            $resourcelink->created = $now;
574
            $data['created'] = $resourcelink->created;
575
            $id = $DB->insert_record($this->resourcelinktable, (object) $data);
576
            if ($id) {
577
                $resourcelink->setRecordId($id);
578
                return true;
579
            }
580
 
581
        } else {
582
            $data['id'] = $id;
583
            return $DB->update_record($this->resourcelinktable, (object) $data);
584
        }
585
 
586
        return false;
587
    }
588
 
589
    /**
590
     * Delete resource link object.
591
     *
592
     * @param ResourceLink $resourcelink ResourceLink object
593
     * @return boolean True if the resource link object and its related records were successfully deleted.
594
     *                 Otherwise, a DML exception is thrown.
595
     */
596
    public function deleteResourceLink($resourcelink) {
597
        global $DB;
598
 
599
        $resourcelinkid = $resourcelink->getRecordId();
600
 
601
        // Delete any outstanding share keys for resource links for this consumer.
602
        $DB->delete_records($this->sharekeytable, ['resourcelinkid' => $resourcelinkid]);
603
 
604
        // Delete users.
605
        $DB->delete_records($this->userresulttable, ['resourcelinkid' => $resourcelinkid]);
606
 
607
        // Update any resource links for which this is the primary resource link.
608
        $records = $DB->get_records($this->resourcelinktable, ['primaryresourcelinkid' => $resourcelinkid]);
609
        foreach ($records as $record) {
610
            $record->primaryresourcelinkid = null;
611
            $DB->update_record($this->resourcelinktable, $record);
612
        }
613
 
614
        // Delete resource link.
615
        $DB->delete_records($this->resourcelinktable, ['id' => $resourcelinkid]);
616
 
617
        $resourcelink->initialize();
618
 
619
        return true;
620
    }
621
 
622
    /**
623
     * Get array of user objects.
624
     *
625
     * Obtain an array of User objects for users with a result sourcedId.  The array may include users from other
626
     * resource links which are sharing this resource link.  It may also be optionally indexed by the user ID of a specified scope.
627
     *
628
     * @param ResourceLink $resourcelink Resource link object
629
     * @param boolean $localonly True if only users within the resource link are to be returned
630
     *                           (excluding users sharing this resource link)
631
     * @param int $idscope Scope value to use for user IDs
632
     * @return array Array of User objects
633
     */
634
    public function getUserResultSourcedIDsResourceLink($resourcelink, $localonly, $idscope) {
635
        global $DB;
636
 
637
        $users = [];
638
 
639
        $params = ['resourcelinkid' => $resourcelink->getRecordId()];
640
 
641
        // Where clause for the subquery.
642
        $subwhere = "(id = :resourcelinkid AND primaryresourcelinkid IS NULL)";
643
        if (!$localonly) {
644
            $subwhere .= " OR (primaryresourcelinkid = :resourcelinkid2 AND shareapproved = 1)";
645
            $params['resourcelinkid2'] = $resourcelink->getRecordId();
646
        }
647
 
648
        // The subquery.
649
        $subsql = "SELECT id
650
                     FROM {{$this->resourcelinktable}}
651
                    WHERE {$subwhere}";
652
 
653
        // Our main where clause.
654
        $where = "resourcelinkid IN ($subsql)";
655
 
656
        // Fields to be queried.
657
        $fields = 'id, ltiresultsourcedid, ltiuserkey, created, updated';
658
 
659
        // Fetch records.
660
        $rs = $DB->get_recordset_select($this->userresulttable, $where, $params, '', $fields);
661
        foreach ($rs as $row) {
662
            $user = User::fromResourceLink($resourcelink, $row->ltiuserkey);
663
            $user->setRecordId($row->id);
664
            $user->ltiResultSourcedId = $row->ltiresultsourcedid;
665
            $user->created = $row->created;
666
            $user->updated = $row->updated;
667
            if (is_null($idscope)) {
668
                $users[] = $user;
669
            } else {
670
                $users[$user->getId($idscope)] = $user;
671
            }
672
        }
673
        $rs->close();
674
 
675
        return $users;
676
    }
677
 
678
    /**
679
     * Get array of shares defined for this resource link.
680
     *
681
     * @param ResourceLink $resourcelink ResourceLink object
682
     * @return array Array of ResourceLinkShare objects
683
     */
684
    public function getSharesResourceLink($resourcelink) {
685
        global $DB;
686
 
687
        $shares = [];
688
 
689
        $params = ['primaryresourcelinkid' => $resourcelink->getRecordId()];
690
        $fields = 'id, shareapproved, consumerid';
691
        $records = $DB->get_records($this->resourcelinktable, $params, 'consumerid', $fields);
692
        foreach ($records as $record) {
693
            $share = new ResourceLinkShare();
694
            $share->resourceLinkId = $record->id;
695
            $share->approved = $record->shareapproved == 1;
696
            $shares[] = $share;
697
        }
698
 
699
        return $shares;
700
    }
701
 
702
    /*
703
     * ConsumerNonce methods
704
     */
705
 
706
    /**
707
     * Load nonce object.
708
     *
709
     * @param ConsumerNonce $nonce Nonce object
710
     * @return boolean True if the nonce object was successfully loaded
711
     */
712
    public function loadConsumerNonce($nonce) {
713
        global $DB;
714
 
715
        // Delete any expired nonce values.
716
        $now = time();
717
        $DB->delete_records_select($this->noncetable, "expires <= ?", [$now]);
718
 
719
        // Load the nonce.
720
        $params = [
721
            'consumerid' => $nonce->getConsumer()->getRecordId(),
722
            'value' => $nonce->getValue()
723
        ];
724
        $result = $DB->get_field($this->noncetable, 'value', $params);
725
 
726
        return !empty($result);
727
    }
728
 
729
    /**
730
     * Save nonce object.
731
     *
732
     * @param ConsumerNonce $nonce Nonce object
733
     * @return boolean True if the nonce object was successfully saved
734
     */
735
    public function saveConsumerNonce($nonce) {
736
        global $DB;
737
 
738
        $data = [
739
            'consumerid' => $nonce->getConsumer()->getRecordId(),
740
            'value' => $nonce->getValue(),
741
            'expires' => $nonce->expires
742
        ];
743
 
744
        return $DB->insert_record($this->noncetable, (object) $data, false);
745
    }
746
 
747
    /*
748
     * ResourceLinkShareKey methods.
749
     */
750
 
751
    /**
752
     * Load resource link share key object.
753
     *
754
     * @param ResourceLinkShareKey $sharekey ResourceLink share key object
755
     * @return boolean True if the resource link share key object was successfully loaded
756
     */
757
    public function loadResourceLinkShareKey($sharekey) {
758
        global $DB;
759
 
760
        // Clear expired share keys.
761
        $now = time();
762
        $where = "expires <= :expires";
763
 
764
        $DB->delete_records_select($this->sharekeytable, $where, ['expires' => $now]);
765
 
766
        // Load share key.
767
        $fields = 'resourcelinkid, autoapprove, expires';
768
        if ($sharekeyrecord = $DB->get_record($this->sharekeytable, ['sharekey' => $sharekey->getId()], $fields)) {
769
            if ($sharekeyrecord->resourcelinkid == $sharekey->resourceLinkId) {
770
                $sharekey->autoApprove = $sharekeyrecord->autoapprove == 1;
771
                $sharekey->expires = $sharekeyrecord->expires;
772
                return true;
773
            }
774
        }
775
 
776
        return false;
777
    }
778
 
779
    /**
780
     * Save resource link share key object.
781
     *
782
     * @param ResourceLinkShareKey $sharekey Resource link share key object
783
     * @return boolean True if the resource link share key object was successfully saved
784
     */
785
    public function saveResourceLinkShareKey($sharekey) {
786
        global $DB;
787
 
788
        if ($sharekey->autoApprove) {
789
            $approve = 1;
790
        } else {
791
            $approve = 0;
792
        }
793
 
794
        $expires = $sharekey->expires;
795
 
796
        $params = [
797
            'sharekey' => $sharekey->getId(),
798
            'resourcelinkid' => $sharekey->resourceLinkId,
799
            'autoapprove' => $approve,
800
            'expires' => $expires
801
        ];
802
 
803
        return $DB->insert_record($this->sharekeytable, (object) $params, false);
804
    }
805
 
806
    /**
807
     * Delete resource link share key object.
808
     *
809
     * @param ResourceLinkShareKey $sharekey Resource link share key object
810
     * @return boolean True if the resource link share key object was successfully deleted
811
     */
812
    public function deleteResourceLinkShareKey($sharekey) {
813
        global $DB;
814
 
815
        $DB->delete_records($this->sharekeytable, ['sharekey' => $sharekey->getId()]);
816
        $sharekey->initialize();
817
 
818
        return true;
819
    }
820
 
821
    /*
822
     * User methods
823
     */
824
 
825
    /**
826
     * Load user object.
827
     *
828
     * @param User $user User object
829
     * @return boolean True if the user object was successfully loaded
830
     */
831
    public function loadUser($user) {
832
        global $DB;
833
 
834
        $userid = $user->getRecordId();
835
        $fields = 'id, resourcelinkid, ltiuserkey, ltiresultsourcedid, created, updated';
836
        if (!empty($userid)) {
837
            $row = $DB->get_record($this->userresulttable, ['id' => $userid], $fields);
838
        } else {
839
            $resourcelinkid = $user->getResourceLink()->getRecordId();
840
            $userid = $user->getId(ToolProvider\ToolProvider::ID_SCOPE_ID_ONLY);
841
            $row = $DB->get_record_select(
842
                $this->userresulttable,
843
                "resourcelinkid = ? AND ltiuserkey = ?",
844
                [$resourcelinkid, $userid],
845
                $fields
846
            );
847
        }
848
        if ($row) {
849
            $user->setRecordId($row->id);
850
            $user->setResourceLinkId($row->resourcelinkid);
851
            $user->ltiUserId = $row->ltiuserkey;
852
            $user->ltiResultSourcedId = $row->ltiresultsourcedid;
853
            $user->created = $row->created;
854
            $user->updated = $row->updated;
855
            return true;
856
        }
857
 
858
        return false;
859
    }
860
 
861
    /**
862
     * Save user object.
863
     *
864
     * @param User $user User object
865
     * @return boolean True if the user object was successfully saved
866
     */
867
    public function saveUser($user) {
868
        global $DB;
869
 
870
        $now = time();
871
        $isinsert = is_null($user->created);
872
        $user->updated = $now;
873
 
874
        $params = [
875
            'ltiresultsourcedid' => $user->ltiResultSourcedId,
876
            'updated' => $user->updated
877
        ];
878
 
879
        if ($isinsert) {
880
            $params['resourcelinkid'] = $user->getResourceLink()->getRecordId();
881
            $params['ltiuserkey'] = $user->getId(ToolProvider\ToolProvider::ID_SCOPE_ID_ONLY);
882
            $user->created = $now;
883
            $params['created'] = $user->created;
884
            $id = $DB->insert_record($this->userresulttable, (object) $params);
885
            if ($id) {
886
                $user->setRecordId($id);
887
                return true;
888
            }
889
 
890
        } else {
891
            $params['id'] = $user->getRecordId();
892
            return $DB->update_record($this->userresulttable, (object) $params);
893
        }
894
 
895
        return false;
896
    }
897
 
898
    /**
899
     * Delete user object.
900
     *
901
     * @param User $user User object
902
     * @return boolean True if the user object was successfully deleted
903
     */
904
    public function deleteUser($user) {
905
        global $DB;
906
 
907
        $DB->delete_records($this->userresulttable, ['id' => $user->getRecordId()]);
908
        $user->initialize();
909
 
910
        return true;
911
    }
912
 
913
    /**
914
     * Fetches the list of Context objects that are linked to a ToolConsumer.
915
     *
916
     * @param ToolConsumer $consumer
917
     * @return Context[]
918
     */
919
    public function get_contexts_from_consumer(ToolConsumer $consumer) {
920
        global $DB;
921
 
922
        $contexts = [];
923
        $contextrecords = $DB->get_records($this->contexttable, ['consumerid' => $consumer->getRecordId()], '', 'lticontextkey');
924
        foreach ($contextrecords as $record) {
925
            $context = Context::fromConsumer($consumer, $record->lticontextkey);
926
            $contexts[] = $context;
927
        }
928
 
929
        return $contexts;
930
    }
931
 
932
    /**
933
     * Fetches a resource link record that is associated with a ToolConsumer.
934
     *
935
     * @param ToolConsumer $consumer
936
     * @return ResourceLink
937
     */
938
    public function get_resourcelink_from_consumer(ToolConsumer $consumer) {
939
        global $DB;
940
 
941
        $resourcelink = null;
942
        if ($resourcelinkrecord = $DB->get_record($this->resourcelinktable, ['consumerid' => $consumer->getRecordId()],
943
            'ltiresourcelinkkey')) {
944
            $resourcelink = ResourceLink::fromConsumer($consumer, $resourcelinkrecord->ltiresourcelinkkey);
945
        }
946
 
947
        return $resourcelink;
948
    }
949
 
950
    /**
951
     * Fetches a resource link record that is associated with a Context object.
952
     *
953
     * @param Context $context
954
     * @return ResourceLink
955
     */
956
    public function get_resourcelink_from_context(Context $context) {
957
        global $DB;
958
 
959
        $resourcelink = null;
960
        if ($resourcelinkrecord = $DB->get_record($this->resourcelinktable, ['contextid' => $context->getRecordId()],
961
            'ltiresourcelinkkey')) {
962
            $resourcelink = ResourceLink::fromContext($context, $resourcelinkrecord->ltiresourcelinkkey);
963
        }
964
 
965
        return $resourcelink;
966
    }
967
 
968
 
969
    /**
970
     * Fetches the list of ToolConsumer objects that are linked to a tool.
971
     *
972
     * @param int $toolid
973
     * @return ToolConsumer[]
974
     */
975
    public function get_consumers_mapped_to_tool($toolid) {
976
        global $DB;
977
 
978
        $consumers = [];
979
        $consumerrecords = $DB->get_records('enrol_lti_tool_consumer_map', ['toolid' => $toolid], '', 'consumerid');
980
        foreach ($consumerrecords as $record) {
981
            $consumers[] = ToolConsumer::fromRecordId($record->consumerid, $this);
982
        }
983
        return $consumers;
984
    }
985
 
986
    /**
987
     * Builds a ToolConsumer object from a record object from the DB.
988
     *
989
     * @param stdClass $record The DB record object.
990
     * @param ToolConsumer $consumer
991
     */
992
    protected function build_tool_consumer_object($record, ToolConsumer $consumer) {
993
        $consumer->setRecordId($record->id);
994
        $consumer->name = $record->name;
995
        $key = empty($record->consumerkey) ? $record->consumerkey256 : $record->consumerkey;
996
        $consumer->setKey($key);
997
        $consumer->secret = $record->secret;
998
        $consumer->ltiVersion = $record->ltiversion;
999
        $consumer->consumerName = $record->consumername;
1000
        $consumer->consumerVersion = $record->consumerversion;
1001
        $consumer->consumerGuid = $record->consumerguid;
1002
        $consumer->profile = json_decode($record->profile ?? '');
1003
        $consumer->toolProxy = $record->toolproxy;
1004
        $settings = unserialize($record->settings);
1005
        if (!is_array($settings)) {
1006
            $settings = array();
1007
        }
1008
        $consumer->setSettings($settings);
1009
        $consumer->protected = $record->protected == 1;
1010
        $consumer->enabled = $record->enabled == 1;
1011
        $consumer->enableFrom = null;
1012
        if (!is_null($record->enablefrom)) {
1013
            $consumer->enableFrom = $record->enablefrom;
1014
        }
1015
        $consumer->enableUntil = null;
1016
        if (!is_null($record->enableuntil)) {
1017
            $consumer->enableUntil = $record->enableuntil;
1018
        }
1019
        $consumer->lastAccess = null;
1020
        if (!is_null($record->lastaccess)) {
1021
            $consumer->lastAccess = $record->lastaccess;
1022
        }
1023
        $consumer->created = $record->created;
1024
        $consumer->updated = $record->updated;
1025
    }
1026
}