Passed
Push — master ( 721f66...a5a5d7 )
by Julito
12:15
created

GroupManager::deleteGroup()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 73
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 23
nc 7
nop 2
dl 0
loc 73
rs 8.9297
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\Course;
6
use Chamilo\CoreBundle\Framework\Container;
7
use Chamilo\CourseBundle\Entity\CGroup;
8
use Chamilo\CourseBundle\Entity\CGroupCategory;
9
10
/**
11
 * This library contains some functions for group-management.
12
 *
13
 * @author Bart Mollet
14
 *
15
 * @todo Add $course_code parameter to all functions. So this GroupManager can
16
 * be used outside a session.
17
 */
18
class GroupManager
19
{
20
    /* DEFAULT_GROUP_CATEGORY:
21
    When group categories aren't available (platform-setting),
22
    all groups are created in this 'dummy'-category*/
23
    public const DEFAULT_GROUP_CATEGORY = 2;
24
25
    /**
26
     * infinite.
27
     */
28
    public const INFINITE = 99999;
29
    /**
30
     * No limit on the number of users in a group.
31
     */
32
    public const MEMBER_PER_GROUP_NO_LIMIT = 0;
33
    /**
34
     * No limit on the number of groups per user.
35
     */
36
    public const GROUP_PER_MEMBER_NO_LIMIT = 0;
37
    /**
38
     * The tools of a group can have 3 states
39
     * - not available
40
     * - public
41
     * - private.
42
     */
43
    public const TOOL_NOT_AVAILABLE = 0;
44
    public const TOOL_PUBLIC = 1;
45
    public const TOOL_PRIVATE = 2;
46
    public const TOOL_PRIVATE_BETWEEN_USERS = 3;
47
48
    /**
49
     * Constants for the available group tools.
50
     */
51
    public const GROUP_TOOL_FORUM = 0;
52
    public const GROUP_TOOL_DOCUMENTS = 1;
53
    public const GROUP_TOOL_CALENDAR = 2;
54
    public const GROUP_TOOL_ANNOUNCEMENT = 3;
55
    public const GROUP_TOOL_WORK = 4;
56
    public const GROUP_TOOL_WIKI = 5;
57
    public const GROUP_TOOL_CHAT = 6;
58
59
    public const DOCUMENT_MODE_SHARE = 0; // By default
60
    public const DOCUMENT_MODE_READ_ONLY = 1;
61
    public const DOCUMENT_MODE_COLLABORATION = 2;
62
63
    /**
64
     * GroupManager constructor.
65
     */
66
    public function __construct()
67
    {
68
    }
69
70
    /**
71
     * @param int $courseId
72
     *
73
     * @return array
74
     */
75
    public static function get_groups($courseId = 0)
76
    {
77
        $repo = Container::getGroupRepository();
78
        $course = api_get_course_entity($courseId);
79
80
        $qb = $repo->getResourcesByCourse($course);
81
82
        return $qb->getQuery()->getArrayResult();
83
84
        $table_group = Database::get_course_table(TABLE_GROUP);
0 ignored issues
show
Unused Code introduced by
$table_group = Database:...urse_table(TABLE_GROUP) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
85
        $courseId = !empty($courseId) ? (int) $courseId : api_get_course_int_id();
86
87
        $sql = "SELECT * FROM $table_group WHERE c_id = $courseId  ";
88
        $result = Database::query($sql);
89
90
        return Database::store_result($result, 'ASSOC');
91
    }
92
93
    /**
94
     * Get list of groups for current course.
95
     *
96
     * @param int   $categoryId  The id of the category from which the groups are
97
     *                           requested
98
     * @param array $course_info Default is current course
99
     * @param int   $status      group status
100
     * @param int   $sessionId
101
     * @param bool  $getCount
102
     *
103
     * @return array an array with all information about the groups
104
     */
105
    public static function get_group_list(
106
        $categoryId = null,
107
        $course_info = [],
108
        $status = null,
109
        $sessionId = 0,
110
        $getCount = false
111
    ) {
112
        $course_info = empty($course_info) ? api_get_course_info() : $course_info;
113
114
        if (empty($course_info)) {
115
            return [];
116
        }
117
118
        $sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
119
        $course_id = $course_info['real_id'];
120
121
        $repo = Container::getGroupRepository();
122
        $course = api_get_course_entity($course_id);
123
        $session = api_get_session_entity($sessionId);
124
        $group = api_get_group_entity(api_get_group_id());
125
126
        $qb = $repo->getResourcesByCourse($course, $session, $group);
127
128
        if (null === $categoryId) {
129
            $qb
130
                ->andWhere('resource.category is NULL');
131
        } else {
132
            $qb
133
                ->andWhere('resource.category = :category')
134
                ->setParameter('category', $categoryId);
135
        }
136
137
        if ($getCount) {
138
            $qb->select('count(resource)');
139
140
            return $qb->getQuery()->getSingleScalarResult();
141
        }
142
143
        return $qb->getQuery()->getArrayResult();
144
145
        $table_group = Database::get_course_table(TABLE_GROUP);
0 ignored issues
show
Unused Code introduced by
$table_group = Database:...urse_table(TABLE_GROUP) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
146
147
        $select = ' g.iid,
148
                    g.name,
149
                    g.description,
150
                    g.category_id,
151
                    g.max_student maximum_number_of_members,
152
                    g.secret_directory,
153
                    g.self_registration_allowed,
154
                    g.self_unregistration_allowed,
155
                    g.status
156
                    ';
157
        if ($getCount) {
158
            $select = ' DISTINCT count(g.iid) as count ';
159
        }
160
161
        $sql = "SELECT
162
                $select
163
                FROM $table_group g
164
                WHERE 1 = 1 ";
165
166
        if (!is_null($categoryId)) {
167
            $sql .= " AND g.category_id = '".intval($categoryId)."' ";
168
            $session_condition = api_get_session_condition($sessionId);
169
            if (!empty($session_condition)) {
170
                //$sql .= $session_condition;
171
            }
172
        } else {
173
            $session_condition = api_get_session_condition($sessionId, true);
174
        }
175
176
        $session_condition = '';
177
178
        if (!is_null($status)) {
179
            $sql .= " AND g.status = '".intval($status)."' ";
180
        }
181
182
        //$sql .= " AND g.c_id = $course_id ";
183
184
        if (!empty($session_condition)) {
185
            $sql .= $session_condition;
186
        }
187
        $sql .= ' ORDER BY UPPER(g.name)';
188
189
        $result = Database::query($sql);
190
191
        if ($getCount) {
192
            $row = Database::fetch_array($result);
193
194
            return $row['count'];
195
        }
196
197
        $groups = [];
198
        while ($thisGroup = Database::fetch_array($result)) {
199
            $thisGroup['number_of_members'] = count(self::get_subscribed_users($thisGroup));
200
            if (0 != $thisGroup['session_id']) {
201
                $sql = 'SELECT name FROM '.Database::get_main_table(TABLE_MAIN_SESSION).'
202
                        WHERE id='.$thisGroup['session_id'];
203
                $rs_session = Database::query($sql);
204
                if (Database::num_rows($rs_session) > 0) {
205
                    $thisGroup['session_name'] = Database::result($rs_session, 0, 0);
206
                }
207
            }
208
            $groups[] = $thisGroup;
209
        }
210
211
        return $groups;
212
    }
213
214
    /**
215
     * Create a group.
216
     *
217
     * @param string $name        The name for this group
218
     * @param int    $category_id
219
     * @param int    $tutor       The user-id of the group's tutor
220
     * @param int    $places      How many people can subscribe to the new group
221
     *
222
     * @return int
223
     */
224
    public static function create_group($name, $category_id, $tutor, $places)
225
    {
226
        $_course = api_get_course_info();
227
        $session_id = api_get_session_id();
228
        $course_id = $_course['real_id'];
229
        $category = self::get_category($category_id);
230
        $places = (int) $places;
231
232
        // Default values
233
        $docState = self::TOOL_PRIVATE;
234
        $calendarState = self::TOOL_PRIVATE;
235
        $workState = self::TOOL_PRIVATE;
236
        $anonuncementState = self::TOOL_PRIVATE;
237
        $forumState = self::TOOL_PRIVATE;
238
        $wikiState = self::TOOL_PRIVATE;
239
        $chatState = self::TOOL_PRIVATE;
240
        $selfRegAllowed = 0;
241
        $selfUnregAllwoed = 0;
242
        $documentAccess = 0;
243
244
        if ($category) {
245
            if (0 == $places) {
246
                //if the amount of users per group is not filled in, use the setting from the category
247
                $places = $category['max_student'];
248
            } else {
249
                if ($places > $category['max_student'] && 0 != $category['max_student']) {
250
                    $places = $category['max_student'];
251
                }
252
            }
253
            $docState = $category['doc_state'];
254
            $calendarState = $category['calendar_state'];
255
            $workState = $category['work_state'];
256
            $anonuncementState = $category['announcements_state'];
257
            $forumState = $category['forum_state'];
258
            $wikiState = $category['wiki_state'];
259
            $chatState = $category['chat_state'];
260
            $selfRegAllowed = $category['self_reg_allowed'];
261
            $selfUnregAllwoed = $category['self_unreg_allowed'];
262
            $documentAccess = isset($category['document_access']) ? $category['document_access'] : 0;
263
        }
264
265
        $course = api_get_course_entity($course_id);
266
        $session = api_get_session_entity($session_id);
267
268
        $category = null;
269
        if (!empty($category_id)) {
270
            $category = Container::getGroupCategoryRepository()->find($category_id);
271
        }
272
273
        $group = new CGroup();
274
        $group
275
            ->setName($name)
276
            ->setCategory($category)
277
            ->setMaxStudent($places)
278
            ->setDocState($docState)
279
            ->setCalendarState($calendarState)
280
            ->setWorkState($workState)
281
            ->setForumState($forumState)
282
            ->setWikiState($wikiState)
283
            ->setAnnouncementsState($anonuncementState)
284
            ->setChatState($chatState)
285
            ->setSelfRegistrationAllowed($selfRegAllowed)
286
            ->setSelfUnregistrationAllowed($selfUnregAllwoed)
287
            ->setDocumentAccess($documentAccess)
288
            ->setParent($course)
289
            ->addCourseLink($course, $session)
290
        ;
291
292
        $repo = Container::getGroupRepository();
293
        $repo->getEntityManager()->persist($group);
294
        $repo->getEntityManager()->flush();
295
        $lastId = $group->getIid();
296
297
        if ($lastId) {
298
            /*$desired_dir_name = '/'.api_replace_dangerous_char($name).'_groupdocs';
299
300
            $newFolderData = create_unexisting_directory(
301
                $_course,
302
                api_get_user_id(),
303
                $session_id,
304
                $lastId,
305
                null,
306
                null,
307
                    $desired_dir_name,
308
                $desired_dir_name,
309
                1
310
            );*/
311
312
            //$unique_name = $newFolderData->getPath();
313
314
            /* Stores the directory path into the group table */
315
            /*$sql = "UPDATE $table_group SET
316
                        name = '".Database::escape_string($name)."',
317
                        secret_directory = '".$unique_name."'
318
                    WHERE c_id = $course_id AND id ='".$lastId."'";
319
320
            Database::query($sql);*/
321
322
            // create a forum if needed
323
            if ($forumState >= 0) {
324
                require_once api_get_path(SYS_CODE_PATH).'forum/forumfunction.inc.php';
325
326
                $forumName = get_lang('Group forums');
327
                $repo = Container::getForumCategoryRepository();
328
                $criteria = ['cId' => $course_id, 'catTitle' => $forumName];
329
                $category = $repo->findOneBy($criteria);
330
331
                if (empty($category)) {
332
                    $categoryParam = [
333
                        'forum_category_title' => $forumName,
334
                    ];
335
                    $categoryId = store_forumcategory($categoryParam);
336
                } else {
337
                    $categoryId = $category->getIid();
338
                }
339
340
                $values = [];
341
                $values['forum_title'] = $name;
342
                $values['group_id'] = $lastId;
343
                $values['forum_category'] = $categoryId;
344
                $values['allow_anonymous_group']['allow_anonymous'] = 0;
345
                $values['students_can_edit_group']['students_can_edit'] = 0;
346
                $values['approval_direct_group']['approval_direct'] = 0;
347
                $values['allow_attachments_group']['allow_attachments'] = 1;
348
                $values['allow_new_threads_group']['allow_new_threads'] = 1;
349
                $values['default_view_type_group']['default_view_type'] = api_get_setting('default_forum_view');
350
                $values['group_forum'] = $lastId;
351
                if ('1' == $forumState) {
352
                    $values['public_private_group_forum_group']['public_private_group_forum'] = 'public';
353
                } elseif ('2' == $forumState) {
354
                    $values['public_private_group_forum_group']['public_private_group_forum'] = 'private';
355
                } elseif ('0' == $forumState) {
356
                    $values['public_private_group_forum_group']['public_private_group_forum'] = 'unavailable';
357
                }
358
                store_forum($values);
359
            }
360
        }
361
362
        return $lastId;
363
    }
364
365
    /**
366
     * Create subgroups.
367
     * This function creates new groups based on an existing group. It will
368
     * create the specified number of groups and fill those groups with users
369
     * from the base group.
370
     *
371
     * @param int $group_id         the group from which subgroups have to be created
372
     * @param int $number_of_groups The number of groups that have to be created
373
     */
374
    public static function create_subgroups($group_id, $number_of_groups)
375
    {
376
        $courseId = api_get_course_int_id();
377
        $table_group = Database::get_course_table(TABLE_GROUP);
378
        $category_id = self::create_category(
379
            get_lang('Subgroups'),
380
            '',
381
            self::TOOL_PRIVATE,
382
            self::TOOL_PRIVATE,
383
            0,
384
            0,
385
            1,
386
            1
387
        );
388
        $users = self::get_users($group_id);
389
        $group_ids = [];
390
391
        for ($group_nr = 1; $group_nr <= $number_of_groups; $group_nr++) {
392
            $group_ids[] = self::create_group(
393
                get_lang('Subgroup').' '.$group_nr,
394
                $category_id,
395
                0,
396
                0
397
            );
398
        }
399
400
        $members = [];
401
        foreach ($users as $index => $user_id) {
402
            $groupId = $group_ids[$index % $number_of_groups];
403
            $groupInfo = self::get_group_properties($groupId);
404
            self::subscribe_users(
405
                $user_id,
406
                $groupInfo
407
            );
408
            $members[$group_ids[$groupId]]++;
409
        }
410
411
        foreach ($members as $group_id => $places) {
412
            $sql = "UPDATE $table_group SET max_student = $places
413
                    WHERE c_id = $courseId  AND id = $group_id";
414
            Database::query($sql);
415
        }
416
    }
417
418
    /**
419
     * Create a group for every class subscribed to the current course.
420
     *
421
     * @param int $categoryId The category in which the groups should be created
422
     *
423
     * @return array
424
     */
425
    public static function create_class_groups($categoryId)
426
    {
427
        $options['where'] = [' usergroup.course_id = ? ' => api_get_course_int_id()];
428
        $obj = new UserGroup();
429
        $classes = $obj->getUserGroupInCourse($options);
430
        $group_ids = [];
431
432
        foreach ($classes as $class) {
433
            $userList = $obj->get_users_by_usergroup($class['id']);
434
            $groupId = self::create_group(
435
                $class['name'],
436
                $categoryId,
437
                0,
438
                null
439
            );
440
441
            if ($groupId) {
442
                $groupInfo = self::get_group_properties($groupId);
443
                self::subscribe_users($userList, $groupInfo);
444
                $group_ids[] = $groupId;
445
            }
446
        }
447
448
        return $group_ids;
449
    }
450
451
    /**
452
     * Deletes groups and their data.
453
     *
454
     * @author Christophe Gesche <[email protected]>
455
     * @author Hugues Peeters <[email protected]>
456
     * @author Bart Mollet
457
     *
458
     * @param array  $groupInfo   iid
459
     * @param string $course_code Default is current course
460
     *
461
     * @return int - number of groups deleted
462
     */
463
    public static function deleteGroup($groupInfo, $course_code = null)
464
    {
465
        if (empty($groupInfo['iid'])) {
466
            return false;
467
        }
468
        $course_info = api_get_course_info($course_code);
469
        if (empty($course_info)) {
470
            return false;
471
        }
472
473
        $course_id = $course_info['real_id'];
474
        $em = Database::getManager();
475
        $groupInfo = self::get_group_properties($groupInfo['iid'], true);
476
        if ($groupInfo) {
477
            $groupIid = $groupInfo['iid'];
478
            // Unsubscribe all users
479
            self::unsubscribe_all_users($groupInfo);
480
            self::unsubscribe_all_tutors($groupInfo);
481
482
            if (!empty($groupInfo['secret_directory'])) {
483
                /*
484
                $directory = $groupInfo['secret_directory'];
485
                // move group-documents to garbage
486
                $source_directory = api_get_path(SYS_COURSE_PATH).$course_info['path']."/document".$directory;
487
                // File to renamed
488
                $destination_dir = api_get_path(SYS_COURSE_PATH).$course_info['path']."/document".$directory.'_DELETED_'.$groupInfo['id'];
489
                //Deleting from document tool
490
                DocumentManager::delete_document(
491
                    $course_info,
492
                    $directory,
493
                    $source_directory
494
                );
495
496
                if (file_exists($source_directory)) {
497
                    if ('true' === api_get_setting('permanently_remove_deleted_files')) {
498
                        // Delete
499
                        my_delete($source_directory);
500
                    } else {
501
                        // Rename
502
                        rename($source_directory, $destination_dir);
503
                    }
504
                }*/
505
            }
506
507
            $em
508
                ->createQuery(
509
                    'DELETE FROM ChamiloCourseBundle:CForumForum f WHERE f.forumOfGroup = :group'
510
                )
511
                ->execute(['group' => $groupIid]);
512
513
            // Delete item properties of this group.
514
            // to_group_id is related to c_group_info.iid
515
            /*$em
516
                ->createQuery(
517
                    'DELETE FROM ChamiloCourseBundle:CItemProperty ci WHERE ci.course = :course AND ci.group = :group'
518
                )
519
                ->execute(['course' => $course_id, 'group' => $groupId]);
520
            */
521
            // delete the groups
522
            $repo = Container::getGroupRepository();
523
            $group = $repo->find($groupIid);
524
            if ($group) {
525
                $em->remove($group);
526
                $em->flush();
527
            }
528
            /*$em
529
                ->createQuery(
530
                    'DELETE FROM ChamiloCourseBundle:CGroup g WHERE g.course = :course AND g.iid = :id'
531
                )
532
                ->execute(['course' => $course_id, 'id' => $groupIid]);*/
533
        }
534
535
        return true;
536
    }
537
538
    /**
539
     * @deprecated Should be deleted by the resources.
540
     *
541
     * Function needed only when deleting a course, in order to be sure that all group ids are deleted.
542
     *
543
     * @param int $courseId
544
     *
545
     * @return bool
546
     */
547
    public static function deleteAllGroupsFromCourse($courseId)
548
    {
549
        $courseId = (int) $courseId;
550
551
        if (empty($courseId)) {
552
            return false;
553
        }
554
555
        $table = Database::get_course_table(TABLE_GROUP_CATEGORY);
556
        $sql = "SELECT iid FROM $table
557
                WHERE c_id = $courseId ";
558
        Database::query($sql);
559
560
        // Database table definitions
561
        $table = Database::get_course_table(TABLE_GROUP_USER);
562
        $sql = "DELETE FROM $table
563
                WHERE c_id = $courseId";
564
        Database::query($sql);
565
566
        $table = Database::get_course_table(TABLE_GROUP_TUTOR);
567
        $sql = "DELETE FROM $table
568
                WHERE c_id = $courseId";
569
        Database::query($sql);
570
571
        $groupTable = Database::get_course_table(TABLE_GROUP);
572
        $sql = "DELETE FROM $groupTable
573
                WHERE c_id = $courseId";
574
        Database::query($sql);
575
576
        return true;
577
    }
578
579
    /**
580
     * Get group properties.
581
     *
582
     * @param int $group_id the group from which properties are requested
583
     *
584
     * @return array All properties. Array-keys are:
585
     *               name, tutor_id, description, maximum_number_of_students,
586
     *               directory and visibility of tools
587
     */
588
    public static function get_group_properties($group_id)
589
    {
590
        $group_id = (int) $group_id;
591
592
        if (empty($group_id)) {
593
            return null;
594
        }
595
596
        $table_group = Database::get_course_table(TABLE_GROUP);
597
598
        $sql = "SELECT * FROM $table_group
599
                WHERE iid = ".$group_id;
600
601
        $db_result = Database::query($sql);
602
        $db_object = Database::fetch_object($db_result);
603
604
        $result = [];
605
        if ($db_object) {
606
            $result['id'] = $db_object->iid;
607
            $result['iid'] = $db_object->iid;
608
            $result['name'] = $db_object->name;
609
            $result['status'] = $db_object->status;
610
            $result['description'] = $db_object->description;
611
            $result['maximum_number_of_students'] = $db_object->max_student;
612
            $result['max_student'] = $db_object->max_student;
613
            $result['doc_state'] = $db_object->doc_state;
614
            $result['work_state'] = $db_object->work_state;
615
            $result['calendar_state'] = $db_object->calendar_state;
616
            $result['announcements_state'] = $db_object->announcements_state;
617
            $result['forum_state'] = $db_object->forum_state;
618
            $result['wiki_state'] = $db_object->wiki_state;
619
            $result['chat_state'] = $db_object->chat_state;
620
            $result['directory'] = $db_object->secret_directory;
621
            $result['self_registration_allowed'] = $db_object->self_registration_allowed;
622
            $result['self_unregistration_allowed'] = $db_object->self_unregistration_allowed;
623
            $result['count_users'] = count(
624
                self::get_subscribed_users($result)
625
            );
626
            $result['count_tutor'] = count(
627
                self::get_subscribed_tutors($result)
628
            );
629
            $result['count_all'] = $result['count_users'] + $result['count_tutor'];
630
            $result['document_access'] = isset($db_object->document_access) ? $db_object->document_access : self::DOCUMENT_MODE_SHARE;
631
        }
632
633
        return $result;
634
    }
635
636
    /**
637
     * @param string $name
638
     * @param string $courseCode
639
     * @param int    $sessionId
640
     *
641
     * @return array
642
     */
643
    public static function getGroupByName($name, $courseCode = null, $sessionId = 0)
644
    {
645
        $name = trim($name);
646
647
        if (empty($name)) {
648
            return [];
649
        }
650
651
        $course_info = api_get_course_info($courseCode);
652
        $course_id = $course_info['real_id'];
653
        $name = Database::escape_string($name);
654
        $sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
655
        $sessionCondition = api_get_session_condition($sessionId);
656
657
        $table = Database::get_course_table(TABLE_GROUP);
658
        $sql = "SELECT * FROM $table
659
                WHERE
660
                  c_id = $course_id AND
661
                  name = '$name'
662
                  $sessionCondition
663
                LIMIT 1";
664
        $res = Database::query($sql);
665
        $group = [];
666
        if (Database::num_rows($res)) {
667
            $group = Database::fetch_array($res, 'ASSOC');
668
        }
669
670
        return $group;
671
    }
672
673
    /**
674
     * @param int    $courseId
675
     * @param int    $categoryId
676
     * @param string $name
677
     *
678
     * @return array
679
     */
680
    public static function getGroupListFilterByName($name, $categoryId, $courseId)
681
    {
682
        $name = trim($name);
683
        $name = Database::escape_string($name);
684
        $categoryId = (int) $categoryId;
685
        $courseId = (int) $courseId;
686
687
        if (empty($name)) {
688
            return [];
689
        }
690
        $table_group = Database::get_course_table(TABLE_GROUP);
691
        $sql = "SELECT * FROM $table_group
692
                WHERE c_id = $courseId AND name LIKE '%$name%'";
693
694
        if (!empty($categoryId)) {
695
            $sql .= " AND category_id = $categoryId";
696
        }
697
        $sql .= ' ORDER BY name';
698
        $result = Database::query($sql);
699
700
        return Database::store_result($result, 'ASSOC');
701
    }
702
703
    /**
704
     * Set group properties
705
     * Changes the group's properties.
706
     *
707
     * @param int       Group Id
708
     * @param string    Group name
709
     * @param string    Group description
710
     * @param int       Max number of students in group
711
     * @param int       Document tool's visibility (0=none,1=private,2=public)
712
     * @param int       Work tool's visibility (0=none,1=private,2=public)
713
     * @param int       Calendar tool's visibility (0=none,1=private,2=public)
714
     * @param int       Announcement tool's visibility (0=none,1=private,2=public)
715
     * @param int       Forum tool's visibility (0=none,1=private,2=public)
716
     * @param int       Wiki tool's visibility (0=none,1=private,2=public)
717
     * @param int       Chat tool's visibility (0=none,1=private,2=public)
718
     * @param bool Whether self registration is allowed or not
719
     * @param bool Whether self unregistration is allowed or not
720
     * @param int $categoryId
721
     * @param int $documentAccess
722
     *
723
     * @return bool TRUE if properties are successfully changed, false otherwise
724
     */
725
    public static function set_group_properties(
726
        $group_id,
727
        $name,
728
        $description,
729
        $maxStudent,
730
        $docState,
731
        $workState,
732
        $calendarState,
733
        $anonuncementState,
734
        $forumState,
735
        $wikiState,
736
        $chatState,
737
        $selfRegistrationAllowed,
738
        $selfUnRegistrationAllowed,
739
        $categoryId = null,
740
        $documentAccess = 0
741
    ) {
742
        $table_group = Database::get_course_table(TABLE_GROUP);
743
        $table_forum = Database::get_course_table(TABLE_FORUM);
744
        $categoryId = (int) $categoryId;
745
        $group_id = (int) $group_id;
746
        $repo = Container::getGroupRepository();
747
748
        /** @var CGroup $group */
749
        $group = $repo->find($group_id);
750
751
        $category = null;
752
        if (!empty($categoryId)) {
753
            $category = Container::getGroupCategoryRepository()->find($categoryId);
754
        }
755
756
        $group
757
            ->setName($name)
758
            ->setCategory($category)
759
            ->setMaxStudent($maxStudent)
760
            ->setDocState($docState)
761
            ->setCalendarState($calendarState)
762
            ->setWorkState($workState)
763
            ->setForumState($forumState)
764
            ->setWikiState($wikiState)
765
            ->setAnnouncementsState($anonuncementState)
766
            ->setChatState($chatState)
767
            ->setSelfRegistrationAllowed($selfRegistrationAllowed)
768
            ->setSelfUnregistrationAllowed($selfUnRegistrationAllowed)
769
            ->setDocumentAccess($documentAccess)
770
        ;
771
772
        $repo->getEntityManager()->persist($group);
773
        $repo->getEntityManager()->flush();
774
775
        /* Here we are updating a field in the table forum_forum that perhaps
776
        duplicates the table group_info.forum_state cvargas*/
777
        $forumState = (int) $forumState;
778
        $sql2 = "UPDATE $table_forum SET ";
779
        if (1 === $forumState) {
780
            $sql2 .= " forum_group_public_private='public' ";
781
        } elseif (2 === $forumState) {
782
            $sql2 .= " forum_group_public_private='private' ";
783
        } elseif (0 === $forumState) {
784
            $sql2 .= " forum_group_public_private='unavailable' ";
785
        }
786
        $sql2 .= ' WHERE forum_of_group='.$group_id;
787
        Database::query($sql2);
788
789
        return true;
790
    }
791
792
    /**
793
     * Get the total number of groups for the current course.
794
     *
795
     * @return int the number of groups for the current course
796
     */
797
    public static function get_number_of_groups()
798
    {
799
        $repo = Container::getGroupRepository();
800
801
        $course = api_get_course_entity(api_get_course_int_id());
802
        $session = api_get_session_entity(api_get_session_id());
803
        $group = api_get_group_entity(api_get_group_id());
804
805
        $qb = $repo->getResourcesByCourse($course, $session, $group);
806
        $qb->select('count(resource)');
807
808
        return $qb->getQuery()->getSingleScalarResult();
809
810
        $courseId = api_get_course_int_id();
0 ignored issues
show
Unused Code introduced by
$courseId = api_get_course_int_id() is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
811
        $table = Database::get_course_table(TABLE_GROUP);
812
        $sql = "SELECT COUNT(id) AS number_of_groups
813
                FROM $table
814
                WHERE c_id = $courseId ";
815
        $res = Database::query($sql);
816
        $obj = Database::fetch_object($res);
817
818
        return $obj->number_of_groups;
819
    }
820
821
    /**
822
     * Get all categories.
823
     */
824
    public static function get_categories(Course $course = null): array
825
    {
826
        $repo = Container::getGroupCategoryRepository();
827
828
        if (null === $course) {
829
            $course = api_get_course_entity(api_get_course_int_id());
830
        }
831
832
        $session = api_get_session_entity(api_get_session_id());
833
        $group = api_get_group_entity(api_get_group_id());
834
835
        $qb = $repo->getResourcesByCourse($course, $session, $group);
836
837
        return $qb->getQuery()->getArrayResult();
838
839
        $course_info = api_get_course_info($course_code);
0 ignored issues
show
Unused Code introduced by
$course_info = api_get_course_info($course_code) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
840
        $courseId = $course_info['real_id'];
841
        $table = Database::get_course_table(TABLE_GROUP_CATEGORY);
842
        $sql = "SELECT * FROM $table
843
                WHERE c_id = $courseId
844
                ORDER BY display_order";
845
        $res = Database::query($sql);
846
        $cats = [];
847
        while ($cat = Database::fetch_array($res)) {
848
            $cats[] = $cat;
849
        }
850
851
        return $cats;
852
    }
853
854
    /**
855
     * Get a group category.
856
     *
857
     * @param int    $id          The category id
858
     * @param string $course_code The course (default = current course)
859
     *
860
     * @return array
861
     */
862
    public static function get_category($id, $course_code = null)
863
    {
864
        if (empty($id)) {
865
            return [];
866
        }
867
868
        $courseInfo = api_get_course_info($course_code);
869
        $courseId = $courseInfo['real_id'];
870
        $id = intval($id);
871
        $table = Database::get_course_table(TABLE_GROUP_CATEGORY);
872
        $sql = "SELECT * FROM $table
873
                WHERE  iid = $id
874
                LIMIT 1";
875
        $res = Database::query($sql);
876
877
        return Database::fetch_array($res);
878
    }
879
880
    /**
881
     * Get a group category.
882
     *
883
     * @param string $title
884
     * @param string $course_code The course (default = current course)
885
     *
886
     * @return array
887
     */
888
    public static function getCategoryByTitle($title, $course_code = null)
889
    {
890
        $title = trim($title);
891
892
        if (empty($title)) {
893
            return [];
894
        }
895
896
        $course_info = api_get_course_info($course_code);
897
        $courseId = $course_info['real_id'];
898
        $title = Database::escape_string($title);
899
        $table = Database::get_course_table(TABLE_GROUP_CATEGORY);
900
        $sql = "SELECT * FROM $table
901
                WHERE c_id = $courseId AND title = '$title'
902
                LIMIT 1";
903
        $res = Database::query($sql);
904
        $category = [];
905
        if (Database::num_rows($res)) {
906
            $category = Database::fetch_array($res, 'ASSOC');
907
        }
908
909
        return $category;
910
    }
911
912
    /**
913
     * Get the unique category of a given group.
914
     *
915
     * @param int    $group_id    The iid of the group
916
     * @param string $course_code The course in which the group is (default =
917
     *                            current course)
918
     *
919
     * @return array The category
920
     */
921
    public static function get_category_from_group($group_id, $course_code = '')
922
    {
923
        $table_group = Database::get_course_table(TABLE_GROUP);
924
        $table_group_cat = Database::get_course_table(TABLE_GROUP_CATEGORY);
925
926
        $group_id = (int) $group_id;
927
928
        if (empty($group_id)) {
929
            return [];
930
        }
931
932
        $course_info = api_get_course_info($course_code);
933
934
        if (empty($course_info)) {
935
            return false;
936
        }
937
938
        $courseId = $course_info['real_id'];
939
        $sql = "SELECT gc.* FROM $table_group_cat gc
940
                INNER JOIN $table_group g
941
                ON (gc.iid = g.category_id)
942
                WHERE
943
                    g.iid = $group_id
944
                LIMIT 1";
945
        $res = Database::query($sql);
946
        $cat = [];
947
        if (Database::num_rows($res)) {
948
            $cat = Database::fetch_array($res);
949
        }
950
951
        return $cat;
952
    }
953
954
    /**
955
     * Delete a group category.
956
     *
957
     * @param int    $cat_id      The id of the category to delete
958
     * @param string $course_code The code in which the category should be
959
     *                            deleted (default = current course)
960
     *
961
     * @return bool
962
     */
963
    public static function delete_category($cat_id, $course_code = '')
964
    {
965
        $course_info = api_get_course_info($course_code);
966
        if (empty($course_info)) {
967
            return false;
968
        }
969
        $course_id = $course_info['real_id'];
970
971
        $table_group = Database::get_course_table(TABLE_GROUP);
972
        $table_group_cat = Database::get_course_table(TABLE_GROUP_CATEGORY);
973
        $cat_id = (int) $cat_id;
974
        $sql = "SELECT iid FROM $table_group
975
                WHERE category_id='".$cat_id."'";
976
        $res = Database::query($sql);
977
        if (Database::num_rows($res) > 0) {
978
            while ($group = Database::fetch_object($res)) {
979
                // Delete all groups in category
980
                /*$groupInfo = self::get_group_properties($group->iid, true);
981
                self::deleteGroup($groupInfo, $course_code);
982
                */
983
                // Set the category to NULL to avoid losing groups in sessions.
984
                $sql = "UPDATE $table_group SET category_id = NULL WHERE iid = ".$group->iid;
985
                Database::query($sql);
986
            }
987
        }
988
989
        $category = Database::getManager()->getRepository(CGroupCategory::class)->find($cat_id);
990
        if ($category) {
991
            Database::getManager()->remove($category);
992
            Database::getManager()->flush();
993
        }
994
995
        /*$sql = "DELETE FROM $table_group_cat
996
                WHERE iid='".$cat_id."'";
997
        Database::query($sql);*/
998
999
        return true;
1000
    }
1001
1002
    /**
1003
     * Create group category.
1004
     *
1005
     * @param string $title                     The title of the new category
1006
     * @param string $description               The description of the new category
1007
     * @param int    $selfRegistrationAllowed   allow users to self register
1008
     * @param int    $selfUnRegistrationAllowed allow user to self unregister
1009
     * @param int    $documentAccess            document access
1010
     *
1011
     * @return mixed
1012
     */
1013
    public static function create_category(
1014
        $title,
1015
        $description,
1016
        $docState,
1017
        $workState,
1018
        $calendarState,
1019
        $anonuncementState,
1020
        $forumState,
1021
        $wikiState,
1022
        $chatState = 1,
1023
        $selfRegistrationAllowed = 0,
1024
        $selfUnRegistrationAllowed = 0,
1025
        $maxStudent = 8,
1026
        $groupsPerUser = 0,
1027
        $documentAccess = 0
1028
    ) {
1029
        if (empty($title)) {
1030
            return false;
1031
        }
1032
        /*$sql = "SELECT MAX(display_order)+1 as new_order
1033
                FROM $table
1034
                WHERE c_id = $course_id ";
1035
        $res = Database::query($sql);
1036
        $obj = Database::fetch_object($res);
1037
        if (!isset($obj->new_order)) {
1038
            $obj->new_order = 1;
1039
        }*/
1040
1041
        $course = api_get_course_entity(api_get_course_int_id());
1042
        $session = api_get_session_entity(api_get_session_id());
1043
1044
        $category = new CGroupCategory();
1045
        $category
1046
            ->setTitle($title)
1047
            ->setDescription($description)
1048
            ->setMaxStudent($maxStudent)
1049
            ->setDocState($docState)
1050
            ->setCalendarState($calendarState)
1051
            ->setWorkState($workState)
1052
            ->setForumState($forumState)
1053
            ->setWikiState($wikiState)
1054
            ->setAnnouncementsState($anonuncementState)
1055
            ->setChatState($chatState)
1056
            ->setSelfRegAllowed($selfRegistrationAllowed)
1057
            ->setSelfUnregAllowed($selfUnRegistrationAllowed)
1058
            ->setDocumentAccess($documentAccess)
1059
            ->setGroupsPerUser($groupsPerUser)
1060
            ->setParent($course)
1061
            ->addCourseLink($course, $session)
1062
        ;
1063
1064
        $repo = Container::getGroupCategoryRepository();
1065
        $repo->getEntityManager()->persist($category);
1066
        $repo->getEntityManager()->flush();
1067
1068
        return $category->getIid();
1069
    }
1070
1071
    /**
1072
     * Update group category.
1073
     *
1074
     * @param int    $id
1075
     * @param string $title
1076
     * @param string $description
1077
     * @param $doc_state
1078
     * @param $work_state
1079
     * @param $calendar_state
1080
     * @param $announcements_state
1081
     * @param $forum_state
1082
     * @param $wiki_state
1083
     * @param $chat_state
1084
     * @param $selfRegistrationAllowed
1085
     * @param $selfUnRegistrationAllowed
1086
     * @param $maximum_number_of_students
1087
     * @param $groups_per_user
1088
     * @param $documentAccess
1089
     */
1090
    public static function update_category(
1091
        $id,
1092
        $title,
1093
        $description,
1094
        $doc_state,
1095
        $work_state,
1096
        $calendar_state,
1097
        $announcements_state,
1098
        $forum_state,
1099
        $wiki_state,
1100
        $chat_state,
1101
        $selfRegistrationAllowed,
1102
        $selfUnRegistrationAllowed,
1103
        $maximum_number_of_students,
1104
        $groups_per_user,
1105
        $documentAccess
1106
    ) {
1107
        $table = Database::get_course_table(TABLE_GROUP_CATEGORY);
1108
        $id = (int) $id;
1109
1110
        $courseId = api_get_course_int_id();
1111
1112
        $allowDocumentAccess = api_get_configuration_value('group_category_document_access');
1113
        $documentCondition = '';
1114
        if ($allowDocumentAccess) {
1115
            $documentAccess = (int) $documentAccess;
1116
            $documentCondition = " document_access = $documentAccess, ";
1117
        }
1118
1119
        $sql = 'UPDATE '.$table." SET
1120
                    title='".Database::escape_string($title)."',
1121
                    description='".Database::escape_string($description)."',
1122
                    doc_state = '".Database::escape_string($doc_state)."',
1123
                    work_state = '".Database::escape_string($work_state)."',
1124
                    calendar_state = '".Database::escape_string($calendar_state)."',
1125
                    announcements_state = '".Database::escape_string($announcements_state)."',
1126
                    forum_state = '".Database::escape_string($forum_state)."',
1127
                    wiki_state = '".Database::escape_string($wiki_state)."',
1128
                    chat_state = '".Database::escape_string($chat_state)."',
1129
                    groups_per_user   = '".Database::escape_string($groups_per_user)."',
1130
                    self_reg_allowed = '".Database::escape_string($selfRegistrationAllowed)."',
1131
                    self_unreg_allowed = '".Database::escape_string($selfUnRegistrationAllowed)."',
1132
                    $documentCondition
1133
                    max_student = ".intval($maximum_number_of_students)."
1134
                WHERE iid = $id";
1135
1136
        Database::query($sql);
1137
1138
        // Updating all groups inside this category
1139
        $groups = self::get_group_list($id);
1140
1141
        if (!empty($groups)) {
1142
            foreach ($groups as $group) {
1143
                self::set_group_properties(
1144
                    $group['iid'],
1145
                    $group['name'],
1146
                    $group['description'],
1147
                    $maximum_number_of_students,
1148
                    $doc_state,
1149
                    $work_state,
1150
                    $calendar_state,
1151
                    $announcements_state,
1152
                    $forum_state,
1153
                    $wiki_state,
1154
                    $chat_state,
1155
                    $selfRegistrationAllowed,
1156
                    $selfUnRegistrationAllowed,
1157
                    $id,
1158
                    $documentAccess
1159
                );
1160
            }
1161
        }
1162
    }
1163
1164
    /**
1165
     * Returns the number of groups of the user with the greatest number of
1166
     * subscriptions in the given category.
1167
     */
1168
    public static function get_current_max_groups_per_user($category_id = null, $course_code = null)
1169
    {
1170
        $course_info = api_get_course_info($course_code);
1171
        $group_table = Database::get_course_table(TABLE_GROUP);
1172
1173
        $group_user_table = Database::get_course_table(TABLE_GROUP_USER);
1174
        $sql = "SELECT COUNT(gu.group_id) AS current_max
1175
                FROM $group_user_table gu
1176
                INNER JOIN $group_table g
1177
                ON (gu.group_id = g.iid)
1178
                WHERE 1= 1 ";
1179
        if (null != $category_id) {
1180
            $category_id = intval($category_id);
1181
            $sql .= ' AND g.category_id = '.$category_id;
1182
        }
1183
        $sql .= ' GROUP BY gu.user_id
1184
                  ORDER BY current_max DESC LIMIT 1';
1185
1186
        $res = Database::query($sql);
1187
        $obj = Database::fetch_object($res);
1188
1189
        if ($obj) {
1190
            return $obj->current_max;
1191
        }
1192
1193
        return 0;
1194
    }
1195
1196
    /**
1197
     * Swaps the display-order of two categories.
1198
     *
1199
     * @param int $id1 The id of the first category
1200
     * @param int $id2 The id of the second category
1201
     */
1202
    public static function swap_category_order($id1, $id2)
1203
    {
1204
        $table = Database::get_course_table(TABLE_GROUP_CATEGORY);
1205
        $id1 = intval($id1);
1206
        $id2 = intval($id2);
1207
        $course_id = api_get_course_int_id();
1208
1209
        $sql = "SELECT id, display_order FROM $table
1210
                WHERE id IN ($id1,$id2) AND c_id = $course_id ";
1211
        $res = Database::query($sql);
1212
        $cat1 = Database::fetch_object($res);
1213
        $cat2 = Database::fetch_object($res);
1214
        if ($cat1 && $cat2) {
1215
            $sql = "UPDATE $table SET display_order=$cat2->display_order
1216
                    WHERE id = $cat1->id AND c_id = $course_id ";
1217
            Database::query($sql);
1218
1219
            $sql = "UPDATE $table SET display_order=$cat1->display_order
1220
                    WHERE id = $cat2->id AND c_id = $course_id ";
1221
            Database::query($sql);
1222
        }
1223
    }
1224
1225
    /**
1226
     * Get all users from a given group.
1227
     *
1228
     * @param int  $group_id        The group
1229
     * @param bool $load_extra_info
1230
     * @param int  $start
1231
     * @param int  $limit
1232
     * @param bool $getCount
1233
     * @param int  $courseId
1234
     * @param $column
1235
     * @param $direction
1236
     *
1237
     * @return array list of user id
1238
     */
1239
    public static function get_users(
1240
        $group_id,
1241
        $load_extra_info = false,
1242
        $start = null,
1243
        $limit = null,
1244
        $getCount = false,
1245
        $courseId = null,
1246
        $column = null,
1247
        $direction = null
1248
    ) {
1249
        $group_user_table = Database::get_course_table(TABLE_GROUP_USER);
1250
        $groupTable = Database::get_course_table(TABLE_GROUP);
1251
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1252
        $group_id = intval($group_id);
1253
1254
        if (empty($courseId)) {
1255
            $courseId = api_get_course_int_id();
1256
        } else {
1257
            $courseId = intval($courseId);
1258
        }
1259
1260
        $select = ' SELECT u.id, firstname, lastname ';
1261
        if ($getCount) {
1262
            $select = ' SELECT count(u.id) count';
1263
        }
1264
        $sql = "$select
1265
                FROM $group_user_table gu
1266
                INNER JOIN $groupTable g
1267
                ON (gu.group_id = g.id and g.c_id = gu.c_id)
1268
                INNER JOIN $user_table u
1269
                ON (u.id = gu.user_id)
1270
                WHERE
1271
                    gu.c_id = $courseId AND
1272
                    g.id = $group_id";
1273
1274
        if (!empty($column) && !empty($direction)) {
1275
            $column = Database::escape_string($column, null, false);
1276
            $direction = ('ASC' == $direction ? 'ASC' : 'DESC');
1277
            $sql .= " ORDER BY $column $direction";
1278
        }
1279
1280
        if (!empty($start) && !empty($limit)) {
1281
            $start = (int) $start;
1282
            $limit = (int) $limit;
1283
            $sql .= " LIMIT $start, $limit";
1284
        }
1285
        $res = Database::query($sql);
1286
        $users = [];
1287
        while ($obj = Database::fetch_object($res)) {
1288
            if ($getCount) {
1289
                return $obj->count;
1290
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
1291
            }
1292
            if ($load_extra_info) {
1293
                $users[] = api_get_user_info($obj->id);
1294
            } else {
1295
                $users[] = $obj->id;
1296
            }
1297
        }
1298
1299
        return $users;
1300
    }
1301
1302
    /**
1303
     * @param int $group_id id
1304
     *
1305
     * @return array
1306
     */
1307
    public static function getStudentsAndTutors($group_id)
1308
    {
1309
        $group_user_table = Database::get_course_table(TABLE_GROUP_USER);
1310
        $tutor_user_table = Database::get_course_table(TABLE_GROUP_TUTOR);
1311
        $groupTable = Database::get_course_table(TABLE_GROUP);
1312
1313
        $course_id = api_get_course_int_id();
1314
        $group_id = (int) $group_id;
1315
1316
        $sql = "SELECT user_id
1317
                FROM $group_user_table gu
1318
                INNER JOIN $groupTable g
1319
                ON (gu.group_id = g.iid)
1320
                WHERE g.iid = $group_id";
1321
        $res = Database::query($sql);
1322
        $users = [];
1323
1324
        while ($obj = Database::fetch_object($res)) {
1325
            $users[] = api_get_user_info($obj->user_id);
1326
        }
1327
1328
        $sql = "SELECT user_id
1329
                FROM $tutor_user_table gu
1330
                INNER JOIN $groupTable g
1331
                ON (gu.group_id = g.iid)
1332
                WHERE g.iid = $group_id";
1333
        $res = Database::query($sql);
1334
        while ($obj = Database::fetch_object($res)) {
1335
            $users[] = api_get_user_info($obj->user_id);
1336
        }
1337
1338
        return $users;
1339
    }
1340
1341
    /**
1342
     * Get only tutors from a group.
1343
     *
1344
     * @param array $groupInfo
1345
     *
1346
     * @return array
1347
     */
1348
    public static function getTutors($groupInfo)
1349
    {
1350
        $groupTable = Database::get_course_table(TABLE_GROUP);
1351
        $tutor_user_table = Database::get_course_table(TABLE_GROUP_TUTOR);
1352
        $course_id = api_get_course_int_id();
1353
        $group_id = (int) $groupInfo['iid'];
1354
1355
        $sql = "SELECT user_id
1356
                FROM $tutor_user_table gu
1357
                INNER JOIN $groupTable g
1358
                ON (gu.group_id = g.iid)
1359
                WHERE g.iid = $group_id";
1360
        $res = Database::query($sql);
1361
1362
        $users = [];
1363
        while ($obj = Database::fetch_object($res)) {
1364
            $users[] = api_get_user_info($obj->user_id);
1365
        }
1366
1367
        return $users;
1368
    }
1369
1370
    /**
1371
     * Get only students from a group (not tutors).
1372
     *
1373
     * @param bool $filterOnlyActive
1374
     *
1375
     * @return array
1376
     */
1377
    public static function getStudents($groupId, $filterOnlyActive = false)
1378
    {
1379
        $groupId = (int) $groupId;
1380
1381
        $activeCondition = $filterOnlyActive ? 'AND u.active = 1' : '';
1382
1383
        $em = Database::getManager();
1384
        $subscriptions = $em
1385
            ->createQuery("
1386
                SELECT u.id FROM ChamiloCoreBundle:User u
1387
                INNER JOIN ChamiloCourseBundle:CGroupRelUser gu
1388
                    WITH u.id = gu.user
1389
                INNER JOIN ChamiloCourseBundle:CGroup g
1390
                WITH gu.group = g.iid
1391
                WHERE g.iid = :group
1392
                    $activeCondition
1393
            ")
1394
            ->setParameters([
1395
                'group' => $groupId,
1396
            ])
1397
            ->getResult();
1398
1399
        $users = [];
1400
        foreach ($subscriptions as $subscription) {
1401
            $users[] = api_get_user_info($subscription['id']);
1402
        }
1403
1404
        return $users;
1405
    }
1406
1407
    /**
1408
     * Returns users belonging to any of the group.
1409
     *
1410
     * @param array $groups list of group ids
1411
     *
1412
     * @return array list of user ids
1413
     */
1414
    public static function get_groups_users($groups = [])
1415
    {
1416
        $result = [];
1417
        $table = Database::get_course_table(TABLE_GROUP_USER);
1418
        $course_id = api_get_course_int_id();
1419
1420
        $groups = array_map('intval', $groups);
1421
        // protect individual elements with surrounding quotes
1422
        $groups = implode(', ', $groups);
1423
        $sql = "SELECT DISTINCT user_id
1424
                FROM $table gu
1425
                WHERE gu.group_id IN ($groups)";
1426
        $rs = Database::query($sql);
1427
        while ($row = Database::fetch_array($rs)) {
1428
            $result[] = $row['user_id'];
1429
        }
1430
1431
        return $result;
1432
    }
1433
1434
    /**
1435
     * Fill the groups with students.
1436
     * The algorithm takes care to first fill the groups with the least # of users.
1437
     * Analysis
1438
     * There was a problem with the "ALL" setting.
1439
     * When max # of groups is set to all, the value is sometimes NULL and sometimes ALL
1440
     * and in both cased the query does not work as expected.
1441
     * Stupid solution (currently implemented: set ALL to a big number (INFINITE) and things are solved :)
1442
     * Better solution: that's up to you.
1443
     *
1444
     * Note
1445
     * Throughout Dokeos there is some confusion about "course id" and "course code"
1446
     * The code is e.g. TEST101, but sometimes a variable that is called courseID also contains a course code string.
1447
     * However, there is also a integer course_id that uniquely identifies the course.
1448
     * ywarnier:> Now the course_id has been removed (25/1/2005)
1449
     * The databases are als very inconsistent in this.
1450
     *
1451
     * @param array $groupInfo
1452
     *
1453
     * @author Chrisptophe Gesche <[email protected]>,
1454
     *         Hugues Peeters     <[email protected]> - original version
1455
     * @author Roan Embrechts - virtual course support, code cleaning
1456
     * @author Bart Mollet - code cleaning, use other GroupManager-functions
1457
     *
1458
     * @return bool
1459
     */
1460
    public static function fillGroupWithUsers($groupInfo)
1461
    {
1462
        $_course = api_get_course_info();
1463
        if (empty($_course) || empty($groupInfo)) {
1464
            return false;
1465
        }
1466
        $session_id = api_get_session_id();
1467
        $complete_user_list = CourseManager::get_user_list_from_course_code(
1468
            $_course['code'],
1469
            $session_id
1470
        );
1471
        $groupIid = $groupInfo['iid'];
1472
        $category = self::get_category_from_group($groupIid);
1473
1474
        // Getting max numbers of user from group
1475
        $maxNumberStudents = empty($groupInfo['maximum_number_of_students']) ? self::INFINITE : $groupInfo['maximum_number_of_students'];
1476
        $groupsPerUser = self::INFINITE;
1477
        $categoryId = 0;
1478
        if ($category) {
1479
            $groupsPerUser = empty($category['groups_per_user']) ? self::INFINITE : $category['groups_per_user'];
1480
            $maxNumberStudentsCategory = empty($category['max_student']) ? self::INFINITE : $category['max_student'];
1481
            $categoryId = $category['id'];
1482
            if ($maxNumberStudentsCategory < $maxNumberStudents) {
1483
                $maxNumberStudents = $maxNumberStudentsCategory;
1484
            }
1485
        }
1486
1487
        $usersToAdd = [];
1488
        foreach ($complete_user_list as $userInfo) {
1489
            $isSubscribed = self::is_subscribed($userInfo['user_id'], $groupInfo);
1490
            if ($isSubscribed) {
1491
                continue;
1492
            }
1493
            $numberOfGroups = self::user_in_number_of_groups(
1494
                $userInfo['user_id'],
1495
                $categoryId
1496
            );
1497
            if ($groupsPerUser > $numberOfGroups) {
1498
                $usersToAdd[] = $userInfo['user_id'];
1499
            }
1500
            if (count($usersToAdd) == $maxNumberStudents) {
1501
                break;
1502
            }
1503
        }
1504
1505
        foreach ($usersToAdd as $userId) {
1506
            self::subscribe_users($userId, $groupInfo);
1507
        }
1508
    }
1509
1510
    /**
1511
     * Get the number of students in a group.
1512
     *
1513
     * @param int $group_id id
1514
     *
1515
     * @return int number of students in the given group
1516
     */
1517
    public static function number_of_students($group_id, $course_id = null)
1518
    {
1519
        $table = Database::get_course_table(TABLE_GROUP_USER);
1520
        $group_id = (int) $group_id;
1521
        $course_id = (int) $course_id;
1522
1523
        if (empty($course_id)) {
1524
            $course_id = api_get_course_int_id();
1525
        }
1526
        $sql = "SELECT COUNT(*) AS number_of_students
1527
                FROM $table
1528
                WHERE c_id = $course_id AND group_id = $group_id";
1529
        $result = Database::query($sql);
1530
        $db_object = Database::fetch_object($result);
1531
1532
        return $db_object->number_of_students;
1533
    }
1534
1535
    /**
1536
     * Maximum number of students in a group.
1537
     *
1538
     * @param int $group_id iid
1539
     *
1540
     * @return int maximum number of students in the given group
1541
     */
1542
    public static function maximum_number_of_students($group_id)
1543
    {
1544
        $table = Database::get_course_table(TABLE_GROUP);
1545
        $group_id = (int) $group_id;
1546
        $course_id = api_get_course_int_id();
1547
        $sql = "SELECT max_student FROM $table
1548
                WHERE iid = $group_id";
1549
        $db_result = Database::query($sql);
1550
        $db_object = Database::fetch_object($db_result);
1551
        if (0 == $db_object->max_student) {
1552
            return self::INFINITE;
1553
        }
1554
1555
        return $db_object->max_student;
1556
    }
1557
1558
    /**
1559
     * Number of groups of a user.
1560
     *
1561
     * @param int $user_id
1562
     * @param int $cat_id
1563
     *
1564
     * @return int the number of groups the user is subscribed in
1565
     */
1566
    public static function user_in_number_of_groups($user_id, $cat_id = 0)
1567
    {
1568
        $table_group_user = Database::get_course_table(TABLE_GROUP_USER);
1569
        $table_group = Database::get_course_table(TABLE_GROUP);
1570
        $user_id = (int) $user_id;
1571
        $cat_id = (int) $cat_id;
1572
1573
        $course_id = api_get_course_int_id();
1574
        $cat_condition = '';
1575
        if (!empty($cat_id)) {
1576
            $cat_condition = " AND g.category_id =  $cat_id ";
1577
        }
1578
1579
        $sql = "SELECT COUNT(*) AS number_of_groups
1580
                FROM $table_group_user gu
1581
                INNER JOIN $table_group g
1582
                ON (g.iid = gu.group_id)
1583
                WHERE
1584
                    gu.user_id = $user_id
1585
                    $cat_condition";
1586
1587
        $result = Database::query($sql);
1588
        $db_object = Database::fetch_object($result);
1589
1590
        return $db_object->number_of_groups;
1591
    }
1592
1593
    /**
1594
     * Is sef-registration allowed?
1595
     *
1596
     * @param int   $user_id
1597
     * @param array $groupInfo
1598
     *
1599
     * @return bool TRUE if self-registration is allowed in the given group
1600
     */
1601
    public static function is_self_registration_allowed($user_id, $groupInfo)
1602
    {
1603
        $course_id = api_get_course_int_id();
1604
        if (empty($user_id)) {
1605
            return false;
1606
        }
1607
1608
        $groupIid = $groupInfo['iid'];
1609
        $table = Database::get_course_table(TABLE_GROUP);
1610
        if (isset($groupIid)) {
1611
            $sql = "SELECT status, self_registration_allowed
1612
                    FROM $table
1613
                    WHERE iid = $groupIid";
1614
            $result = Database::query($sql);
1615
            $group = Database::fetch_object($result);
1616
1617
            if (0 == $group->status || 1 != $group->self_registration_allowed) {
1618
                return false;
1619
            }
1620
1621
            return self::canUserSubscribe($user_id, $groupInfo);
1622
        }
1623
1624
        return false;
1625
    }
1626
1627
    /**
1628
     * Is sef-unregistration allowed?
1629
     *
1630
     * @param int   $user_id
1631
     * @param array $groupInfo
1632
     *
1633
     * @return bool TRUE if self-unregistration is allowed in the given group
1634
     */
1635
    public static function is_self_unregistration_allowed($user_id, $groupInfo)
1636
    {
1637
        if (empty($user_id) || empty($groupInfo)) {
1638
            return false;
1639
        }
1640
        $groupIid = $groupInfo['iid'];
1641
        $table = Database::get_course_table(TABLE_GROUP);
1642
        $course_id = api_get_course_int_id();
1643
1644
        $sql = "SELECT status, self_unregistration_allowed
1645
                FROM $table
1646
                WHERE iid = $groupIid";
1647
        $result = Database::query($sql);
1648
        $group = Database::fetch_object($result);
1649
1650
        if (0 == $group->status || 1 != $group->self_unregistration_allowed) {
1651
            return false;
1652
        }
1653
1654
        return self::is_subscribed($user_id, $groupInfo);
1655
    }
1656
1657
    /**
1658
     * Is user subscribed in group?
1659
     *
1660
     * @param int   $user_id
1661
     * @param array $groupInfo
1662
     *
1663
     * @return bool TRUE if given user is subscribed in given group
1664
     */
1665
    public static function is_subscribed($user_id, $groupInfo)
1666
    {
1667
        $course_id = api_get_course_int_id();
1668
        if (empty($user_id) || empty($groupInfo) || empty($course_id)) {
1669
            return false;
1670
        }
1671
        $table = Database::get_course_table(TABLE_GROUP_USER);
1672
        $group_id = intval($groupInfo['iid']);
1673
        $user_id = intval($user_id);
1674
1675
        $sql = "SELECT 1 FROM $table
1676
                WHERE
1677
                    group_id = $group_id AND
1678
                    user_id = $user_id
1679
                ";
1680
        $result = Database::query($sql);
1681
1682
        return Database::num_rows($result) > 0;
1683
    }
1684
1685
    /**
1686
     * Can a user subscribe to a specified group in a course.
1687
     *
1688
     * @param int   $user_id
1689
     * @param array $groupInfo
1690
     * @param bool  $checkMaxNumberStudents
1691
     *
1692
     * @return bool TRUE if given user  can be subscribed in given group
1693
     */
1694
    public static function canUserSubscribe(
1695
        $user_id,
1696
        $groupInfo,
1697
        $checkMaxNumberStudents = true
1698
    ) {
1699
        $group_id = $groupInfo['id'];
1700
        $groupIid = $groupInfo['iid'];
1701
        if ($checkMaxNumberStudents) {
1702
            $category = self::get_category_from_group($groupIid);
1703
            if ($category) {
1704
                if (self::GROUP_PER_MEMBER_NO_LIMIT == $category['groups_per_user']) {
1705
                    $category['groups_per_user'] = self::INFINITE;
1706
                }
1707
                $result = self::user_in_number_of_groups($user_id, $category['iid']) < $category['groups_per_user'];
1708
                if (false == $result) {
1709
                    return false;
1710
                }
1711
            }
1712
1713
            $result = self::number_of_students($group_id) < self::maximum_number_of_students($groupIid);
1714
1715
            if (false == $result) {
1716
                return false;
1717
            }
1718
        }
1719
1720
        $result = self::is_tutor_of_group($user_id, $groupInfo);
1721
1722
        if ($result) {
1723
            return false;
1724
        }
1725
1726
        $result = self::is_subscribed($user_id, $groupInfo);
1727
1728
        if ($result) {
1729
            return false;
1730
        }
1731
1732
        return true;
1733
    }
1734
1735
    /**
1736
     * Get all subscribed users (members) from a group.
1737
     *
1738
     * @param array $groupInfo
1739
     *
1740
     * @return array An array with information of all users from the given group.
1741
     *               (user_id, firstname, lastname, email)
1742
     */
1743
    public static function get_subscribed_users($groupInfo)
1744
    {
1745
        if (empty($groupInfo)) {
1746
            return [];
1747
        }
1748
1749
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1750
        $table_group_user = Database::get_course_table(TABLE_GROUP_USER);
1751
        $order_clause = api_sort_by_first_name() ? ' ORDER BY u.firstname, u.lastname' : ' ORDER BY u.lastname, u.firstname';
1752
        $orderListByOfficialCode = api_get_setting('order_user_list_by_official_code');
1753
        if ('true' === $orderListByOfficialCode) {
1754
            $order_clause = ' ORDER BY u.official_code, u.firstname, u.lastname';
1755
        }
1756
1757
        $group_id = (int) $groupInfo['iid'];
1758
1759
        if (empty($group_id)) {
1760
            return [];
1761
        }
1762
1763
        $course_id = api_get_course_int_id();
1764
1765
        $sql = "SELECT
1766
                    ug.iid,
1767
                    u.id as user_id,
1768
                    u.lastname,
1769
                    u.firstname,
1770
                    u.email,
1771
                    u.username
1772
                FROM $table_user u
1773
                INNER JOIN $table_group_user ug
1774
                ON (ug.user_id = u.id)
1775
                WHERE
1776
                      ug.group_id = $group_id
1777
                $order_clause";
1778
1779
        $db_result = Database::query($sql);
1780
        $users = [];
1781
        while ($user = Database::fetch_object($db_result)) {
1782
            $users[$user->user_id] = [
1783
                'user_id' => $user->user_id,
1784
                'firstname' => $user->firstname,
1785
                'lastname' => $user->lastname,
1786
                'email' => $user->email,
1787
                'username' => $user->username,
1788
            ];
1789
        }
1790
1791
        return $users;
1792
    }
1793
1794
    /**
1795
     * @author Patrick Cool <[email protected]>, Ghent University
1796
     * Get all subscribed tutors of a group
1797
     *
1798
     * @param array $groupInfo
1799
     *
1800
     * @return array An array with information of all users from the given group.
1801
     *               (user_id, firstname, lastname, email)
1802
     */
1803
    public static function get_subscribed_tutors($groupInfo, $id_only = false)
1804
    {
1805
        if (empty($groupInfo)) {
1806
            return [];
1807
        }
1808
1809
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1810
        $table_group_tutor = Database::get_course_table(TABLE_GROUP_TUTOR);
1811
        $order_clause = api_sort_by_first_name() ? ' ORDER BY u.firstname, u.lastname' : ' ORDER BY u.lastname, u.firstname';
1812
1813
        $orderListByOfficialCode = api_get_setting('order_user_list_by_official_code');
1814
        if ('true' === $orderListByOfficialCode) {
1815
            $order_clause = ' ORDER BY u.official_code, u.firstname, u.lastname';
1816
        }
1817
1818
        $group_id = (int) $groupInfo['iid'];
1819
        $course_id = api_get_course_int_id();
1820
1821
        $sql = "SELECT u.id, u.lastname, u.firstname, u.email
1822
                FROM $table_user u
1823
                INNER JOIN $table_group_tutor tg
1824
                ON (tg.user_id = u.id)
1825
                WHERE
1826
                    tg.group_id = $group_id
1827
                    $order_clause
1828
                ";
1829
        $db_result = Database::query($sql);
1830
        $users = [];
1831
        while ($user = Database::fetch_object($db_result)) {
1832
            if (!$id_only) {
1833
                $member['user_id'] = $user->id;
1834
                $member['firstname'] = $user->firstname;
1835
                $member['lastname'] = $user->lastname;
1836
                $member['email'] = $user->email;
1837
                $users[] = $member;
1838
            } else {
1839
                $users[] = $user->id;
1840
            }
1841
        }
1842
1843
        return $users;
1844
    }
1845
1846
    /**
1847
     * Subscribe user(s) to a specified group in current course (as a student).
1848
     *
1849
     * @param mixed $user_ids  Can be an array with user-id's or a single user-id
1850
     * @param array $groupInfo
1851
     * @param int   $course_id
1852
     *
1853
     * @return bool TRUE if successful
1854
     */
1855
    public static function subscribe_users($user_ids, $groupInfo, $course_id = null)
1856
    {
1857
        $user_ids = is_array($user_ids) ? $user_ids : [$user_ids];
1858
        $course_id = empty($course_id) ? api_get_course_int_id() : (int) $course_id;
1859
        $group_id = $groupInfo['id'];
1860
1861
        if (!empty($user_ids)) {
1862
            $table = Database::get_course_table(TABLE_GROUP_USER);
1863
            foreach ($user_ids as $user_id) {
1864
                if (self::canUserSubscribe($user_id, $groupInfo)) {
1865
                    $user_id = (int) $user_id;
1866
                    $sql = "INSERT INTO $table (c_id, user_id, group_id, status, role)
1867
                            VALUES ('$course_id', '".$user_id."', '".$group_id."', 0, '')";
1868
                    Database::query($sql);
1869
                }
1870
            }
1871
        }
1872
1873
        return true;
1874
    }
1875
1876
    /**
1877
     * Subscribe tutor(s) to a specified group in current course.
1878
     *
1879
     * @param mixed $user_ids  Can be an array with user-id's or a single user-id
1880
     * @param array $groupInfo
1881
     * @param int   $course_id
1882
     *
1883
     * @author Patrick Cool <[email protected]>, Ghent University
1884
     *
1885
     * @see subscribe_users. This function is almost an exact copy of that function.
1886
     *
1887
     * @return bool TRUE if successful
1888
     */
1889
    public static function subscribe_tutors($user_ids, $groupInfo, $course_id = 0)
1890
    {
1891
        $user_ids = is_array($user_ids) ? $user_ids : [$user_ids];
1892
        $result = true;
1893
        $course_id = isset($course_id) && !empty($course_id) ? intval($course_id) : api_get_course_int_id();
1894
        $table_group_tutor = Database::get_course_table(TABLE_GROUP_TUTOR);
1895
        $groupId = (int) $groupInfo['id'];
1896
1897
        foreach ($user_ids as $user_id) {
1898
            $user_id = intval($user_id);
1899
            if (self::canUserSubscribe($user_id, $groupInfo, false)) {
1900
                $sql = 'INSERT INTO '.$table_group_tutor." (c_id, user_id, group_id)
1901
                        VALUES ('$course_id', '".$user_id."', '".$groupId."')";
1902
                $result = Database::query($sql);
1903
            }
1904
        }
1905
1906
        return $result;
1907
    }
1908
1909
    /**
1910
     * Unsubscribe user(s) from a specified group in current course.
1911
     *
1912
     * @param mixed $user_ids  Can be an array with user-id's or a single user-id
1913
     * @param array $groupInfo
1914
     *
1915
     * @return bool TRUE if successful
1916
     */
1917
    public static function unsubscribe_users($user_ids, $groupInfo)
1918
    {
1919
        $user_ids = is_array($user_ids) ? $user_ids : [$user_ids];
1920
        $table_group_user = Database::get_course_table(TABLE_GROUP_USER);
1921
        $group_id = intval($groupInfo['id']);
1922
        $course_id = api_get_course_int_id();
1923
        $sql = 'DELETE FROM '.$table_group_user.'
1924
                WHERE
1925
                    group_id = '.$group_id.' AND
1926
                    user_id IN ('.implode(',', $user_ids).')
1927
                ';
1928
        Database::query($sql);
1929
    }
1930
1931
    /**
1932
     * Unsubscribe all users from one or more groups.
1933
     *
1934
     * @param array $groupInfo
1935
     *
1936
     * @return bool TRUE if successful
1937
     */
1938
    public static function unsubscribe_all_users($groupInfo)
1939
    {
1940
        $course_id = api_get_course_int_id();
1941
        $groupId = (int) $groupInfo['id'];
1942
        if (empty($course_id) || empty($groupId)) {
1943
            return false;
1944
        }
1945
1946
        $table_group_user = Database::get_course_table(TABLE_GROUP_USER);
1947
        $sql = "DELETE FROM $table_group_user
1948
                WHERE
1949
                    group_id = $groupId ";
1950
1951
        return Database::query($sql);
1952
    }
1953
1954
    /**
1955
     * Unsubscribe all tutors from one or more groups.
1956
     *
1957
     * @param int $groupId iid
1958
     *
1959
     * @see unsubscribe_all_users. This function is almost an exact copy of that function.
1960
     *
1961
     * @return bool TRUE if successful
1962
     *
1963
     * @author Patrick Cool <[email protected]>, Ghent University
1964
     */
1965
    public static function unsubscribe_all_tutors($groupId)
1966
    {
1967
        $courseId = api_get_course_int_id();
1968
        $groupId = (int) $groupId;
1969
1970
        if (empty($courseId) || empty($groupId)) {
1971
            return false;
1972
        }
1973
1974
        if (!empty($groupId)) {
1975
            $table_group_tutor = Database::get_course_table(TABLE_GROUP_TUTOR);
1976
            $sql = "DELETE FROM $table_group_tutor
1977
                    WHERE group_id = $groupId ";
1978
            $result = Database::query($sql);
1979
1980
            return $result;
1981
        }
1982
1983
        return true;
1984
    }
1985
1986
    /**
1987
     * Is the user a tutor of this group?
1988
     *
1989
     * @param int   $user_id   the id of the user
1990
     * @param array $groupInfo
1991
     * @param int   $courseId
1992
     *
1993
     * @return bool true/false
1994
     *
1995
     * @todo use the function user_has_access that includes this function
1996
     *
1997
     * @author Patrick Cool <[email protected]>, Ghent University
1998
     */
1999
    public static function is_tutor_of_group($user_id, $groupInfo, $courseId = 0)
2000
    {
2001
        if (empty($groupInfo)) {
2002
            return false;
2003
        }
2004
2005
        $courseId = empty($courseId) ? api_get_course_int_id() : (int) $courseId;
2006
        if (empty($courseId)) {
2007
            return false;
2008
        }
2009
2010
        $user_id = (int) $user_id;
2011
        $group_id = (int) $groupInfo['id'];
2012
2013
        $table = Database::get_course_table(TABLE_GROUP_TUTOR);
2014
2015
        $sql = "SELECT * FROM $table
2016
                WHERE
2017
                    user_id = $user_id AND
2018
                    group_id = $group_id";
2019
        $result = Database::query($sql);
2020
        if (Database::num_rows($result) > 0) {
2021
            return true;
2022
        }
2023
2024
        return false;
2025
    }
2026
2027
    /**
2028
     * Is the user part of this group? This can be a tutor or a normal member
2029
     * you should use this function if the access to a tool or functionality is
2030
     * restricted to the people who are actually in the group
2031
     * before you had to check if the user was
2032
     * 1. a member of the group OR
2033
     * 2. a tutor of the group. This function combines both.
2034
     *
2035
     * @param int   $user_id   the id of the user
2036
     * @param array $groupInfo
2037
     *
2038
     * @return bool true/false
2039
     *
2040
     * @author Patrick Cool <[email protected]>, Ghent University
2041
     */
2042
    public static function is_user_in_group($user_id, $groupInfo)
2043
    {
2044
        $member = self::is_subscribed($user_id, $groupInfo);
2045
        if ($member) {
2046
            return true;
2047
        }
2048
2049
        $tutor = self::is_tutor_of_group($user_id, $groupInfo);
2050
        if ($tutor) {
2051
            return true;
2052
        }
2053
2054
        return false;
2055
    }
2056
2057
    /**
2058
     * Get all group's from a given course in which a given user is unsubscribed.
2059
     *
2060
     * @author  Patrick Cool
2061
     *
2062
     * @param int $course_id retrieve the groups for
2063
     * @param int $user_id   the ID of the user you want to know all its group memberships
2064
     *
2065
     * @return array
2066
     */
2067
    public static function get_group_ids($course_id, $user_id)
2068
    {
2069
        $groups = [];
2070
        $tbl_group = Database::get_course_table(TABLE_GROUP_USER);
2071
        $tbl_group_tutor = Database::get_course_table(TABLE_GROUP_TUTOR);
2072
        $user_id = intval($user_id);
2073
        $course_id = intval($course_id);
2074
2075
        $sql = "SELECT group_id FROM $tbl_group
2076
                WHERE user_id = '$user_id'";
2077
        $result = Database::query($sql);
2078
2079
        if ($result) {
2080
            while ($row = Database::fetch_array($result)) {
2081
                $groups[] = $row['group_id'];
2082
            }
2083
        }
2084
2085
        //Also loading if i'm the tutor
2086
        $sql = "SELECT group_id FROM $tbl_group_tutor
2087
                WHERE user_id = '$user_id'";
2088
        $result = Database::query($sql);
2089
        if ($result) {
2090
            while ($row = Database::fetch_array($result)) {
2091
                $groups[] = $row['group_id'];
2092
            }
2093
        }
2094
        if (!empty($groups)) {
2095
            array_filter($groups);
2096
        }
2097
2098
        return $groups;
2099
    }
2100
2101
    /**
2102
     * Check if a user has access to a certain group tool.
2103
     *
2104
     * @param int    $user_id  The user id
2105
     * @param int    $group_id The group iid
2106
     * @param string $tool     The tool to check the access rights. This should be
2107
     *                         one of constants: GROUP_TOOL_DOCUMENTS
2108
     *
2109
     * @return bool true if the given user has access to the given tool in the
2110
     *              given course
2111
     */
2112
    public static function user_has_access($user_id, $group_id, $tool)
2113
    {
2114
        // Admin have access everywhere
2115
        if (api_is_platform_admin()) {
2116
            return true;
2117
        }
2118
2119
        // Course admin also have access to everything
2120
        if (api_is_allowed_to_edit(false, true, true)) {
2121
            return true;
2122
        }
2123
2124
        switch ($tool) {
2125
            case self::GROUP_TOOL_FORUM:
2126
                $key = 'forum_state';
2127
                break;
2128
            case self::GROUP_TOOL_DOCUMENTS:
2129
                $key = 'doc_state';
2130
                break;
2131
            case self::GROUP_TOOL_CALENDAR:
2132
                $key = 'calendar_state';
2133
                break;
2134
            case self::GROUP_TOOL_ANNOUNCEMENT:
2135
                $key = 'announcements_state';
2136
                break;
2137
            case self::GROUP_TOOL_WORK:
2138
                $key = 'work_state';
2139
                break;
2140
            case self::GROUP_TOOL_WIKI:
2141
                $key = 'wiki_state';
2142
                break;
2143
            case self::GROUP_TOOL_CHAT:
2144
                $key = 'chat_state';
2145
                break;
2146
            default:
2147
                return false;
2148
        }
2149
2150
        // Check group properties
2151
        $groupInfo = self::get_group_properties($group_id, true);
2152
2153
        if (empty($groupInfo)) {
2154
            return false;
2155
        }
2156
2157
        if (0 == $groupInfo['status']) {
2158
            return false;
2159
        }
2160
2161
        if (!isset($groupInfo[$key])) {
2162
            return false;
2163
        }
2164
2165
        $status = $groupInfo[$key];
2166
2167
        switch ($status) {
2168
            case self::TOOL_NOT_AVAILABLE:
2169
                return false;
2170
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
2171
            case self::TOOL_PUBLIC:
2172
                return true;
2173
                break;
2174
            case self::TOOL_PRIVATE:
2175
                $userIsInGroup = self::is_user_in_group($user_id, $groupInfo);
2176
                if ($userIsInGroup) {
2177
                    return true;
2178
                }
2179
                break;
2180
            case self::TOOL_PRIVATE_BETWEEN_USERS:
2181
                // Only works for announcements for now
2182
                $userIsInGroup = self::is_user_in_group($user_id, $groupInfo);
2183
                if ($userIsInGroup && self::GROUP_TOOL_ANNOUNCEMENT == $tool) {
2184
                    return true;
2185
                }
2186
                break;
2187
        }
2188
2189
        return false;
2190
    }
2191
2192
    /**
2193
     * @param int   $userId
2194
     * @param array $groupInfo
2195
     * @param int   $sessionId
2196
     *
2197
     * @return bool
2198
     */
2199
    public static function userHasAccessToBrowse($userId, $groupInfo, $sessionId = 0)
2200
    {
2201
        if (empty($groupInfo)) {
2202
            return false;
2203
        }
2204
2205
        if (api_is_platform_admin()) {
2206
            return true;
2207
        }
2208
2209
        if (api_is_allowed_to_edit(false, true, true)) {
2210
            return true;
2211
        }
2212
2213
        if (!empty($sessionId)) {
2214
            if (api_is_coach($sessionId, api_get_course_int_id())) {
2215
                return true;
2216
            }
2217
2218
            if (api_is_drh()) {
2219
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
2220
                    return true;
2221
                }
2222
            }
2223
        }
2224
2225
        $groupId = $groupInfo['iid'];
2226
        if (self::is_tutor_of_group($userId, $groupInfo)) {
2227
            return true;
2228
        }
2229
2230
        if (0 == $groupInfo['status']) {
2231
            return false;
2232
        }
2233
2234
        if (self::user_has_access($userId, $groupId, self::GROUP_TOOL_FORUM) ||
2235
            self::user_has_access($userId, $groupId, self::GROUP_TOOL_DOCUMENTS) ||
2236
            self::user_has_access($userId, $groupId, self::GROUP_TOOL_CALENDAR) ||
2237
            self::user_has_access($userId, $groupId, self::GROUP_TOOL_ANNOUNCEMENT) ||
2238
            self::user_has_access($userId, $groupId, self::GROUP_TOOL_WORK) ||
2239
            self::user_has_access($userId, $groupId, self::GROUP_TOOL_WIKI) ||
2240
            self::user_has_access($userId, $groupId, self::GROUP_TOOL_CHAT)
2241
        ) {
2242
            return true;
2243
        }
2244
2245
        if (api_is_session_general_coach() && $groupInfo['session_id'] == $sessionId) {
2246
            return true;
2247
        }
2248
2249
        return false;
2250
    }
2251
2252
    /**
2253
     * Get all groups where a specific user is subscribed.
2254
     *
2255
     * @param int $user_id
2256
     *
2257
     * @return array
2258
     */
2259
    public static function get_user_group_name($user_id)
2260
    {
2261
        $table_group_user = Database::get_course_table(TABLE_GROUP_USER);
2262
        $table_group = Database::get_course_table(TABLE_GROUP);
2263
        $user_id = intval($user_id);
2264
        $course_id = api_get_course_int_id();
2265
        $sql = "SELECT name
2266
                FROM $table_group g
2267
                INNER JOIN $table_group_user gu
2268
                ON (gu.group_id = g.iid)
2269
                WHERE
2270
                  gu.user_id = $user_id";
2271
        $res = Database::query($sql);
2272
        $groups = [];
2273
        while ($group = Database::fetch_array($res)) {
2274
            $groups[] .= $group['name'];
2275
        }
2276
2277
        return $groups;
2278
    }
2279
2280
    /**
2281
     * Get all groups where a specific user is subscribed.
2282
     *
2283
     * @param int      $user_id
2284
     * @param int      $courseId
2285
     * @param int|null $sessionId
2286
     *
2287
     * @return array
2288
     */
2289
    public static function getAllGroupPerUserSubscription($user_id, $courseId = 0, $sessionId = null)
2290
    {
2291
        $table_group_user = Database::get_course_table(TABLE_GROUP_USER);
2292
        $table_tutor_user = Database::get_course_table(TABLE_GROUP_TUTOR);
2293
        $table_group = Database::get_course_table(TABLE_GROUP);
2294
        $user_id = (int) $user_id;
2295
        $courseId = empty($courseId) ? api_get_course_int_id() : (int) $courseId;
2296
2297
        $sql = "SELECT DISTINCT g.*
2298
               FROM $table_group g
2299
               LEFT JOIN $table_group_user gu
2300
               ON (gu.group_id = g.iid)
2301
               LEFT JOIN $table_tutor_user tu
2302
               ON (tu.group_id = g.iid)
2303
               WHERE
2304
                  (gu.user_id = $user_id OR tu.user_id = $user_id) ";
2305
2306
        if (null !== $sessionId) {
2307
            $sessionId = (int) $sessionId;
2308
            $sql .= " AND g.session_id = $sessionId ";
2309
        }
2310
2311
        $res = Database::query($sql);
2312
        $groups = [];
2313
        while ($group = Database::fetch_array($res, 'ASSOC')) {
2314
            $groups[] = $group;
2315
        }
2316
2317
        return $groups;
2318
    }
2319
2320
    /**
2321
     * @param array $group_list
2322
     * @param int   $category_id
2323
     *
2324
     * @return string
2325
     */
2326
    public static function process_groups($group_list, $category_id = 0)
2327
    {
2328
        $charset = 'UTF-8';
2329
        $category_id = (int) $category_id;
2330
        $totalRegistered = 0;
2331
        $group_data = [];
2332
        $user_info = api_get_user_info();
2333
        $session_id = api_get_session_id();
2334
        $user_id = $user_info['user_id'];
2335
        $hideGroup = api_get_setting('hide_course_group_if_no_tools_available');
2336
        $extraField = new ExtraField('survey');
2337
        $surveyGroupExists = $extraField->get_handler_field_info_by_field_variable('group_id') ? true : false;
2338
        $url = api_get_path(WEB_CODE_PATH).'group/';
2339
2340
        foreach ($group_list as $this_group) {
2341
            $groupId = $this_group['iid'];
2342
            // Validation when belongs to a session
2343
            $session_img = '';
2344
            //$session_img = api_get_session_image($this_group['session_id'], $user_info['status']);
2345
2346
            // All the tutors of this group
2347
            $tutors = self::get_subscribed_tutors($this_group, true);
2348
            $isMember = self::is_subscribed($user_id, $this_group);
2349
2350
            // Create a new table-row
2351
            $row = [];
2352
            // Checkbox
2353
            if (api_is_allowed_to_edit(false, true) && count($group_list) > 1) {
2354
                $row[] = $this_group['iid'];
2355
            }
2356
2357
            if (self::userHasAccessToBrowse($user_id, $this_group, $session_id)) {
2358
                // Group name
2359
                $groupNameClass = null;
2360
                if (0 == $this_group['status']) {
2361
                    $groupNameClass = 'muted';
2362
                }
2363
2364
                $group_name = '<a
2365
                    class="'.$groupNameClass.'"
2366
                    href="group_space.php?'.api_get_cidreq(true, false).'&gid='.$groupId.'">'.
2367
                    Security::remove_XSS($this_group['name']).'</a> ';
2368
2369
                $group_name2 = '';
2370
                if (api_get_configuration_value('extra')) {
2371
                    $group_name2 = '<a href="group_space_tracking.php?cid='.api_get_course_int_id().'&gid='
2372
                        .$groupId.'">'.get_lang('suivi_de').''.stripslashes($this_group['name']).'</a>';
2373
                }
2374
2375
                if (!empty($user_id) && !empty($this_group['id_tutor']) && $user_id == $this_group['id_tutor']) {
2376
                    $group_name .= Display::label(get_lang('my supervision'), 'success');
2377
                } elseif ($isMember) {
2378
                    $group_name .= Display::label(get_lang('my group'), 'success');
2379
                }
2380
2381
                if (api_is_allowed_to_edit() && !empty($this_group['session_name'])) {
2382
                    $group_name .= ' ('.$this_group['session_name'].')';
2383
                }
2384
                $group_name .= $session_img;
2385
                $row[] = $group_name.$group_name2.'<br />'.stripslashes(trim($this_group['description']));
2386
            } else {
2387
                if ('true' === $hideGroup) {
2388
                    continue;
2389
                }
2390
                $row[] = $this_group['name'].'<br />'.stripslashes(trim($this_group['description']));
2391
            }
2392
2393
            // Tutor name
2394
            $tutor_info = '';
2395
            if (count($tutors) > 0) {
2396
                foreach ($tutors as $tutor_id) {
2397
                    $tutor = api_get_user_info($tutor_id);
2398
                    $username = api_htmlentities(
2399
                        sprintf(get_lang('Login: %s'), $tutor['username']),
2400
                        ENT_QUOTES
2401
                    );
2402
                    if ('true' === api_get_setting('show_email_addresses')) {
2403
                        $tutor_info .= Display::tag(
2404
                            'span',
2405
                            Display::encrypted_mailto_link(
2406
                                $tutor['mail'],
2407
                                $tutor['complete_name']
2408
                            ),
2409
                            ['title' => $username]
2410
                        ).', ';
2411
                    } else {
2412
                        if (api_is_allowed_to_edit()) {
2413
                            $tutor_info .= Display::tag(
2414
                            'span',
2415
                                Display::encrypted_mailto_link(
2416
                                    $tutor['mail'],
2417
                                    $tutor['complete_name_with_username']
2418
                                ),
2419
                                ['title' => $username]
2420
                            ).', ';
2421
                        } else {
2422
                            $tutor_info .= Display::tag(
2423
                                'span',
2424
                                $tutor['complete_name'],
2425
                                ['title' => $username]
2426
                            ).', ';
2427
                        }
2428
                    }
2429
                }
2430
            }
2431
2432
            $tutor_info = api_substr(
2433
                $tutor_info,
2434
                0,
2435
                api_strlen($tutor_info) - 2
2436
            );
2437
            $row[] = $tutor_info;
2438
2439
            // Max number of members in group
2440
            $max_members = self::MEMBER_PER_GROUP_NO_LIMIT == $this_group['maxStudent'] ? ' ' : ' / '.$this_group['maxStudent'];
2441
2442
            // Number of members in group
2443
            $row[] = $this_group['maxStudent'].$max_members;
2444
2445
            // Self-registration / unregistration
2446
            if (!api_is_allowed_to_edit(false, true)) {
2447
                if (self::is_self_registration_allowed($user_id, $this_group)) {
2448
                    $row[] = '<a class = "btn btn-default" href="group.php?'.api_get_cidreq().'&category='.$category_id.'&action=self_reg&group_id='.$groupId.'" onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang('Please confirm your choice'), ENT_QUOTES, $charset))."'".')) return false;">'.get_lang('register').'</a>';
2449
                } elseif (self::is_self_unregistration_allowed($user_id, $this_group)) {
2450
                    $row[] = '<a class = "btn btn-default" href="group.php?'.api_get_cidreq().'&category='.$category_id.'&action=self_unreg&group_id='.$groupId.'" onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang('Please confirm your choice'), ENT_QUOTES, $charset))."'".')) return false;">'.get_lang('unregister').'</a>';
2451
                } else {
2452
                    $row[] = '-';
2453
                }
2454
            }
2455
2456
            // Edit-links
2457
            if (api_is_allowed_to_edit(false, true) &&
2458
                !(api_is_session_general_coach() && intval($this_group['session_id']) != $session_id)
2459
            ) {
2460
                $edit_actions = '<a href="'.$url.'settings.php?'.api_get_cidreq(true, false).'&gid='.$groupId.'"  title="'.get_lang('Edit').'">'.
2461
                    Display::return_icon('edit.png', get_lang('Edit this group'), '', ICON_SIZE_SMALL).'</a>&nbsp;';
2462
2463
                if (1 == $this_group['status']) {
2464
                    $edit_actions .= '<a href="'.api_get_self().'?'.api_get_cidreq(true, false).'&category='.$category_id.'&action=set_invisible&id='.$groupId.'" title="'.get_lang('Hide').'">'.
2465
                        Display::return_icon('visible.png', get_lang('Hide'), '', ICON_SIZE_SMALL).'</a>&nbsp;';
2466
                } else {
2467
                    $edit_actions .= '<a href="'.api_get_self().'?'.api_get_cidreq(true, false).'&category='.$category_id.'&action=set_visible&id='.$groupId.'" title="'.get_lang('Show').'">'.
2468
                        Display::return_icon('invisible.png', get_lang('Show'), '', ICON_SIZE_SMALL).'</a>&nbsp;';
2469
                }
2470
2471
                $edit_actions .= '<a href="'.$url.'member_settings.php?'.api_get_cidreq(true, false).'&gid='.$groupId.'"  title="'.get_lang('Group members').'">'.
2472
                    Display::return_icon('user.png', get_lang('Group members'), '', ICON_SIZE_SMALL).'</a>&nbsp;';
2473
2474
                $edit_actions .= '<a href="'.$url.'group_overview.php?action=export&type=xls&'.api_get_cidreq(true, false).'&id='.$groupId.'"  title="'.get_lang('Export users list').'">'.
2475
                    Display::return_icon('export_excel.png', get_lang('Export'), '', ICON_SIZE_SMALL).'</a>&nbsp;';
2476
2477
                if ($surveyGroupExists) {
2478
                    $edit_actions .= Display::url(
2479
                            Display::return_icon('survey.png', get_lang('ExportSurveyResults'), '', ICON_SIZE_SMALL),
2480
                            $url.'group_overview.php?action=export_surveys&'.api_get_cidreq(true, false).'&id='.$groupId
2481
                        ).'&nbsp;';
2482
                }
2483
                $edit_actions .= '<a href="'.api_get_self().'?'.api_get_cidreq(true, false).'&category='.$category_id.'&action=fill_one&id='.$groupId.'"
2484
                    onclick="javascript: if(!confirm('."'".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES))."'".')) return false;" title="'.get_lang('FillGroup').'">'.
2485
                    Display::return_icon('fill.png', get_lang('FillGroup'), '', ICON_SIZE_SMALL).'</a>&nbsp;';
2486
2487
                $edit_actions .= '<a href="'.api_get_self().'?'.api_get_cidreq(true, false).'&category='.$category_id.'&action=delete_one&id='.$groupId.'"
2488
                    onclick="javascript: if(!confirm('."'".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES))."'".')) return false;" title="'.get_lang('Delete').'">'.
2489
                    Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL).'</a>&nbsp;';
2490
2491
                $row[] = $edit_actions;
2492
            }
2493
            if (!empty($this_group['nbMember'])) {
2494
                $totalRegistered = $totalRegistered + $this_group['nbMember'];
2495
            }
2496
            $group_data[] = $row;
2497
        } // end loop
2498
2499
        // If no groups then don't show the table (only for students)
2500
        if (!api_is_allowed_to_edit(true, false)) {
2501
            if (empty($group_data)) {
2502
                return '';
2503
            }
2504
        }
2505
2506
        $table = new SortableTableFromArrayConfig(
2507
            $group_data,
2508
            1,
2509
            20,
2510
            'group_category_'.$category_id
2511
        );
2512
        $table->set_additional_parameters(['category' => $category_id]);
2513
        $column = 0;
2514
        if (api_is_allowed_to_edit(false, true) and count($group_list) > 1) {
2515
            $table->set_header($column++, '', false);
2516
        }
2517
        $table->set_header($column++, get_lang('Groups'));
2518
        $table->set_header($column++, get_lang('Group tutor'));
2519
        $table->set_header($column++, get_lang('Registered'), false);
2520
2521
        if (!api_is_allowed_to_edit(false, true)) {
2522
            // If self-registration allowed
2523
            $table->set_header($column++, get_lang('Registration'), false);
2524
        }
2525
2526
        if (api_is_allowed_to_edit(false, true)) {
2527
            // Only for course administrator
2528
            $table->set_header($column++, get_lang('Edit'), false);
2529
            $form_actions = [];
2530
            $form_actions['fill_selected'] = get_lang('Fill the group randomly with course students');
2531
            $form_actions['empty_selected'] = get_lang('unsubscribe all users');
2532
            $form_actions['delete_selected'] = get_lang('Delete');
2533
            if (count($group_list) > 1) {
2534
                $table->set_form_actions($form_actions, 'group');
2535
            }
2536
        }
2537
2538
        return $table->return_table();
2539
    }
2540
2541
    /**
2542
     * @param array $groupData
2543
     * @param bool  $deleteNotInArray
2544
     *
2545
     * @return array
2546
     */
2547
    public static function importCategoriesAndGroupsFromArray($groupData, $deleteNotInArray = false)
2548
    {
2549
        $result = [];
2550
        $elementsFound = [
2551
            'categories' => [],
2552
            'groups' => [],
2553
        ];
2554
2555
        $courseCode = api_get_course_id();
2556
        $sessionId = api_get_session_id();
2557
        $groupCategories = self::get_categories();
2558
2559
        if (empty($groupCategories)) {
2560
            $result['error'][] = get_lang('Create a category');
2561
2562
            return $result;
2563
        }
2564
2565
        foreach ($groupData as $data) {
2566
            $isCategory = empty($data['group']) ? true : false;
2567
            if ($isCategory) {
2568
                $categoryInfo = self::getCategoryByTitle($data['category']);
2569
                $categoryId = $categoryInfo['id'];
2570
2571
                if (!empty($categoryInfo)) {
2572
                    // Update
2573
                    self::update_category(
2574
                        $categoryId,
2575
                        $data['category'],
2576
                        $data['description'],
2577
                        $data['doc_state'],
2578
                        $data['work_state'],
2579
                        $data['calendar_state'],
2580
                        $data['announcements_state'],
2581
                        $data['forum_state'],
2582
                        $data['wiki_state'],
2583
                        $data['chat_state'],
2584
                        $data['self_reg_allowed'],
2585
                        $data['self_unreg_allowed'],
2586
                        $data['max_student'],
2587
                        $data['groups_per_user'],
2588
                        $data['document_access']
2589
                    );
2590
                    $data['category_id'] = $categoryId;
2591
                    $result['updated']['category'][] = $data;
2592
                } else {
2593
                    // Add
2594
                    $categoryId = self::create_category(
2595
                        $data['category'],
2596
                        $data['description'],
2597
                        $data['doc_state'],
2598
                        $data['work_state'],
2599
                        $data['calendar_state'],
2600
                        $data['announcements_state'],
2601
                        $data['forum_state'],
2602
                        $data['wiki_state'],
2603
                        $data['chat_state'],
2604
                        $data['self_reg_allowed'],
2605
                        $data['self_unreg_allowed'],
2606
                        $data['max_student'],
2607
                        $data['groups_per_user']
2608
                    );
2609
2610
                    if ($categoryId) {
2611
                        $data['category_id'] = $categoryId;
2612
                        $result['added']['category'][] = $data;
2613
                    }
2614
                }
2615
                $elementsFound['categories'][] = $categoryId;
2616
            } else {
2617
                $groupInfo = self::getGroupByName($data['group']);
2618
                $categoryInfo = [];
2619
                if (isset($data['category'])) {
2620
                    $categoryInfo = self::getCategoryByTitle($data['category']);
2621
                }
2622
                $categoryId = null;
2623
                if (!empty($categoryInfo)) {
2624
                    $categoryId = $categoryInfo['id'];
2625
                } else {
2626
                    if (!empty($groupCategories) && isset($groupCategories[0])) {
2627
                        $defaultGroupCategory = $groupCategories[0];
2628
                        $categoryId = $defaultGroupCategory['id'];
2629
                    }
2630
                }
2631
2632
                if (empty($groupInfo)) {
2633
                    // Add
2634
                    $groupId = self::create_group(
2635
                        $data['group'],
2636
                        $categoryId,
2637
                        null,
2638
                        $data['max_student']
2639
                    );
2640
2641
                    if ($groupId) {
2642
                        self::set_group_properties(
2643
                            $groupId,
2644
                            $data['group'],
2645
                            $data['description'],
2646
                            $data['max_student'],
2647
                            $data['doc_state'],
2648
                            $data['work_state'],
2649
                            $data['calendar_state'],
2650
                            $data['announcements_state'],
2651
                            $data['forum_state'],
2652
                            $data['wiki_state'],
2653
                            $data['chat_state'],
2654
                            $data['self_reg_allowed'],
2655
                            $data['self_unreg_allowed'],
2656
                            $categoryId
2657
                        );
2658
                        $data['group_id'] = $groupId;
2659
                        $result['added']['group'][] = $data;
2660
                    }
2661
                    $groupInfo = self::get_group_properties($groupId, true);
2662
                } else {
2663
                    // Update
2664
                    $groupId = $groupInfo['id'];
2665
                    self::set_group_properties(
2666
                        $groupId,
2667
                        $data['group'],
2668
                        $data['description'],
2669
                        $data['max_student'],
2670
                        $data['doc_state'],
2671
                        $data['work_state'],
2672
                        $data['calendar_state'],
2673
                        $data['announcements_state'],
2674
                        $data['forum_state'],
2675
                        $data['wiki_state'],
2676
                        $data['chat_state'],
2677
                        $data['self_reg_allowed'],
2678
                        $data['self_unreg_allowed'],
2679
                        $categoryId
2680
                    );
2681
2682
                    $data['group_id'] = $groupId;
2683
                    $result['updated']['group'][] = $data;
2684
                    $groupInfo = self::get_group_properties($groupId);
2685
                }
2686
2687
                $students = isset($data['students']) ? explode(',', $data['students']) : [];
2688
                if (!empty($students)) {
2689
                    $studentUserIdList = [];
2690
                    foreach ($students as $student) {
2691
                        $userInfo = api_get_user_info_from_username($student);
2692
2693
                        if (!$userInfo) {
2694
                            continue;
2695
                        }
2696
2697
                        if (!CourseManager::is_user_subscribed_in_course(
2698
                                $userInfo['user_id'],
2699
                                $courseCode,
2700
                                !empty($sessionId),
2701
                                $sessionId
2702
                            )
2703
                        ) {
2704
                            Display::addFlash(
2705
                                Display::return_message(
2706
                                    sprintf(
2707
                                        get_lang('Student %s is no subscribed to this course'),
2708
                                        $userInfo['complete_name']
2709
                                    ),
2710
                                    'warning'
2711
                                )
2712
                            );
2713
                            continue;
2714
                        }
2715
2716
                        $studentUserIdList[] = $userInfo['user_id'];
2717
                    }
2718
                    self::subscribe_users($studentUserIdList, $groupInfo);
2719
                }
2720
2721
                $tutors = isset($data['tutors']) ? explode(',', $data['tutors']) : [];
2722
                if (!empty($tutors)) {
2723
                    $tutorIdList = [];
2724
                    foreach ($tutors as $tutor) {
2725
                        $userInfo = api_get_user_info_from_username($tutor);
2726
2727
                        if (!$userInfo) {
2728
                            continue;
2729
                        }
2730
2731
                        if (!CourseManager::is_user_subscribed_in_course(
2732
                                $userInfo['user_id'],
2733
                                $courseCode,
2734
                                !empty($sessionId),
2735
                                $sessionId
2736
                            )
2737
                        ) {
2738
                            Display::addFlash(
2739
                                Display::return_message(
2740
                                    sprintf(get_lang('Tutor %s is no subscribed to this course'), $userInfo['complete_name']),
2741
                                    'warning'
2742
                                )
2743
                            );
2744
2745
                            continue;
2746
                        }
2747
2748
                        $tutorIdList[] = $userInfo['user_id'];
2749
                    }
2750
                    self::subscribe_tutors($tutorIdList, $groupInfo);
2751
                }
2752
2753
                $elementsFound['groups'][] = $groupId;
2754
            }
2755
        }
2756
2757
        if ($deleteNotInArray) {
2758
            // Check categories
2759
            $categories = self::get_categories();
2760
            foreach ($categories as $category) {
2761
                if (!in_array($category['id'], $elementsFound['categories'])) {
2762
                    self::delete_category($category['id']);
2763
                    $category['category'] = $category['title'];
2764
                    $result['deleted']['category'][] = $category;
2765
                }
2766
            }
2767
2768
            $groups = self::get_groups();
2769
            foreach ($groups as $group) {
2770
                if (!in_array($group['iid'], $elementsFound['groups'])) {
2771
                    self::deleteGroup($group);
2772
                    $group['group'] = $group['name'];
2773
                    $result['deleted']['group'][] = $group;
2774
                }
2775
            }
2776
        }
2777
2778
        return $result;
2779
    }
2780
2781
    /**
2782
     * Export all categories/group from a course to an array.
2783
     * This function works only in a context of a course.
2784
     *
2785
     * @param int  $groupId
2786
     * @param bool $loadUsers
2787
     *
2788
     * @return array
2789
     */
2790
    public static function exportCategoriesAndGroupsToArray($groupId = null, $loadUsers = false)
2791
    {
2792
        $data = [];
2793
        $data[] = [
2794
            'category',
2795
            'group',
2796
            'description',
2797
            'announcements_state',
2798
            'calendar_state',
2799
            'chat_state',
2800
            'doc_state',
2801
            'forum_state',
2802
            'work_state',
2803
            'wiki_state',
2804
            'max_student',
2805
            'self_reg_allowed',
2806
            'self_unreg_allowed',
2807
            'groups_per_user',
2808
        ];
2809
2810
        $count = 1;
2811
2812
        if ($loadUsers) {
2813
            $data[0][] = 'students';
2814
            $data[0][] = 'tutors';
2815
        }
2816
2817
        if (false == $loadUsers) {
2818
            $categories = self::get_categories();
2819
2820
            foreach ($categories as $categoryInfo) {
2821
                $data[$count] = [
2822
                    $categoryInfo['title'],
2823
                    null,
2824
                    $categoryInfo['description'],
2825
                    $categoryInfo['announcements_state'],
2826
                    $categoryInfo['calendar_state'],
2827
                    $categoryInfo['chat_state'],
2828
                    $categoryInfo['doc_state'],
2829
                    $categoryInfo['forum_state'],
2830
                    $categoryInfo['work_state'],
2831
                    $categoryInfo['wiki_state'],
2832
                    $categoryInfo['max_student'],
2833
                    $categoryInfo['self_reg_allowed'],
2834
                    $categoryInfo['self_unreg_allowed'],
2835
                    $categoryInfo['groups_per_user'],
2836
                ];
2837
                $count++;
2838
            }
2839
        }
2840
2841
        $groups = self::get_group_list();
2842
2843
        foreach ($groups as $groupInfo) {
2844
            $groupId = $groupInfo['iid'];
2845
            $categoryTitle = null;
2846
            $categoryInfo = [];
2847
            if (isset($groupInfo['category'])) {
2848
                $categoryInfo = self::get_category($groupInfo['category']);
2849
            }
2850
2851
            $groupSettings = self::get_group_properties($groupId);
2852
            if (!empty($categoryInfo)) {
2853
                $categoryTitle = $categoryInfo['title'];
2854
            }
2855
2856
            $users = self::getStudents($groupId);
2857
            $userList = [];
2858
            foreach ($users as $user) {
2859
                $user = api_get_user_info($user['user_id']);
2860
                $userList[] = $user['username'];
2861
            }
2862
2863
            $tutors = self::getTutors($groupInfo);
2864
            $tutorList = [];
2865
            foreach ($tutors as $user) {
2866
                $user = api_get_user_info($user['user_id']);
2867
                $tutorList[] = $user['username'];
2868
            }
2869
2870
            $userListToString = null;
2871
            if (!empty($userList)) {
2872
                $userListToString = implode(',', $userList);
2873
            }
2874
2875
            $tutorListToString = null;
2876
            if (!empty($tutorList)) {
2877
                $tutorListToString = implode(',', $tutorList);
2878
            }
2879
2880
            $data[$count] = [
2881
                $categoryTitle,
2882
                $groupSettings['name'],
2883
                $groupSettings['description'],
2884
                $groupSettings['announcements_state'],
2885
                $groupSettings['calendar_state'],
2886
                $groupSettings['chat_state'],
2887
                $groupSettings['doc_state'],
2888
                $groupSettings['forum_state'],
2889
                $groupSettings['work_state'],
2890
                $groupSettings['wiki_state'],
2891
                $groupSettings['maximum_number_of_students'],
2892
                $groupSettings['self_registration_allowed'],
2893
                $groupSettings['self_unregistration_allowed'],
2894
                null,
2895
            ];
2896
2897
            if ($loadUsers) {
2898
                $data[$count][] = $userListToString;
2899
                $data[$count][] = $tutorListToString;
2900
            }
2901
2902
            if (!empty($groupId)) {
2903
                if ($groupId == $groupInfo['iid']) {
2904
                    break;
2905
                }
2906
            }
2907
            $count++;
2908
        }
2909
2910
        return $data;
2911
    }
2912
2913
    /**
2914
     * @param string $default
2915
     */
2916
    public static function getSettingBar($default)
2917
    {
2918
        $activeSettings = null;
2919
        $activeTutor = null;
2920
        $activeMember = null;
2921
2922
        switch ($default) {
2923
            case 'settings':
2924
                $activeSettings = 'active';
2925
                break;
2926
            case'tutor':
2927
                $activeTutor = 'active';
2928
                break;
2929
            case 'member':
2930
                $activeMember = 'active';
2931
                break;
2932
        }
2933
2934
        $url = api_get_path(WEB_CODE_PATH).'group/%s?'.api_get_cidreq();
2935
2936
        echo '
2937
            <ul class="toolbar-groups nav nav-tabs">
2938
                <li class="'.$activeSettings.'">
2939
                    <a id="group_settings_tab" href="'.sprintf($url, 'settings.php').'">
2940
                    '.Display::return_icon('settings.png').' '.get_lang('Settings').'
2941
                    </a>
2942
                </li>
2943
                <li class="'.$activeMember.'">
2944
                    <a id="group_members_tab" href="'.sprintf($url, 'member_settings.php').'">
2945
                    '.Display::return_icon('user.png').' '.get_lang('Group members').'</a>
2946
                </li>
2947
                <li class="'.$activeTutor.'">
2948
                    <a id="group_tutors_tab" href="'.sprintf($url, 'tutor_settings.php').'">
2949
                    '.Display::return_icon('teacher.png').' '.get_lang('Group tutors').'
2950
                    </a>
2951
                </li>
2952
            </ul>';
2953
    }
2954
2955
    /**
2956
     * @param int    $courseId
2957
     * @param string $keyword
2958
     *
2959
     * @return string
2960
     */
2961
    public static function getOverview($courseId, $keyword = '')
2962
    {
2963
        $content = null;
2964
        $categories = self::get_categories();
2965
        if (!empty($categories)) {
2966
            foreach ($categories as $category) {
2967
                if ('true' == api_get_setting('allow_group_categories')) {
2968
                    $content .= '<h2>'.$category['title'].'</h2>';
2969
                }
2970
                if (!empty($keyword)) {
2971
                    $groups = self::getGroupListFilterByName(
2972
                        $keyword,
2973
                        $category['id'],
2974
                        $courseId
2975
                    );
2976
                } else {
2977
                    $groups = self::get_group_list($category['id']);
2978
                }
2979
2980
                if (empty($groups)) {
2981
                    $groups = self::get_group_list();
2982
                }
2983
2984
                $content .= '<ul>';
2985
                if (!empty($groups)) {
2986
                    foreach ($groups as $group) {
2987
                        $content .= '<li>';
2988
                        $content .= Display::tag(
2989
                            'h3',
2990
                            Security::remove_XSS($group['name'])
2991
                        );
2992
                        $users = self::getTutors($group);
2993
                        if (!empty($users)) {
2994
                            $content .= '<ul>';
2995
                            $content .= '<li>'.Display::tag('h4', get_lang('Coaches')).'</li><ul>';
2996
                            foreach ($users as $user) {
2997
                                $user_info = api_get_user_info($user['user_id']);
2998
                                $content .= '<li title="'.$user_info['username'].'">'.
2999
                                    $user_info['complete_name_with_username'].
3000
                                '</li>';
3001
                            }
3002
                            $content .= '</ul>';
3003
                            $content .= '</ul>';
3004
                        }
3005
3006
                        $users = self::getStudents($group['id']);
3007
                        if (!empty($users)) {
3008
                            $content .= '<ul>';
3009
                            $content .= '<li>'.Display::tag('h4', get_lang('Learners')).'</li><ul>';
3010
                            foreach ($users as $user) {
3011
                                $user_info = api_get_user_info($user['user_id']);
3012
                                $content .= '<li title="'.$user_info['username'].'">'.
3013
                                    $user_info['complete_name_with_username'].
3014
                                    '</li>';
3015
                            }
3016
                            $content .= '</ul>';
3017
                            $content .= '</ul>';
3018
                        }
3019
                        $content .= '</li>';
3020
                    }
3021
                }
3022
                $content .= '</ul>';
3023
            }
3024
        }
3025
3026
        return $content;
3027
    }
3028
3029
    /**
3030
     * Returns the search form.
3031
     *
3032
     * @return string
3033
     */
3034
    public static function getSearchForm()
3035
    {
3036
        $url = api_get_path(WEB_CODE_PATH).'group/group_overview.php?'.api_get_cidreq();
3037
        $form = new FormValidator(
3038
            'search_groups',
3039
            'get',
3040
            $url,
3041
            null,
3042
            ['class' => 'form-search'],
3043
            FormValidator::LAYOUT_INLINE
3044
        );
3045
        $form->addElement('text', 'keyword');
3046
        $form->addButtonSearch();
3047
3048
        return $form->toHtml();
3049
    }
3050
3051
    /**
3052
     * @param int $groupId
3053
     * @param int $status
3054
     */
3055
    public static function setStatus($groupId, $status)
3056
    {
3057
        $groupInfo = self::get_group_properties($groupId);
3058
3059
        $courseId = api_get_course_int_id();
3060
        if (!empty($groupInfo)) {
3061
            $table = Database::get_course_table(TABLE_GROUP);
3062
            $params = [
3063
                'status' => intval($status),
3064
            ];
3065
            Database::update(
3066
                $table,
3067
                $params,
3068
                ['c_id = ? AND id = ?' => [$courseId, $groupId]]
3069
            );
3070
        }
3071
    }
3072
3073
    /**
3074
     * @param int $groupId
3075
     */
3076
    public static function setVisible($groupId)
3077
    {
3078
        self::setStatus($groupId, 1);
3079
    }
3080
3081
    /**
3082
     * @param int $groupId
3083
     */
3084
    public static function setInvisible($groupId)
3085
    {
3086
        self::setStatus($groupId, 0);
3087
    }
3088
3089
    /**
3090
     * @param int   $userId
3091
     * @param int   $courseId
3092
     * @param array $groupInfo
3093
     * @param array $documentInfoToBeCheck
3094
     * @param bool  $blockPage
3095
     *
3096
     * @return bool
3097
     */
3098
    public static function allowUploadEditDocument(
3099
        $userId,
3100
        $courseId,
3101
        $groupInfo,
3102
        $documentInfoToBeCheck = null,
3103
        $blockPage = false
3104
    ) {
3105
        // Admin and teachers can make any change no matter what
3106
        if (api_is_platform_admin() || api_is_allowed_to_edit(false, true)) {
3107
            return true;
3108
        }
3109
3110
        if (empty($groupInfo) || !isset($groupInfo['id'])) {
3111
            if ($blockPage) {
3112
                api_not_allowed(true);
3113
            }
3114
3115
            return false;
3116
        }
3117
3118
        // Tutor can also make any change
3119
        $isTutor = self::is_tutor_of_group($userId, $groupInfo, $courseId);
3120
3121
        if ($isTutor) {
3122
            return true;
3123
        }
3124
3125
        // Just in case also check if document in group is available
3126
        if (0 == $groupInfo['doc_state']) {
3127
            if ($blockPage) {
3128
                api_not_allowed(true);
3129
            }
3130
3131
            return false;
3132
        }
3133
3134
        // Default behaviour
3135
        $documentAccess = self::DOCUMENT_MODE_SHARE;
3136
3137
        // Check category document access
3138
        /*$allowCategoryGroupDocumentAccess = api_get_configuration_value('group_category_document_access');
3139
        if ($allowCategoryGroupDocumentAccess) {
3140
            $category = GroupManager::get_category_from_group($groupInfo['iid']);
3141
            if (!empty($category) && isset($category['document_access'])) {
3142
                $documentAccess = (int) $category['document_access'];
3143
            }
3144
        }*/
3145
3146
        // Check group document access
3147
        $allow = api_get_configuration_value('group_document_access');
3148
        if ($allow) {
3149
            if (isset($groupInfo['document_access'])) {
3150
                $documentAccess = (int) $groupInfo['document_access'];
3151
            }
3152
        }
3153
3154
        // Check access for students
3155
        $result = false;
3156
        switch ($documentAccess) {
3157
            case self::DOCUMENT_MODE_SHARE:
3158
                // Default chamilo behaviour
3159
                // Student can upload his own content, cannot modify another content.
3160
                $isMember = self::is_subscribed($userId, $groupInfo);
3161
                if ($isMember) {
3162
                    // No document to check, allow access to document feature.
3163
                    if (empty($documentInfoToBeCheck)) {
3164
                        $result = true;
3165
                    } else {
3166
                        // Member can only edit his own document
3167
                        $authorId = isset($documentInfoToBeCheck['insert_user_id']) ? $documentInfoToBeCheck['insert_user_id'] : 0;
3168
                        // If "insert_user_id" is not set, check the author id from c_item_property
3169
                        if (empty($authorId) && isset($documentInfoToBeCheck['id'])) {
3170
                            // @todo use resources
3171
                            /*$documentInfo = api_get_item_property_info(
3172
                                $courseId,
3173
                                'document',
3174
                                $documentInfoToBeCheck['id'],
3175
                                0
3176
                            );
3177
                            // Try to find this document in the session
3178
                            if (!empty($sessionId)) {
3179
                                $documentInfo = api_get_item_property_info(
3180
                                    $courseId,
3181
                                    'document',
3182
                                    $documentInfoToBeCheck['id'],
3183
                                    api_get_session_id()
3184
                                );
3185
                            }
3186
3187
                            if (!empty($documentInfo) && isset($documentInfo['insert_user_id'])) {
3188
                                $authorId = $documentInfo['insert_user_id'];
3189
                            }*/
3190
                        }
3191
3192
                        if ($authorId == $userId) {
3193
                            $result = true;
3194
                        }
3195
                    }
3196
                }
3197
                break;
3198
            case self::DOCUMENT_MODE_READ_ONLY:
3199
                // Student cannot upload content, cannot modify another content.
3200
                $result = false;
3201
                break;
3202
            case self::DOCUMENT_MODE_COLLABORATION:
3203
                // Student can upload content, can modify another content.
3204
                $isMember = self::is_subscribed($userId, $groupInfo);
3205
                if ($isMember) {
3206
                    $result = true;
3207
                }
3208
                break;
3209
        }
3210
3211
        if ($blockPage && false == $result) {
3212
            api_not_allowed(true);
3213
        }
3214
3215
        return $result;
3216
    }
3217
}
3218