group.php 17.6 KB
Newer Older
1
2
<?php
/**
Francois Marier's avatar
Francois Marier committed
3
 * Mahara: Electronic portfolio, weblog, resume builder and social networking
4
 * Copyright (C) 2006-2008 Catalyst IT Ltd (http://www.catalyst.net.nz)
5
 *
Francois Marier's avatar
Francois Marier committed
6
7
8
9
 * 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 3 of the License, or
 * (at your option) any later version.
10
 *
Francois Marier's avatar
Francois Marier committed
11
12
13
14
 * 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.
15
 *
Francois Marier's avatar
Francois Marier committed
16
17
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19
20
 *
 * @package    mahara
 * @subpackage core
21
 * @author     Catalyst IT Ltd
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
23
 * @copyright  (C) 2006-2008 Catalyst IT Ltd http://catalyst.net.nz
24
25
26
27
28
29
30
 *
 */

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


/**
31
 * is a user allowed to leave a group? 
32
33
 * checks if they're the owner and the membership type
 *
34
 * @param object $group (corresponds to db record). if an id is given, record will be fetched.
35
36
 * @param int $userid (optional, will default to logged in user)
 */
37
function group_user_can_leave($group, $userid=null) {
38
39

    $userid = optional_userid($userid);
40
    
41
    if (is_numeric($group)) {
42
        if (!$group = get_record('group', 'id', $group, 'deleted', 0)) {
43
44
45
46
            return false;
        }
    }
    
47
    // TODO: disallow users from leaving if they are the only administrator in the group
48
    
49
    if ($group->jointype == 'controlled') {
50
51
52
53
54
55
        return false;
    }
    return true;
}

/**
56
 * removes a user from a group
Clare Lenihan's avatar
Clare Lenihan committed
57
 * removed view access given by the user to the group
58
 *
59
 * @param int $group id of group
60
61
 * @param int $user id of user to remove
 */
62
function group_remove_user($group, $userid) {    
63
    db_begin();
64
    delete_records('group_member', 'group', $group, 'member', $userid);
65
    delete_records_sql(
66
67
68
        'DELETE FROM {view_access_group}
        WHERE "group" = ?
        AND view IN (
69
70
71
72
73
74
            SELECT v.id
            FROM {view} v
            WHERE v.owner = ?
        )',
        array($group, $userid)
    );
75
    db_commit();
76
77
78
79
80
81

    require_once(get_config('docroot') . 'interaction/lib.php');
    $interactions = get_column('interaction_instance', 'id', 'group', $group);
    foreach ($interactions as $interaction) {
        interaction_instance_from_id($interaction)->interaction_remove_user($userid);
    }
82
83
84
}

/**
85
 * all groups the user is a member of
86
87
 * 
 * @param int userid (optional, defaults to $USER id) 
88
 * @return array of group db rows
89
 */
90
function get_member_groups($userid=0, $offset=0, $limit=0) {
91

92
93
    $userid = optional_userid($userid);

94
    return get_records_sql_array('SELECT g.id, g.name, g.description, g.jointype, g.owner, g.ctime, g.mtime, gm.ctime, gm.tutor, COUNT(v.view) AS hasviews
95
96
97
              FROM {group} g 
              JOIN {group_member} gm ON gm.group = g.id
              LEFT JOIN {view_access_group} v ON v.group = g.id
98
99
              WHERE g.owner != ? AND gm.member = ? AND g.deleted = ?
              GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9', array($userid, $userid, 0), $offset, $limit);
100
101
102
}


103
/**
104
 * all groups the user owns
105
106
 * 
 * @param int userid (optional, defaults to $USER id) 
107
 * @param string $jointype (optional), will filter by jointype.
108
 * @return array of group db rows
109
 */
110
function get_owned_groups($userid=0, $jointype=null) {
111
112
113

    $userid = optional_userid($userid);

114
    // TODO: select groups where role in group is admin
115
    $sql = 'SELECT g.* FROM {group} g 
116
117
             WHERE g.deleted = ? LIMIT 1';
    $values = array(0);
118
119
120
121
122
123
124

    if (!empty($jointype)) {
        $sql .= ' AND jointype = ?';
        $values[] = $jointype;
    }
       
    return get_records_sql_array($sql, $values);
125
126
127
}

/**
128
 * all groups the user has pending invites to
129
130
 * 
 * @param int userid (optional, defaults to $USER id)
131
 * @return array of group db rows
132
 */
133
function get_invited_groups($userid=0) {
134
135
136

    $userid = optional_userid($userid);

137
    return get_records_sql_array('SELECT g.*, gmi.ctime, gmi.reason
138
139
             FROM {group} g 
             JOIN {group_member_invite} gmi ON gmi.group = g.id
140
             WHERE gmi.member = ? AND g.deleted = ?', array($userid, 0));
141
142
143
}

/**
144
 * all groups the user has pending requests for 
145
146
 * 
 * @param int $userid (optional, defaults to $USER id)
147
 * @return array of group db rows
148
149
 */

150
function get_requested_group($userid=0) {
151
152
153

    $userid = optional_userid($userid);

154
    return get_records_sql_array('SELECT g.*, gmr.ctime, gmr.reason 
155
              FROM {group} g 
156
              JOIN {group_member_request} gmr ON gmr.group = g.id
157
              WHERE gmr.member = ? AND g.deleted = ?', array($userid, 0));
158
159
}

160
/**
161
 * all groups this user is associated with at all
162
163
164
 * either member, invited or requested.
 * 
 * @param int $userid (optional, defaults to $USER id)
165
 * @param boolean $all (optional defaults to true) whether to include requested and invited groups
166
 * @return array of group db rows (with type=member|invite|request)
167
168
 */

169
function get_associated_groups($userid=0, $all=true) {
170
171
172

    $userid = optional_userid($userid);
    
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
    if (!$all) {
        $sql = "SELECT g.*, a.type FROM {group} g JOIN (
        SELECT gm.group, 'member' AS type
            FROM {group_member} gm
            JOIN {group} ON owner != ? AND id = gm.group
            WHERE gm.member = ? AND gm.tutor = 0
        UNION
        SELECT gm.group, 'member' AS type
            FROM {group_member} gm
            JOIN {group} ON owner != ? AND id = gm.group
            WHERE gm.member = ? AND gm.tutor = 1
        UNION
            SELECT g.id, 'owner' AS type
            FROM {group} g WHERE g.owner = ?
        ) AS a ON a.group = g.id
        WHERE g.deleted = 0
        ORDER BY g.name";
        return get_records_sql_assoc($sql, array($userid, $userid, $userid, $userid, $userid));
    }
192
    $sql = "SELECT g.*, a.type FROM {group} g JOIN (
193
    SELECT gm.group, 'invite' AS type
194
        FROM {group_member_invite} gm WHERE gm.member = ?
195
    UNION
196
    SELECT gm.group, 'request' AS type
197
        FROM {group_member_request} gm WHERE gm.member = ?
198
    UNION
199
    SELECT gm.group, 'member' AS type
200
201
202
        FROM {group_member} gm
        JOIN {group} ON owner != ? AND id = gm.group
        WHERE gm.member = ? AND gm.tutor = 0
203
    UNION
204
205
206
207
208
209
210
    SELECT gm.group, 'member' AS type
        FROM {group_member} gm
        JOIN {group} ON owner != ? AND id = gm.group
        WHERE gm.member = ? AND gm.tutor = 1
    UNION
    SELECT g.id, 'owner' AS type
        FROM {group} g WHERE g.owner = ?
211
    ) AS a ON a.group = g.id
212
213
    WHERE g.deleted = 0
    ORDER BY g.name";
214
    
215
    return get_records_sql_assoc($sql, array($userid, $userid, $userid, $userid, $userid, $userid, $userid));
216
217
218
219
}


/**
220
 * gets groups the user is a tutor in, or the user owns
221
222
223
224
 * 
 * @param int $userid (optional, defaults to $USER id)
 * @param string $jointype (optional, will filter by jointype
 */
225
function get_tutor_groups($userid=0, $jointype=null) {
226
227
228

    $userid = optional_userid($userid);

229
    $sql = 'SELECT DISTINCT g.*, gm.ctime
230
231
              FROM {group} g 
              LEFT JOIN {group_member} gm ON gm.group = g.id
Clare Lenihan's avatar
Clare Lenihan committed
232
              WHERE (g.owner = ? OR (gm.member = ? AND gm.tutor = ?)) AND g.deleted = ?';
233
    $values = array($userid, $userid, 1, 0);
234
235
    
    if (!empty($jointype)) {
236
        $sql .= ' AND g.jointype = ? ';
237
238
239
240
241
        $values[] = $jointype;
    }
    return get_records_sql_array($sql, $values);
}

242
243
244
245
246
247
// constants for group membership type
define('GROUP_MEMBERSHIP_ADMIN', 1);
define('GROUP_MEMBERSHIP_STAFF', 2);
define('GROUP_MEMBERSHIP_OWNER', 4);
define('GROUP_MEMBERSHIP_TUTOR', 8);
define('GROUP_MEMBERSHIP_MEMBER', 16);
248

249

250
/**
251
 * Can a user access a given group?
252
 * 
253
 * @param mixed $group id of group or db record (object)
254
255
256
257
 * @param mixed $user optional (object or id), defaults to logged in user
 *
 * @returns constant access level or FALSE
 */
258
function user_can_access_group($group, $user=null) {
259
    log_warn("user_can_access_group is deprecated: please use group_user_access instead");
260
261
262
263
264
265
266
267
268
269
270
271
272

    if (empty($userid)) {
        global $USER;
        $user = $USER;
    }
    else if (is_int($user)) {
        $user = get_user($user);
    }
    else if (is_object($user) && !$user instanceof User) {
        $user = get_user($user->get('id'));
    }

    if (!$user instanceof User) {
273
        throw new InvalidArgumentException("not useful user arg given to user_can_access_group: $user");
274
275
    }

276
    if (is_int($group)) {
277
        $group = get_record('group', 'id', $group, 'deleted', 0);
278
279
    }

280
281
    if (!is_object($group)) {
        throw new InvalidArgumentException("not useful group arg given to user_can_access_group: $group");
282
283
    }

284
    $membertypes = 0;
285
    // admins/staff/owners can do whatever tutors can do
286
    if ($user->get('admin')) {
287
        $membertypes = GROUP_MEMBERSHIP_ADMIN | GROUP_MEMBERSHIP_TUTOR;
288
    }
289
    if ($user->get('staff') || $user->is_institutional_admin() || $user->is_institutional_staff()) {
290
        $membertypes = $membertypes | GROUP_MEMBERSHIP_STAFF | GROUP_MEMBERSHIP_TUTOR;
291
    }
292
    if ($group->owner == $user->get('id')) {
293
        $membertypes = $membertypes | GROUP_MEMBERSHIP_OWNER | GROUP_MEMBERSHIP_TUTOR;
294
295
    }

296
    if (!$membership = get_record('group_member', 'group', $group->id, 'member', $user->get('id'))) {
297
        return $membertypes;
298
299
300
    }

    if ($membership->tutor) {
301
        $membertypes = $membertypes | GROUP_MEMBERSHIP_TUTOR;
302
303
    }
    
304
    return ($membertypes | GROUP_MEMBERSHIP_MEMBER);
305
306
}

307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
/**
 * Establishes what role a user has in a given group.
 *
 * If the user is not in the group, this returns false.
 *
 * @param mixed $groupid  ID of the group to check
 * @param mixed $userid   ID of the user to check. Defaults to the logged in 
 *                        user.
 * @return mixed          The role the user has in the group, or false if they 
 *                        have no role in the group
 */
function group_user_access($groupid, $userid=null) {
    // TODO: caching

    if (!is_int($groupid) || $groupid == 0) {
        throw new InvalidArgumentException("group_user_access: group argument appears to be invalid: $groupid");
    }

    if (is_null($userid)) {
        global $USER;
        $userid = (int)$USER->get('id');
    }

    if (!is_int($userid) || $userid == 0) {
        throw new InvalidArgumentException("group_user_access: user argument appears to be invalid: $userid");
    }

334
    return get_field('group_member', 'role', 'group', $groupid, 'member', $userid);
335
336
}

337
/**
338
 * function to add a member to a group
339
340
 * doesn't do any jointype checking, that should be handled by the caller
 *
341
 * @param int $groupid
342
343
 * @param int $userid
 */
344
function group_add_member($groupid, $userid) {
345
346
    $cm = new StdClass;
    $cm->member = $userid;
347
    $cm->group = $groupid;
348
349
    $cm->ctime =  db_format_timestamp(time());
    $cm->tutor = 0;
350
    insert_record('group_member', $cm);
Penny Leach's avatar
Penny Leach committed
351
    $user = optional_userobj($userid);
352
353
}

354
355
356
357
358
359
360
361
362
function group_has_members($groupid) {
    $sql = 'SELECT (
        (SELECT COUNT(*) FROM {group_member} WHERE "group" = ?)
        +
        (SELECT COUNT(*) FROM {group_member_request} WHERE "group" = ?)
    )';
    return count_records_sql($sql, array($groupid, $groupid));
}

363
364
365
366
function delete_group($groupid) {
    update_record('group', array('deleted' => 1), array('id' => $groupid));
}

367
/**
368
 * Sets up groups for display in mygroups.php and find.php
369
 *
370
371
372
373
 * @param array $groups    Initial group data, including the current user's 
 *                         membership type in each group. See mygroups.php for
 *                         the query to build this information.
 * @param string $returnto Where forms generated for display should be told to return to
374
 */
375
function group_prepare_usergroups_for_display($groups, $returnto='mygroups') {
376
377
378
    if (!$groups) {
        return;
    }
379
380
381
382
383

    // Retrieve a list of all the group admins, for placing in each $group object
    $groupadmins = array();
    $groupids = array_map(create_function('$a', 'return $a->id;'), $groups);
    if ($groupids) {
384
385
386
        $groupadmins = (array)get_records_sql_array('SELECT "group", member
            FROM {group_member}
            WHERE "group" IN (' . implode(',', db_array_to_ph($groupids)) . ")
387
            AND role = 'admin'", $groupids);
388
389
    }

390
391
    $i = 0;
    foreach ($groups as $group) {
392
393
394
395
396
397
        $group->admins = array();
        foreach ($groupadmins as $admin) {
            if ($admin->group == $group->id) {
                $group->admins[] = $admin->member;
            }
        }
398
        $group->description = str_shorten($group->description, 100, true);
399
        if ($group->membershiptype == 'member') {
400
401
402
403
404
405
406
407
408
            $group->canleave = group_user_can_leave($group->id);
        }
        else if ($group->jointype == 'open') {
            $group->groupjoin = pieform(array(
                'name' => 'joingroup' . $i++,
                'successcallback' => 'joingroup_submit',
                'elements' => array(
                    'join' => array(
                        'type' => 'submit',
Clare Lenihan's avatar
Clare Lenihan committed
409
                        'value' => get_string('joingroup', 'group')
410
411
412
413
414
415
416
417
                    ),
                    'group' => array(
                        'type' => 'hidden',
                        'value' => $group->id
                    )
                )
            ));
        }
418
        else if ($group->membershiptype == 'invite') {
419
420
421
422
423
424
425
           $group->invite = pieform(array(
               'name'     => 'invite' . $i++,
               'renderer' => 'oneline',
               'successcallback' => 'group_invite_submit',
               'elements' => array(
                    'accept' => array(
                        'type'  => 'submit',
Clare Lenihan's avatar
Clare Lenihan committed
426
                        'value' => get_string('acceptinvitegroup', 'group')
427
428
429
                    ),
                    'decline' => array(
                        'type'  => 'submit',
Clare Lenihan's avatar
Clare Lenihan committed
430
                        'value' => get_string('declineinvitegroup', 'group')
431
432
433
434
435
436
437
438
439
440
441
442
                    ),
                    'group' => array(
                        'type' => 'hidden',
                        'value' => $group->id
                    ),
                    'returnto' => array(
                        'type' => 'hidden',
                        'value' => $returnto
                    )
                )
            ));
        }
443
        else if ($group->membershiptype == 'admin' && $group->requests > 1) {
444
445
446
447
448
449
450
451
            $group->requests = array($group->requests);
        }
    }
}

function joingroup_submit(Pieform $form, $values) {
    global $SESSION, $USER;
    group_add_member($values['group'], $USER->get('id'));
Clare Lenihan's avatar
Clare Lenihan committed
452
    $SESSION->add_ok_msg(get_string('joinedgroup', 'group'));
453
454
455
456
457
458
459
460
461
    redirect('/group/view.php?id=' . $values['group']);
}

function group_invite_submit(Pieform $form, $values) {
    global $SESSION, $USER;
    if (get_record('group_member_invite', 'member', $USER->get('id'), 'group', $values['group'])) {
        delete_records('group_member_invite', 'group', $values['group'], 'member', $USER->get('id'));
        if (isset($values['accept'])) {
            group_add_member($values['group'], $USER->get('id'));
Clare Lenihan's avatar
Clare Lenihan committed
462
            $SESSION->add_ok_msg(get_string('groupinviteaccepted', 'group'));
463
464
465
            redirect('/group/view.php?id=' . $values['group']);
        }
        else {
Clare Lenihan's avatar
Clare Lenihan committed
466
            $SESSION->add_ok_msg(get_string('groupinvitedeclined', 'group'));
467
468
469
470
471
            redirect($values['returnto'] == 'find' ? '/group/find.php' : '/group/mygroups.php');
        }
    }
}

472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
function group_get_membersearch_data($group, $query, $offset, $limit) {
    $results = get_group_user_search_results($group, $query, $offset, $limit);

    $params = array();
    if (!empty($query)) {
        $params[] = 'query=' . $query;
    }
    $params[] = 'limit=' . $limit;
    $searchurl = get_config('wwwroot') . 'group/view.php?' . join('&amp;', $params);

    $smarty = smarty_core();
    $smarty->assign_by_ref('results', $results);
    $smarty->assign('searchurl', $searchurl);
    $smarty->assign('pagebaseurl', $searchurl);
    $html = $smarty->fetch('group/membersearchresults.tpl');

    $pagination = build_pagination(array(
        'id' => 'member_pagination',
        'class' => 'center',
        'url' => get_config('wwwroot') . 'group/view.php?id=' . $group,
        'count' => $results['count'],
        'limit' => $limit,
        'offset' => $offset,
        'datatable' => 'membersearchresults',
        'jsonscript' => 'group/membersearchresults.php',
        'firsttext' => '',
        'previoustext' => '',
        'nexttext' => '',
        'lasttext' => '',
        'numbersincludefirstlast' => false,
    ));

    return array($html, $pagination, $results['count'], $offset);
}

507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
/**
 * Where is the syntax error?
 */
abstract class GroupType {

    public static abstract function allowed_join_types();

    /**
     * Returns whether the currently logged in user can create a group of this 
     * grouptype
     */
    public static function can_be_created_by_user() {
        return true;
    }

522
    /**
523
     * Returns the roles this group type implements
524
     */
525
    public static abstract function get_roles();
526

527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
}

/**
 * Returns a list of available grouptypes
 */
function group_get_grouptypes() {
    static $grouptypes = null;

    if (is_null($grouptypes)) {
        $grouptypes = array();
        $grouptypedir = get_config('libroot') . 'grouptype/';

        if ($dh = opendir($grouptypedir)) {
            while (false !== ($file = readdir($dh))) {
                if (!preg_match('/^[a-zA-Z0-9-]+\.php$/', $file)) {
                    continue;
                }
                if (is_file("$grouptypedir$file")) {
                    $grouptypes[] = substr($file, 0, -4);
                }
            }
        }
    }

    return $grouptypes;
}

554
?>