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
 * Class to manage subscriptions.
19
 *
20
 * @package    tool_monitor
21
 * @copyright  2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
namespace tool_monitor;
26
 
27
defined('MOODLE_INTERNAL') || die();
28
 
29
/**
30
 * Class to manage subscriptions.
31
 *
32
 * @since      Moodle 2.8
33
 * @package    tool_monitor
34
 * @copyright  2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
35
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36
 */
37
class subscription_manager {
38
 
39
    /** @var Period of time, in days, after which an inactive subscription will be removed completely.*/
40
    const INACTIVE_SUBSCRIPTION_LIFESPAN_IN_DAYS = 30;
41
 
42
    /**
43
     * Subscribe a user to a given rule.
44
     *
45
     * @param int $ruleid  Rule id.
46
     * @param int $courseid Course id.
47
     * @param int $cmid Course module id.
48
     * @param int $userid User who is subscribing, defaults to $USER.
49
     *
50
     * @return bool|int returns id of the created subscription.
51
     */
52
    public static function create_subscription($ruleid, $courseid, $cmid, $userid = 0) {
53
        global $DB, $USER;
54
 
55
        $subscription = new \stdClass();
56
        $subscription->ruleid = $ruleid;
57
        $subscription->courseid = $courseid;
58
        $subscription->cmid = $cmid;
59
        $subscription->userid = empty($userid) ? $USER->id : $userid;
60
        if ($DB->record_exists('tool_monitor_subscriptions', (array)$subscription)) {
61
            // Subscription already exists.
62
            return false;
63
        }
64
 
65
        $subscription->timecreated = time();
66
        $subscription->id = $DB->insert_record('tool_monitor_subscriptions', $subscription);
67
 
68
        // Trigger a subscription created event.
69
        if ($subscription->id) {
70
            if (!empty($subscription->courseid)) {
71
                $courseid = $subscription->courseid;
72
                $context = \context_course::instance($subscription->courseid);
73
            } else {
74
                $courseid = 0;
75
                $context = \context_system::instance();
76
            }
77
 
78
            $params = array(
79
                'objectid' => $subscription->id,
80
                'courseid' => $courseid,
81
                'context' => $context
82
            );
83
            $event = \tool_monitor\event\subscription_created::create($params);
84
            $event->trigger();
85
 
86
            // Let's invalidate the cache.
87
            $cache = \cache::make('tool_monitor', 'eventsubscriptions');
88
            $cache->delete($courseid);
89
        }
90
 
91
        return $subscription->id;
92
    }
93
 
94
    /**
95
     * Delete a subscription.
96
     *
97
     * @param subscription|int $subscriptionorid an instance of subscription class or id.
98
     * @param bool $checkuser Check if the subscription belongs to current user before deleting.
99
     *
100
     * @return bool
101
     * @throws \coding_exception if $checkuser is true and the subscription doesn't belong to the current user.
102
     */
103
    public static function delete_subscription($subscriptionorid, $checkuser = true) {
104
        global $DB, $USER;
105
        if (is_object($subscriptionorid)) {
106
            $subscription = $subscriptionorid;
107
        } else {
108
            $subscription = self::get_subscription($subscriptionorid);
109
        }
110
        if ($checkuser && $subscription->userid != $USER->id) {
111
            throw new \coding_exception('Invalid subscription supplied');
112
        }
113
 
114
        // Store the subscription before we delete it.
115
        $subscription = $DB->get_record('tool_monitor_subscriptions', array('id' => $subscription->id));
116
 
117
        $success = $DB->delete_records('tool_monitor_subscriptions', array('id' => $subscription->id));
118
 
119
        // If successful trigger a subscription_deleted event.
120
        if ($success) {
121
            if (!empty($subscription->courseid) &&
122
                    ($coursecontext = \context_course::instance($subscription->courseid, IGNORE_MISSING))) {
123
                $courseid = $subscription->courseid;
124
                $context = $coursecontext;
125
            } else {
126
                $courseid = 0;
127
                $context = \context_system::instance();
128
            }
129
 
130
            $params = array(
131
                'objectid' => $subscription->id,
132
                'courseid' => $courseid,
133
                'context' => $context
134
            );
135
            $event = \tool_monitor\event\subscription_deleted::create($params);
136
            $event->add_record_snapshot('tool_monitor_subscriptions', $subscription);
137
            $event->trigger();
138
 
139
            // Let's invalidate the cache.
140
            $cache = \cache::make('tool_monitor', 'eventsubscriptions');
141
            $cache->delete($courseid);
142
        }
143
 
144
        return $success;
145
    }
146
 
147
    /**
148
     * Delete all subscriptions for a user.
149
     *
150
     * @param int $userid user id.
151
     *
152
     * @return mixed
153
     */
154
    public static function delete_user_subscriptions($userid) {
155
        global $DB;
156
        return $DB->delete_records('tool_monitor_subscriptions', array('userid' => $userid));
157
    }
158
 
159
    /**
160
     * Delete all subscriptions for a course module.
161
     *
162
     * @param int $cmid cm id.
163
     *
164
     * @return mixed
165
     */
166
    public static function delete_cm_subscriptions($cmid) {
167
        global $DB;
168
        return $DB->delete_records('tool_monitor_subscriptions', array('cmid' => $cmid));
169
    }
170
 
171
    /**
172
     * Delete all subscribers for a given rule.
173
     *
174
     * @param int $ruleid rule id.
175
     * @param \context|null $coursecontext the context of the course - this is passed when we
176
     *      can not get the context via \context_course as the course has been deleted.
177
     *
178
     * @return bool
179
     */
180
    public static function remove_all_subscriptions_for_rule($ruleid, $coursecontext = null) {
181
        global $DB;
182
 
183
        // Store all the subscriptions we have to delete.
184
        $subscriptions = $DB->get_recordset('tool_monitor_subscriptions', array('ruleid' => $ruleid));
185
 
186
        // Now delete them.
187
        $success = $DB->delete_records('tool_monitor_subscriptions', array('ruleid' => $ruleid));
188
 
189
        // If successful and there were subscriptions that were deleted trigger a subscription deleted event.
190
        if ($success && $subscriptions) {
191
            foreach ($subscriptions as $subscription) {
192
                // It is possible that we are deleting rules associated with a deleted course, so we should be
193
                // passing the context as the second parameter.
194
                if (!is_null($coursecontext)) {
195
                    $context = $coursecontext;
196
                    $courseid = $subscription->courseid;
197
                } else if (!empty($subscription->courseid) && ($context =
198
                        \context_course::instance($subscription->courseid, IGNORE_MISSING))) {
199
                    $courseid = $subscription->courseid;
200
                } else {
201
                    $courseid = 0;
202
                    $context = \context_system::instance();
203
                }
204
 
205
                $params = array(
206
                    'objectid' => $subscription->id,
207
                    'courseid' => $courseid,
208
                    'context' => $context
209
                );
210
                $event = \tool_monitor\event\subscription_deleted::create($params);
211
                $event->add_record_snapshot('tool_monitor_subscriptions', $subscription);
212
                $event->trigger();
213
 
214
                // Let's invalidate the cache.
215
                $cache = \cache::make('tool_monitor', 'eventsubscriptions');
216
                $cache->delete($courseid);
217
            }
218
        }
219
 
220
        $subscriptions->close();
221
 
222
        return $success;
223
    }
224
 
225
    /**
226
     * Delete all subscriptions in a course.
227
     *
228
     * This is called after a course was deleted, context no longer exists but we kept the object
229
     *
230
     * @param \context_course $coursecontext the context of the course
231
     */
232
    public static function remove_all_subscriptions_in_course($coursecontext) {
233
        global $DB;
234
 
235
        // Store all the subscriptions we have to delete.
236
        if ($subscriptions = $DB->get_records('tool_monitor_subscriptions', ['courseid' => $coursecontext->instanceid])) {
237
            // Delete subscriptions in bulk.
238
            $DB->delete_records('tool_monitor_subscriptions', ['courseid' => $coursecontext->instanceid]);
239
 
240
            // Trigger events one by one.
241
            foreach ($subscriptions as $subscription) {
242
                $params = ['objectid' => $subscription->id, 'context' => $coursecontext];
243
                $event = \tool_monitor\event\subscription_deleted::create($params);
244
                $event->add_record_snapshot('tool_monitor_subscriptions', $subscription);
245
                $event->trigger();
246
            }
247
        }
248
    }
249
 
250
    /**
251
     * Get a subscription instance for an given subscription id.
252
     *
253
     * @param subscription|int $subscriptionorid an instance of subscription class or id.
254
     *
255
     * @return subscription returns a instance of subscription class.
256
     */
257
    public static function get_subscription($subscriptionorid) {
258
        global $DB;
259
 
260
        if (is_object($subscriptionorid)) {
261
            return new subscription($subscriptionorid);
262
        }
263
 
264
        $sql = self::get_subscription_join_rule_sql();
265
        $sql .= "WHERE s.id = :id";
266
        $sub = $DB->get_record_sql($sql, array('id' => $subscriptionorid), MUST_EXIST);
267
        return new subscription($sub);
268
    }
269
 
270
    /**
271
     * Get an array of subscriptions for a given user in a given course.
272
     *
273
     * @param int $courseid course id.
274
     * @param int $limitfrom Limit from which to fetch rules.
275
     * @param int $limitto  Limit to which rules need to be fetched.
276
     * @param int $userid Id of the user for which the subscription needs to be fetched. Defaults to $USER;
277
     * @param string $order Order to sort the subscriptions.
278
     *
279
     * @return array list of subscriptions
280
     */
281
    public static function get_user_subscriptions_for_course($courseid, $limitfrom = 0, $limitto = 0, $userid = 0,
282
            $order = 's.timecreated DESC' ) {
283
        global $DB, $USER;
284
        if ($userid == 0) {
285
            $userid = $USER->id;
286
        }
287
        $sql = self::get_subscription_join_rule_sql();
288
        $sql .= "WHERE s.courseid = :courseid AND s.userid = :userid ORDER BY $order";
289
 
290
        return self::get_instances($DB->get_records_sql($sql, array('courseid' => $courseid, 'userid' => $userid), $limitfrom,
291
                $limitto));
292
    }
293
 
294
    /**
295
     * Get count of subscriptions for a given user in a given course.
296
     *
297
     * @param int $courseid course id.
298
     * @param int $userid Id of the user for which the subscription needs to be fetched. Defaults to $USER;
299
     *
300
     * @return int number of subscriptions
301
     */
302
    public static function count_user_subscriptions_for_course($courseid, $userid = 0) {
303
        global $DB, $USER;
304
        if ($userid == 0) {
305
            $userid = $USER->id;
306
        }
307
        $sql = self::get_subscription_join_rule_sql(true);
308
        $sql .= "WHERE s.courseid = :courseid AND s.userid = :userid";
309
 
310
        return $DB->count_records_sql($sql, array('courseid' => $courseid, 'userid' => $userid));
311
    }
312
 
313
    /**
314
     * Get an array of subscriptions for a given user.
315
     *
316
     * @param int $limitfrom Limit from which to fetch rules.
317
     * @param int $limitto  Limit to which rules need to be fetched.
318
     * @param int $userid Id of the user for which the subscription needs to be fetched. Defaults to $USER;
319
     * @param string $order Order to sort the subscriptions.
320
     *
321
     * @return array list of subscriptions
322
     */
323
    public static function get_user_subscriptions($limitfrom = 0, $limitto = 0, $userid = 0,
324
                                                             $order = 's.courseid ASC, r.name' ) {
325
        global $DB, $USER;
326
        if ($userid == 0) {
327
            $userid = $USER->id;
328
        }
329
        $sql = self::get_subscription_join_rule_sql();
330
        $sql .= "WHERE s.userid = :userid ORDER BY $order";
331
 
332
        return self::get_instances($DB->get_records_sql($sql, array('userid' => $userid), $limitfrom, $limitto));
333
    }
334
 
335
    /**
336
     * Get count of subscriptions for a given user.
337
     *
338
     * @param int $userid Id of the user for which the subscription needs to be fetched. Defaults to $USER;
339
     *
340
     * @return int number of subscriptions
341
     */
342
    public static function count_user_subscriptions($userid = 0) {
343
        global $DB, $USER;;
344
        if ($userid == 0) {
345
            $userid = $USER->id;
346
        }
347
        $sql = self::get_subscription_join_rule_sql(true);
348
        $sql .= "WHERE s.userid = :userid";
349
 
350
        return $DB->count_records_sql($sql, array('userid' => $userid));
351
    }
352
 
353
    /**
354
     * Return a list of subscriptions for a given event.
355
     *
356
     * @param \stdClass $event the event object.
357
     *
358
     * @return array
359
     */
360
    public static function get_subscriptions_by_event(\stdClass $event) {
361
        global $DB;
362
 
363
        $sql = self::get_subscription_join_rule_sql();
364
        if ($event->contextlevel == CONTEXT_MODULE && $event->contextinstanceid != 0) {
365
            $sql .= "WHERE r.eventname = :eventname AND s.courseid = :courseid AND (s.cmid = :cmid OR s.cmid = 0)";
366
            $params = array('eventname' => $event->eventname, 'courseid' => $event->courseid, 'cmid' => $event->contextinstanceid);
367
        } else {
368
            $sql .= "WHERE r.eventname = :eventname AND (s.courseid = :courseid OR s.courseid = 0)";
369
            $params = array('eventname' => $event->eventname, 'courseid' => $event->courseid);
370
        }
371
        return self::get_instances($DB->get_records_sql($sql, $params));
372
    }
373
 
374
    /**
375
     * Return sql to join rule and subscription table.
376
     *
377
     * @param bool $count Weather if this is a count query or not.
378
     *
379
     * @return string the sql.
380
     */
381
    protected static function get_subscription_join_rule_sql($count = false) {
382
        if ($count) {
383
            $select = "SELECT COUNT(s.id) ";
384
        } else {
385
            $select = "SELECT s.*, r.description, r.descriptionformat, r.name, r.userid as ruleuserid, r.courseid as rulecourseid,
386
            r.plugin, r.eventname, r.template, r.templateformat, r.frequency, r.timewindow";
387
        }
388
        $sql = $select . "
389
                  FROM {tool_monitor_rules} r
390
                  JOIN {tool_monitor_subscriptions} s
391
                        ON r.id = s.ruleid ";
392
        return $sql;
393
    }
394
 
395
    /**
396
     * Helper method to convert db records to instances.
397
     *
398
     * @param array $arr of subscriptions.
399
     *
400
     * @return array of subscriptions as instances.
401
     */
402
    protected static function get_instances($arr) {
403
        $result = array();
404
        foreach ($arr as $key => $sub) {
405
            $result[$key] = new subscription($sub);
406
        }
407
        return $result;
408
    }
409
 
410
    /**
411
     * Get count of subscriptions for a given rule.
412
     *
413
     * @param int $ruleid rule id of the subscription.
414
     *
415
     * @return int number of subscriptions
416
     */
417
    public static function count_rule_subscriptions($ruleid) {
418
        global $DB;
419
        $sql = self::get_subscription_join_rule_sql(true);
420
        $sql .= "WHERE s.ruleid = :ruleid";
421
 
422
        return $DB->count_records_sql($sql, array('ruleid' => $ruleid));
423
    }
424
 
425
    /**
426
     * Returns true if an event in a particular course has a subscription.
427
     *
428
     * @param string $eventname the name of the event
429
     * @param int $courseid the course id
430
     * @return bool returns true if the event has subscriptions in a given course, false otherwise.
431
     */
432
    public static function event_has_subscriptions($eventname, $courseid) {
433
        global $DB;
434
 
435
        // Check if we can return these from cache.
436
        $cache = \cache::make('tool_monitor', 'eventsubscriptions');
437
 
438
        // The SQL we will be using to fill the cache if it is empty.
439
        $sql = "SELECT DISTINCT(r.eventname)
440
                  FROM {tool_monitor_subscriptions} s
441
            INNER JOIN {tool_monitor_rules} r
442
                    ON s.ruleid = r.id
443
                 WHERE s.courseid = :courseid";
444
 
445
        $sitesubscriptions = $cache->get(0);
446
        // If we do not have the site subscriptions in the cache then return them from the DB.
447
        if ($sitesubscriptions === false) {
448
            // Set the array for the cache.
449
            $sitesubscriptions = array();
450
            if ($subscriptions = $DB->get_records_sql($sql, array('courseid' => 0))) {
451
                foreach ($subscriptions as $subscription) {
452
                    $sitesubscriptions[$subscription->eventname] = true;
453
                }
454
            }
455
            $cache->set(0, $sitesubscriptions);
456
        }
457
 
458
        // Check if a subscription exists for this event site wide.
459
        if (isset($sitesubscriptions[$eventname])) {
460
            return true;
461
        }
462
 
463
        // If the course id is for the site, and we reached here then there is no site wide subscription for this event.
464
        if (empty($courseid)) {
465
            return false;
466
        }
467
 
468
        $coursesubscriptions = $cache->get($courseid);
469
        // If we do not have the course subscriptions in the cache then return them from the DB.
470
        if ($coursesubscriptions === false) {
471
            // Set the array for the cache.
472
            $coursesubscriptions = array();
473
            if ($subscriptions = $DB->get_records_sql($sql, array('courseid' => $courseid))) {
474
                foreach ($subscriptions as $subscription) {
475
                    $coursesubscriptions[$subscription->eventname] = true;
476
                }
477
            }
478
            $cache->set($courseid, $coursesubscriptions);
479
        }
480
 
481
        // Check if a subscription exists for this event in this course.
482
        if (isset($coursesubscriptions[$eventname])) {
483
            return true;
484
        }
485
 
486
        return false;
487
    }
488
 
489
    /**
490
     * Activates a group of subscriptions based on an input array of ids.
491
     *
492
     * @since 3.2.0
493
     * @param array $ids of subscription ids.
494
     * @return bool true if the operation was successful, false otherwise.
495
     */
496
    public static function activate_subscriptions(array $ids) {
497
        global $DB;
498
        if (!empty($ids)) {
499
            list($sql, $params) = $DB->get_in_or_equal($ids);
500
            $success = $DB->set_field_select('tool_monitor_subscriptions', 'inactivedate', '0', 'id ' . $sql, $params);
501
            return $success;
502
        }
503
        return false;
504
    }
505
 
506
    /**
507
     * Deactivates a group of subscriptions based on an input array of ids.
508
     *
509
     * @since 3.2.0
510
     * @param array $ids of subscription ids.
511
     * @return bool true if the operation was successful, false otherwise.
512
     */
513
    public static function deactivate_subscriptions(array $ids) {
514
        global $DB;
515
        if (!empty($ids)) {
516
            $inactivedate = time();
517
            list($sql, $params) = $DB->get_in_or_equal($ids);
518
            $success = $DB->set_field_select('tool_monitor_subscriptions', 'inactivedate', $inactivedate, 'id ' . $sql,
519
                                             $params);
520
            return $success;
521
        }
522
        return false;
523
    }
524
 
525
    /**
526
     * Deletes subscriptions which have been inactive for a period of time.
527
     *
528
     * @since 3.2.0
529
     * @param int $userid if provided, only this user's stale subscriptions will be deleted.
530
     * @return bool true if the operation was successful, false otherwise.
531
     */
532
    public static function delete_stale_subscriptions($userid = 0) {
533
        global $DB;
534
        // Get the expiry duration, in days.
535
        $cutofftime = strtotime("-" . self::INACTIVE_SUBSCRIPTION_LIFESPAN_IN_DAYS . " days", time());
536
 
537
        if (!empty($userid)) {
538
            // Remove any stale subscriptions for the desired user only.
539
            $success = $DB->delete_records_select('tool_monitor_subscriptions',
540
                                                  'userid = ? AND inactivedate < ? AND inactivedate <> 0',
541
                                                  array($userid, $cutofftime));
542
 
543
        } else {
544
            // Remove all stale subscriptions.
545
            $success = $DB->delete_records_select('tool_monitor_subscriptions',
546
                                                  'inactivedate < ? AND inactivedate <> 0',
547
                                                  array($cutofftime));
548
        }
549
        return $success;
550
    }
551
 
552
    /**
553
     * Check whether a subscription is active.
554
     *
555
     * @since 3.2.0
556
     * @param \tool_monitor\subscription $subscription instance.
557
     * @return bool true if the subscription is active, false otherwise.
558
     */
559
    public static function subscription_is_active(subscription $subscription) {
560
        return empty($subscription->inactivedate);
561
    }
562
}