activity.php 21.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php
/**
 * This program is part of Mahara
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 *
 * @package    mahara
 * @subpackage core
 * @author     Penny Leach <penny@catalyst.net.nz>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
 * @copyright  (C) 2006,2007 Catalyst IT Ltd http://catalyst.net.nz
 *
 */

defined('INTERNAL') || die();

/**
 * This is the function to call whenever anything happens
 * that is going to end up on a user's activity page.
 * 
 * @param string $activitytype type of activity
 * @param mixed $data data 
 */
36
function activity_occurred($activitytype, $data) {
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
    if (!$at = get_record('activity_type', 'name', $activitytype)) {
        throw new Exception("Invalid activity type $activitytype");
    }

    if (!empty($at->delay)) {
        $delayed = new StdClass;
        $delayed->type = $activitytype;
        $delayed->data = serialize($data);
        $delayed->ctime = db_format_timestamp(time());
        insert_record('activity_queue', $delayed);
    }
    else {
        handle_activity($at, $data);
    }
}

/** 
 * This function dispatches all the activity stuff
 * to whatever notification plugin it needs to
 * and figures out all the implications of 
 * activity and who needs to know about it.
 * 
 * @param object $activitytype record from activity_type
60
61
62
 * @param mixed $data must contain message to save.
 * it can also contain url.
 * each activity type has different requirements of $data - 
63
64
65
66
67
68
69
70
71
72
73
74
75
76
 *  - <b>contactus</b> must contain $message, $subject (optional), $fromname, $fromaddress, $userfrom (if a logged in user)
 *  - <b>objectionable</b> must contain $message, $view and $artefact if applicable
 *  - <b>maharamessage</b> must contain $users, an array of userids. $subject and $message (contents of message)
 *  - <b>usermessage</b> must contain $userto, id of recipient user, $userfrom, id of user from 
    -       and $subject and $message (contents of message)
 *  - <b>feedback (artefact)</b> must contain both $artefact (id) and $view (id) and $message 
 *  - <b>feedback (view)</b> must contain $view (id) and $message
 *  - <b>watchlist (artefact)</b> must contain $artefact (id of artefact) 
 *  -       and should also contain $subject (or a boring default will be used)
 *  - <b>watchlist (view) </b> must contain $view (id of view) 
    -       and should also contain $subject (or a boring default will be used)
 *  - <b>watchlist (community) </b> must contain $community (id of community)
    -       and should also contain $subject (or a boring default will be used)
 *  - <b>newview</b> must contain $owner userid of view owner AND $view (id of new view)
77
78
79
 */
function handle_activity($activitytype, $data) {

80
    $data = (object)$data;
81
82
83
84
    if (is_string($activitytype)) {
        $activitytype = get_record('activity_type', 'name', $activitytype);
    }
    
85

86
87
88
89
    if (!is_object($activitytype)) {
        throw new InvalidArgumentException("Invalid activitytype $activitytype");
    }

90
91
92
93
94
    $users = array();
    $prefix = get_config('dbprefix');

    if (!empty($activitytype->admin)) {
        $users = activity_get_users($activitytype->name, null, null, true);
95
96
97
98
99
100
        // validation stuff
        switch ($activitytype->name) {
            case 'contactus':
                if (empty($data->message)) {
                    throw new InvalidArgumentException("Message was empty for activity type contactus");
                }
101
                $data->subject = get_string('newcontactusfrom', 'activity') . ' ' .$data->fromname 
102
103
104
105
106
107
108
109
                    . '<' . $data->fromemail .'>' . (isset($data->subject) ? ': ' . $data->subject : '');
                $data->message = $data->subject . "\n\n" . $data->message;
                $data->subject = get_string('newcontactus', 'activity');
                if (!empty($data->userfrom)) {
                    $data->url = get_config('wwwroot') . 'user/view.php?id=' . $data->userfrom;
                }
                break;
            case 'objectionable':
110
111
112
113
114
115
116
117
118
119
                if (empty($data->view)) {
                    throw new InvalidArgumentException("Objectionable content requires an id of a view");
                }
                if (empty($data->message)) {
                    throw new InvalidArgumentException("Objectionable content requires a message");
                }
                if (!$viewtitle = get_field('view', 'title', 'id', $data->view)) {
                    throw new InvalidArgumentException("Couldn't find view with id " . $data->view);
                }
                if (empty($data->artefact)) {
120
                    $data->url = get_config('wwwroot') . 'view/view.php?view=' . $data->view;
121
                    $data->subject = get_string('objectionablecontentview', 'activity') 
Penny Leach's avatar
Penny Leach committed
122
                        . ' ' . get_string('onview', 'activity') . $viewtitle;
123
124
                }
                else {
125
                    $data->url = get_config('wwwroot') . 'view/view.php?artefact=' . $data->artefact . '&view=' . $data->view;
126
127
128
129
130
131
                    if (!$artefacttitle = get_field('artefact', 'title', 'id', $data->artefact)) {
                        throw new InvalidArgumentException("Couldn't find artefact with id " . $data->view);
                    }
                    $data->subject = get_string('objectionablecontentartefact', 'activity') 
                        . ' '  . get_string('onartefact', 'activity') . ' ' . $artefacttitle;
                }
132
133
                break;
            case 'virusrepeat':
134
135
136
                $userstring = $data->username . ' (' . $data->fullname . ') (userid:' . $data->userid . ')' ;
                $data->subject = get_string('virusrepeatsubject', 'mahara', $userstring);
                $data->message = get_string('virusrepeatmessage');
137
138
139
140
                break;
            case 'virusrelease':
                break;
        }
141
142
143
144
145
    }
    else {
        switch ($activitytype->name) {
            // easy ones first :)
            case 'maharamessage':
146
147
148
149
150
151
152
153
154
                if (!is_array($data->users) || empty($data->users)) {
                    throw new InvalidArgumentException("Mahara message activity type expects an array of users");
                }
                if (empty($data->subject)) {
                    throw new InvalidArgumentException("Mahara message activity type expects a subject");
                }
                if (empty($data->message)) {
                    throw new InvalidArgumentException("Mahara message activity type expects a message");
                }
155
                $users = activity_get_users($activitytype->name, $data->users);
156
157
                break;
            case 'usermessage':
158
159
160
161
162
163
164
165
166
                if (!is_numeric($data->userto) || !is_numeric($data->userfrom)) {
                    throw new InvalidArgumentException("User message requires userto and userfrom to be set");
                }
                if (empty($data->subject)) {
                    throw new InvalidArgumentException("User message activity type expects a subject");
                }
                if (empty($data->message)) {
                    throw new InvalidArgumentException("User message activity type expects a message");
                }
167
                $users = activity_get_users($activitytype->name, array($data->userto));
Penny Leach's avatar
Penny Leach committed
168
169
170
171
                if (empty($data->url)) {
                    // @todo when user messaging is implemented, this might change... 
                    $data->url = get_config('wwwroot') . 'user/view.php?id=' . $data->userfrom;
                }
172
173
                break;
            case 'feedback':
174
175
176
                if (empty($data->message)) {
                    throw new InvalidArgumentException("Feedbackactivity type expects a message");
                }
Penny Leach's avatar
Penny Leach committed
177
                if (empty($data->view)) {
178
                    throw new InvalidArgumentException("Feedback missing view id");
Penny Leach's avatar
Penny Leach committed
179
                }
180
                if (!empty($data->artefact)) { // feedback on artefact
181
                    $data->subject = get_string('newfeedbackonartefact', 'activity');
182
183
184
                    if (!$artefact = get_record('artefact', 'id', $data->artefact)) {
                        throw new InvalidArgumentException("Couldn't find artefact with id "  . $data->artefact);
                    }
185
                    $userid = $artefact->owner;
186
                    $data->subject .= ' ' .$artefact->title;
Penny Leach's avatar
Penny Leach committed
187
188
                    if (empty($data->url)) {
                        // @todo this might change later
189
                        $data->url = get_config('wwwroot') . 'view/view.php?artefact=' 
190
                            . $data->artefact . '&view=' . $data->view;
Penny Leach's avatar
Penny Leach committed
191
                    }
192
                } 
193
                else { // feedback on view.
194
                    $data->subject = get_string('newfeedbackonview', 'activity');
195
196
197
                    if (!$view = get_record('view', 'id', $data->view)) {
                        throw new InvalidArgumentException("Couldn't find view with id " . $data->view);
                    }
198
                    $userid = $view->owner;
199
                    $data->subject .= ' ' .$view->title;
Penny Leach's avatar
Penny Leach committed
200
201
                    if (empty($data->url)) {
                        // @todo this might change later
202
                        $data->url = get_config('wwwroot') . 'view/view.php?view=' . $data->view;
Penny Leach's avatar
Penny Leach committed
203
                    }
204
205
206
207
208
                }
                $users = activity_get_users($activitytype->name, array($userid));
                break;
            // and now the harder ones
            case 'watchlist':
209
                if (!empty($data->view)) {
210
211
212
213
                    if (empty($data->subject)) {
                        throw new InvalidArgumentException("subject must be provided for watchlist view");
                    }
                    $oldsubject = isset($data->subject) ? $data->subject : '';
214
                    $data->subject = get_string('watchlistmessageview', 'activity');
215
216
217
218
219
                    if (!$viewinfo = get_record_sql('SELECT u.*, v.title FROM ' . $prefix . 'usr u
                                                     JOIN ' . $prefix . 'view v ON v.owner = u.id
                                                     WHERE v.id = ?', array($data->view))) {
                        throw new InvalidArgumentException("Couldn't find view with id " . $data->view);
                    }
220
221
                    $data->message = $oldsubject . ' ' . get_string('onview', 'activity') 
                        . ' ' . $viewinfo->title . ' ' . get_string('ownedby', 'activity');
Penny Leach's avatar
Penny Leach committed
222
                    $sql = 'SELECT u.*, p.method, CAST(? AS TEXT)  AS url
223
                                FROM ' . $prefix . 'usr_watchlist_view wv
224
                                JOIN ' . $prefix . 'usr u
Penny Leach's avatar
Penny Leach committed
225
                                    ON wv.usr = u.id
226
                                LEFT JOIN ' . $prefix . 'usr_activity_preference p
227
                                    ON p.usr = u.id
228
                                WHERE (p.activity = ? OR p.activity IS NULL)
229
230
                                AND wv.view = ?
                           ';
231
                    $users = get_records_sql_array($sql, 
232
                                                   array(get_config('wwwroot') . 'view/view.php?view=' 
233
                                                         . $data->view, 'watchlist', $data->view));
234
235
236
                    if (empty($users)) {
                        $users = array();
                    }
237
238
                    // ick
                    foreach ($users as $user) {
239
                        $user->message = $data->message . ' ' . display_name($viewinfo, $user);
240
                    }
241
                } 
242
                else if (!empty($data->artefact)) {
243
244
                    $data->subject = get_string('watchlistmessageartefact', 'activity')
                        . (isset($data->subject) ? ': ' . $data->subject : '');
245
246
247
248
249
                    if (!$ainfo = get_record_sql('SELECT u.*, a.title FROM ' . $prefix . 'usr u
                                                  JOIN ' . $prefix . 'artefact a  ON a.owner = u.id
                                                  WHERE a.id = ?', array($data->artefact))) {
                        throw new InvalidArgumentException("Couldn't find artefact with id " . $data->artefact);
                    }
250
                    $data->message = get_string('onartefact', 'activity') 
251
                        . ' ' . $ainfo->title . ' ' . get_string('ownedby', 'activity');
252
                    $sql = 'SELECT DISTINCT u.*, p.method, ?||wa.view as url
253
                                FROM ' . $prefix . 'usr_watchlist_artefact wa
254
                                LEFT JOIN ' . $prefix . 'artefact_parent_cache pc
255
256
                                    ON (pc.parent = wa.artefact OR pc.artefact = wa.artefact)
                                JOIN ' . $prefix . 'usr u 
257
                                    ON wa.usr = u.id
258
                                LEFT JOIN ' . $prefix . 'usr_activity_preference p
259
                                    ON p.usr = u.id
260
                                WHERE (p.activity = ? OR p.activity IS NULL)
261
262
                                AND (pc.parent = ? OR wa.artefact = ?)
                            ';
263
                    $users = get_records_sql_array($sql, 
264
                                                   array(get_config('wwwroot') . 'view/view.php?view=' 
265
                                                         . $data->artefact . '&view=', 'watchlist', 
266
                                                         $data->artefact, $data->artefact));
267
268
269
                    if (empty($users)) {
                        $users = array();
                    }
270
271
                    // ick
                    foreach ($users as $user) {
272
                        $user->message = $data->message . ' ' . display_name($ainfo, $user);
273
                    }
274
                }
275
                else if (!empty($data->community)) {
276
277
278
                    if (empty($data->subject)) {
                        throw new InvalidArgumentException("subject must be provided for watchlist community");
                    }
279
280
281
                    if (!$communityname = get_field('community', 'name', 'id', $data->community)) {
                        throw new InvalidArgumentException("Couldn't find community with id " . $data->community);
                    }
282
283
                    $oldsubject = $data->subject;
                    $data->subject = get_string('watchlistmessagecommunity', 'activity');
284
                    $data->message = $oldsubject . ' ' . get_string('oncommunity', 'activity') . ' ' . $communityname;
Penny Leach's avatar
Penny Leach committed
285
                    $sql = 'SELECT DISTINCT u.*, p.method, CAST(? AS TEXT) AS url
286
287
288
                                FROM ' . $prefix . 'usr_watchlist_community c
                                JOIN ' . $prefix . 'usr u
                                    ON c.usr = u.id
289
                                LEFT JOIN ' . $prefix . 'usr_activity_preference p
290
                                    ON p.usr = u.id
291
                                WHERE (p.activity = ? OR p.activity IS NULL)
292
293
                                AND c.community = ?
                            ';
294
                    $users = get_records_sql_array($sql, 
295
                                                   array(get_config('wwwroot') . 'contacts/communities/view.php?id='
296
                                                         . $data->community, 'watchlist', $data->community));
297
                }
298
299
300
301
302
                else {
                    throw new InvalidArgumentException("Invalid watchlist type");
                }
                break;
            case 'newview':
303
304
305
                if (!is_numeric($data->owner) || !is_numeric($data->view)) {
                    throw new InvalidArgumentException("New view activity type requires view and owner to be set");
                }
306
                if (!$viewinfo = get_record_sql('SELECT u.*, v.title FROM ' . $prefix . 'usr u
307
                                                 JOIN ' . $prefix . 'view v ON v.owner = u.id
308
309
310
                                                 WHERE v.id = ?', array($data->view))) {
                    throw new InvalidArgumentException("Couldn't find view with id " . $data->view);
                }
311
312
313
                $data->message = get_string('newviewmessage', 'activity')
                    . ' ' . $viewinfo->title . ' ' . get_string('ownedby', 'activity');
                $data->subject = get_string('newviewsubject', 'activity');
314
315
316
317
318
319
320
321
                // add users on friendslist, userlist or grouplist...
                $sql = 'SELECT userid, u.*, p.method
                        FROM (
                            SELECT (CASE WHEN usr1 = ? THEN usr2 ELSE usr1 END) AS userid 
                                FROM ' . $prefix . 'usr_friend 
                                WHERE (usr1 = ? OR usr2 = ?)
                            UNION SELECT member AS userid 
                                FROM ' . $prefix . 'usr_group_member m
Penny Leach's avatar
Penny Leach committed
322
                                JOIN ' . $prefix . 'view_access_group g ON m.grp = g.grp 
323
324
325
326
327
328
                            WHERE g.view = ?
                            UNION SELECT usr AS userid 
                                  FROM ' . $prefix . 'view_access_usr u 
                                  WHERE u.view = ?
                        ) AS userlist
                            JOIN ' . $prefix . 'usr u ON u.id = userlist.userid
329
                            LEFT JOIN ' . $prefix . 'usr_activity_preference p ON p.usr = u.id';
330
                $users = get_records_sql_array($sql, array($data->owner, $data->owner, $data->owner,  
331
                                                     $data->view, $data->view));
332
333
334
                if (empty($users)) {
                    $users = array();
                }
335
336
                // ick
                foreach ($users as $user) {
337
                    $user->message = $data->message . ' ' . display_name($viewinfo, $user);
338
339
340
341
                }
                break;
            case 'contactus':
                
342
                break;
Penny Leach's avatar
Penny Leach committed
343
                // @todo more here (admin messages!)
344
345
        }
    }
346
347
348
    if (empty($users)) {
        return;
    }
349
    safe_require('notification', 'internal', 'lib.php', 'require_once');
350
    $data->type = $activitytype->name;
351
    foreach ($users as $user) {
352
353
354
355
356
357
358
359
360
361
        $userdata = $data;
        // some stuff gets overridden by user specific stuff
        if (!empty($user->url)) {
            $userdata->url = $user->url;
        }
        if (!empty($user->message)) {
            $userdata->message = $user->message;
        }
        if (!empty($user->subject)) {
            $userdata->subject = $user->subject;
362
        }
363
364
365
        if (empty($user->method)) {
            $user->method = 'internal';
        }
366
367
        if ($user->method != 'internal') {
            safe_require('notification', $method, 'lib.php', 'require_once');
368
            call_static_method(generate_class_name('notification', $method), 'notify_user', $user, $userdata);
369
            $user->markasread = true; // if we're doing something else, don't generate unread internal ones.
370
371
        }
        // always do internal
372
        call_static_method('PluginNotificationInternal', 'notify_user', $user, $userdata);
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
    }
}

/**
 * this function returns an array of users
 * for a particular activitytype
 * including the notification method.
 *
 * @param string $activitytype the name of the activity type
 * @param array $userids an array of userids to filter by
 * @param array $userobjs an array of user objects to filterby
 * @param bool $adminonly whether to filter by admin flag
 * @return array of users
 */
function activity_get_users($activitytype, $userids=null, $userobjs=null, $adminonly=false) {
    $values = array($activitytype);
    $sql = 'SELECT u.*, p.method
                FROM ' . get_config('dbprefix') .'usr u
391
                LEFT JOIN ' . get_config('dbprefix') . 'usr_activity_preference p
392
                    ON p.usr = u.id
393
                WHERE (p.activity = ? ' . (empty($adminonly) ? ' OR p.activity IS NULL' : '') . ')';
394
395
396
397
398
399
400
401
402
403
404
405
    if (!empty($adminonly)) {
        $sql .= ' AND u.admin = ? ';
        $values[] = 1;
    }
    if (!empty($userobjs) && is_array($userobjs)) {
        $sql .= ' AND u.id IN (' . implode(',',db_array_to_ph($userobjs)) . ')';
        $values = array_merge($values, array_to_fields($userobjs));
    } 
    else if (!empty($userids) && is_array($userids)) {
        $sql .= ' AND u.id IN (' . implode(',',db_array_to_ph($userids)) . ')';
        $values = array_merge($values, $userids);
    }
406
    return get_records_sql_array($sql, $values);
407
408
}

409
410
411
412
413
414
415
416
417
418
419
420
/**
 * this function inserts a default set of activity preferences for a given user
 * id
 */
function activity_set_defaults($user_id) {
    $activitytypes = get_records_array('activity_type', 'admin', 0);
    foreach ($activitytypes as $type) {
        $USER->set_activity_preference($type->name, 'internal');
    }
    
}

421
422

?>