Completed
Push — master ( 9dadb1...edd250 )
by Julito
12:09 queued 19s
created

GroupManager::getOverview()   C

Complexity

Conditions 12
Paths 2

Size

Total Lines 66
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 47
nc 2
nop 2
dl 0
loc 66
rs 6.9666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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\Framework\Container;
6
use Chamilo\CoreBundle\Entity\Course;
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
        $table_group = Database::get_course_table(TABLE_GROUP);
78
        $courseId = !empty($courseId) ? (int) $courseId : api_get_course_int_id();
79
80
        $sql = "SELECT * FROM $table_group WHERE c_id = $courseId  ";
81
        $result = Database::query($sql);
82
83
        return Database::store_result($result, 'ASSOC');
84
    }
85
86
    /**
87
     * Get list of groups for current course.
88
     *
89
     * @param int   $categoryId  The id of the category from which the groups are
90
     *                           requested
91
     * @param array $course_info Default is current course
92
     * @param int   $status      group status
93
     * @param int   $sessionId
94
     * @param bool  $getCount
95
     *
96
     * @return array an array with all information about the groups
97
     */
98
    public static function get_group_list(
99
        $categoryId = null,
100
        $course_info = [],
101
        $status = null,
102
        $sessionId = 0,
103
        $getCount = false
104
    ) {
105
        $course_info = empty($course_info) ? api_get_course_info() : $course_info;
106
107
        if (empty($course_info)) {
108
            return [];
109
        }
110
111
        $sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
112
        $course_id = $course_info['real_id'];
113
114
        $repo = Container::getGroupRepository();
115
        $course = api_get_course_entity($course_id);
116
        $session = api_get_session_entity($sessionId);
117
        $group = api_get_group_entity(api_get_group_id());
118
119
        $qb = $repo->getResourcesByCourse($course, $session, $group);
120
121
        if (null === $categoryId) {
122
            $qb
123
                ->andWhere('resource.category is NULL');
124
        } else {
125
            $qb
126
                ->andWhere('resource.category = :category')
127
                ->setParameter('category', $categoryId);
128
        }
129
130
        if ($getCount) {
131
            $qb->select('count(resource)');
132
133
            return $qb->getQuery()->getSingleScalarResult();
134
        }
135
136
        return $qb->getQuery()->getArrayResult();
137
138
        $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...
139
140
        $select = ' g.iid,
141
                    g.name,
142
                    g.description,
143
                    g.category_id,
144
                    g.max_student maximum_number_of_members,
145
                    g.secret_directory,
146
                    g.self_registration_allowed,
147
                    g.self_unregistration_allowed,
148
                    g.status
149
                    ';
150
        if ($getCount) {
151
            $select = ' DISTINCT count(g.iid) as count ';
152
        }
153
154
        $sql = "SELECT
155
                $select
156
                FROM $table_group g
157
                WHERE 1 = 1 ";
158
159
        if (!is_null($categoryId)) {
160
            $sql .= " AND g.category_id = '".intval($categoryId)."' ";
161
            $session_condition = api_get_session_condition($sessionId);
162
            if (!empty($session_condition)) {
163
                //$sql .= $session_condition;
164
            }
165
        } else {
166
            $session_condition = api_get_session_condition($sessionId, true);
167
        }
168
169
        $session_condition = '';
170
171
        if (!is_null($status)) {
172
            $sql .= " AND g.status = '".intval($status)."' ";
173
        }
174
175
        //$sql .= " AND g.c_id = $course_id ";
176
177
        if (!empty($session_condition)) {
178
            $sql .= $session_condition;
179
        }
180
        $sql .= ' ORDER BY UPPER(g.name)';
181
182
        $result = Database::query($sql);
183
184
        if ($getCount) {
185
            $row = Database::fetch_array($result);
186
187
            return $row['count'];
188
        }
189
190
        $groups = [];
191
        while ($thisGroup = Database::fetch_array($result)) {
192
            $thisGroup['number_of_members'] = count(self::get_subscribed_users($thisGroup));
193
            if (0 != $thisGroup['session_id']) {
194
                $sql = 'SELECT name FROM '.Database::get_main_table(TABLE_MAIN_SESSION).'
195
                        WHERE id='.$thisGroup['session_id'];
196
                $rs_session = Database::query($sql);
197
                if (Database::num_rows($rs_session) > 0) {
198
                    $thisGroup['session_name'] = Database::result($rs_session, 0, 0);
199
                }
200
            }
201
            $groups[] = $thisGroup;
202
        }
203
204
        return $groups;
205
    }
206
207
    /**
208
     * Create a group.
209
     *
210
     * @param string $name        The name for this group
211
     * @param int    $category_id
212
     * @param int    $tutor       The user-id of the group's tutor
213
     * @param int    $places      How many people can subscribe to the new group
214
     *
215
     * @return int
216
     */
217
    public static function create_group($name, $category_id, $tutor, $places)
218
    {
219
        $_course = api_get_course_info();
220
        $session_id = api_get_session_id();
221
        $course_id = $_course['real_id'];
222
        $category = self::get_category($category_id);
223
        $places = (int) $places;
224
225
        // Default values
226
        $docState = self::TOOL_PRIVATE;
227
        $calendarState = self::TOOL_PRIVATE;
228
        $workState = self::TOOL_PRIVATE;
229
        $anonuncementState = self::TOOL_PRIVATE;
230
        $forumState = self::TOOL_PRIVATE;
231
        $wikiState = self::TOOL_PRIVATE;
232
        $chatState = self::TOOL_PRIVATE;
233
        $selfRegAllowed = 0;
234
        $selfUnregAllwoed = 0;
235
        $documentAccess = 0;
236
237
        if ($category) {
238
            if (0 == $places) {
239
                //if the amount of users per group is not filled in, use the setting from the category
240
                $places = $category['max_student'];
241
            } else {
242
                if ($places > $category['max_student'] && 0 != $category['max_student']) {
243
                    $places = $category['max_student'];
244
                }
245
            }
246
            $docState = $category['doc_state'];
247
            $calendarState = $category['calendar_state'];
248
            $workState = $category['work_state'];
249
            $anonuncementState = $category['announcements_state'];
250
            $forumState = $category['forum_state'];
251
            $wikiState = $category['wiki_state'];
252
            $chatState = $category['chat_state'];
253
            $selfRegAllowed = $category['self_reg_allowed'];
254
            $selfUnregAllwoed = $category['self_unreg_allowed'];
255
            $documentAccess = isset($category['document_access']) ? $category['document_access'] : 0;
256
        }
257
258
        $course = api_get_course_entity($course_id);
259
        $session = api_get_session_entity($session_id);
260
261
        $category = null;
262
        if (!empty($category_id)) {
263
            $category = Container::getGroupCategoryRepository()->find($category_id);
264
        }
265
266
        $group = new CGroup();
267
        $group
268
            ->setName($name)
269
            ->setCategory($category)
270
            ->setMaxStudent($places)
271
            ->setDocState($docState)
272
            ->setCalendarState($calendarState)
273
            ->setWorkState($workState)
274
            ->setForumState($forumState)
275
            ->setWikiState($wikiState)
276
            ->setAnnouncementsState($anonuncementState)
277
            ->setChatState($chatState)
278
            ->setSelfRegistrationAllowed($selfRegAllowed)
279
            ->setSelfUnregistrationAllowed($selfUnregAllwoed)
280
            ->setDocumentAccess($documentAccess)
281
            ->setParent($course)
282
            ->addCourseLink($course, $session)
283
        ;
284
285
        $repo = Container::getGroupRepository();
286
        $repo->getEntityManager()->persist($group);
287
        $repo->getEntityManager()->flush();
288
        $lastId = $group->getIid();
289
290
        if ($lastId) {
291
            /*$desired_dir_name = '/'.api_replace_dangerous_char($name).'_groupdocs';
292
293
            $newFolderData = create_unexisting_directory(
294
                $_course,
295
                api_get_user_id(),
296
                $session_id,
297
                $lastId,
298
                null,
299
                null,
300
                    $desired_dir_name,
301
                $desired_dir_name,
302
                1
303
            );*/
304
305
            //$unique_name = $newFolderData->getPath();
306
307
            /* Stores the directory path into the group table */
308
            /*$sql = "UPDATE $table_group SET
309
                        name = '".Database::escape_string($name)."',
310
                        secret_directory = '".$unique_name."'
311
                    WHERE c_id = $course_id AND id ='".$lastId."'";
312
313
            Database::query($sql);*/
314
315
            // create a forum if needed
316
            if ($forumState >= 0) {
317
                require_once api_get_path(SYS_CODE_PATH).'forum/forumfunction.inc.php';
318
319
                $forumName = get_lang('Group forums');
320
                $repo = Container::getForumCategoryRepository();
321
                $criteria = ['cId' => $course_id, 'catTitle' => $forumName];
322
                $category = $repo->findOneBy($criteria);
323
324
                if (empty($category)) {
325
                    $categoryParam = [
326
                        'forum_category_title' => $forumName,
327
                    ];
328
                    $categoryId = store_forumcategory($categoryParam);
329
                } else {
330
                    $categoryId = $category->getIid();
331
                }
332
333
                $values = [];
334
                $values['forum_title'] = $name;
335
                $values['group_id'] = $lastId;
336
                $values['forum_category'] = $categoryId;
337
                $values['allow_anonymous_group']['allow_anonymous'] = 0;
338
                $values['students_can_edit_group']['students_can_edit'] = 0;
339
                $values['approval_direct_group']['approval_direct'] = 0;
340
                $values['allow_attachments_group']['allow_attachments'] = 1;
341
                $values['allow_new_threads_group']['allow_new_threads'] = 1;
342
                $values['default_view_type_group']['default_view_type'] = api_get_setting('default_forum_view');
343
                $values['group_forum'] = $lastId;
344
                if ('1' == $forumState) {
345
                    $values['public_private_group_forum_group']['public_private_group_forum'] = 'public';
346
                } elseif ('2' == $forumState) {
347
                    $values['public_private_group_forum_group']['public_private_group_forum'] = 'private';
348
                } elseif ('0' == $forumState) {
349
                    $values['public_private_group_forum_group']['public_private_group_forum'] = 'unavailable';
350
                }
351
                store_forum($values);
352
            }
353
        }
354
355
        return $lastId;
356
    }
357
358
    /**
359
     * Create subgroups.
360
     * This function creates new groups based on an existing group. It will
361
     * create the specified number of groups and fill those groups with users
362
     * from the base group.
363
     *
364
     * @param int $group_id         the group from which subgroups have to be created
365
     * @param int $number_of_groups The number of groups that have to be created
366
     */
367
    public static function create_subgroups($group_id, $number_of_groups)
368
    {
369
        $courseId = api_get_course_int_id();
370
        $table_group = Database::get_course_table(TABLE_GROUP);
371
        $category_id = self::create_category(
372
            get_lang('Subgroups'),
373
            '',
374
            self::TOOL_PRIVATE,
375
            self::TOOL_PRIVATE,
376
            0,
377
            0,
378
            1,
379
            1
380
        );
381
        $users = self::get_users($group_id);
382
        $group_ids = [];
383
384
        for ($group_nr = 1; $group_nr <= $number_of_groups; ++$group_nr) {
385
            $group_ids[] = self::create_group(
386
                get_lang('Subgroup').' '.$group_nr,
387
                $category_id,
388
                0,
389
                0
390
            );
391
        }
392
393
        $members = [];
394
        foreach ($users as $index => $user_id) {
395
            $groupId = $group_ids[$index % $number_of_groups];
396
            $groupInfo = self::get_group_properties($groupId);
397
            self::subscribe_users(
398
                $user_id,
399
                $groupInfo
400
            );
401
            ++$members[$group_ids[$groupId]];
402
        }
403
404
        foreach ($members as $group_id => $places) {
405
            $sql = "UPDATE $table_group SET max_student = $places
406
                    WHERE c_id = $courseId  AND id = $group_id";
407
            Database::query($sql);
408
        }
409
    }
410
411
    /**
412
     * Create a group for every class subscribed to the current course.
413
     *
414
     * @param int $categoryId The category in which the groups should be created
415
     *
416
     * @return array
417
     */
418
    public static function create_class_groups($categoryId)
419
    {
420
        $options['where'] = [' usergroup.course_id = ? ' => api_get_course_int_id()];
421
        $obj = new UserGroup();
422
        $classes = $obj->getUserGroupInCourse($options);
423
        $group_ids = [];
424
425
        foreach ($classes as $class) {
426
            $userList = $obj->get_users_by_usergroup($class['id']);
427
            $groupId = self::create_group(
428
                $class['name'],
429
                $categoryId,
430
                0,
431
                null
432
            );
433
434
            if ($groupId) {
435
                $groupInfo = self::get_group_properties($groupId);
436
                self::subscribe_users($userList, $groupInfo);
437
                $group_ids[] = $groupId;
438
            }
439
        }
440
441
        return $group_ids;
442
    }
443
444
    /**
445
     * Deletes groups and their data.
446
     *
447
     * @author Christophe Gesche <[email protected]>
448
     * @author Hugues Peeters <[email protected]>
449
     * @author Bart Mollet
450
     *
451
     * @param array  $groupInfo   iid
452
     * @param string $course_code Default is current course
453
     *
454
     * @return int - number of groups deleted
455
     */
456
    public static function deleteGroup($groupInfo, $course_code = null)
457
    {
458
        if (empty($groupInfo['iid'])) {
459
            return false;
460
        }
461
        $course_info = api_get_course_info($course_code);
462
        if (empty($course_info)) {
463
            return false;
464
        }
465
466
        $course_id = $course_info['real_id'];
467
        $em = Database::getManager();
468
        $groupInfo = self::get_group_properties($groupInfo['iid'], true);
469
        if ($groupInfo) {
470
            $groupIid = $groupInfo['iid'];
471
            $groupId = $groupInfo['id'];
472
            // Unsubscribe all users
473
            self::unsubscribe_all_users($groupInfo);
474
            self::unsubscribe_all_tutors($groupInfo);
475
476
            if (!empty($groupInfo['secret_directory'])) {
477
                /*
478
                $directory = $groupInfo['secret_directory'];
479
                // move group-documents to garbage
480
                $source_directory = api_get_path(SYS_COURSE_PATH).$course_info['path']."/document".$directory;
481
                // File to renamed
482
                $destination_dir = api_get_path(SYS_COURSE_PATH).$course_info['path']."/document".$directory.'_DELETED_'.$groupInfo['id'];
483
                //Deleting from document tool
484
                DocumentManager::delete_document(
485
                    $course_info,
486
                    $directory,
487
                    $source_directory
488
                );
489
490
                if (file_exists($source_directory)) {
491
                    if ('true' === api_get_setting('permanently_remove_deleted_files')) {
492
                        // Delete
493
                        my_delete($source_directory);
494
                    } else {
495
                        // Rename
496
                        rename($source_directory, $destination_dir);
497
                    }
498
                }*/
499
            }
500
501
            $em
502
                ->createQuery(
503
                    'DELETE FROM ChamiloCourseBundle:CForumForum f WHERE f.forumOfGroup = :group'
504
                )
505
                ->execute(['group' => $groupId]);
506
507
            // Delete item properties of this group.
508
            // to_group_id is related to c_group_info.iid
509
            /*$em
510
                ->createQuery(
511
                    'DELETE FROM ChamiloCourseBundle:CItemProperty ci WHERE ci.course = :course AND ci.group = :group'
512
                )
513
                ->execute(['course' => $course_id, 'group' => $groupId]);
514
            */
515
            // delete the groups
516
            $em
517
                ->createQuery(
518
                    'DELETE FROM ChamiloCourseBundle:CGroup g WHERE g.course = :course AND g.iid = :id'
519
                )
520
                ->execute(['course' => $course_id, 'id' => $groupIid]);
521
        }
522
523
        return true;
524
    }
525
526
    /**
527
     * Function needed only when deleting a course, in order to be sure that all group ids are deleted.
528
     *
529
     * @param int $courseId
530
     *
531
     * @return bool
532
     */
533
    public static function deleteAllGroupsFromCourse($courseId)
534
    {
535
        $courseId = (int) $courseId;
536
537
        if (empty($courseId)) {
538
            return false;
539
        }
540
541
        $table = Database::get_course_table(TABLE_GROUP_CATEGORY);
542
        $sql = "SELECT iid FROM $table
543
                WHERE c_id = $courseId ";
544
        Database::query($sql);
545
546
        // Database table definitions
547
        $table = Database::get_course_table(TABLE_GROUP_USER);
548
        $sql = "DELETE FROM $table
549
                WHERE c_id = $courseId";
550
        Database::query($sql);
551
552
        $table = Database::get_course_table(TABLE_GROUP_TUTOR);
553
        $sql = "DELETE FROM $table
554
                WHERE c_id = $courseId";
555
        Database::query($sql);
556
557
        $groupTable = Database::get_course_table(TABLE_GROUP);
558
        $sql = "DELETE FROM $groupTable
559
                WHERE c_id = $courseId";
560
        Database::query($sql);
561
562
        return true;
563
    }
564
565
    /**
566
     * Get group properties.
567
     *
568
     * @param int $group_id the group from which properties are requested
569
     *
570
     * @return array All properties. Array-keys are:
571
     *               name, tutor_id, description, maximum_number_of_students,
572
     *               directory and visibility of tools
573
     */
574
    public static function get_group_properties($group_id)
575
    {
576
        $group_id = (int) $group_id;
577
578
        if (empty($group_id)) {
579
            return null;
580
        }
581
582
        $table_group = Database::get_course_table(TABLE_GROUP);
583
584
        $sql = "SELECT * FROM $table_group
585
                WHERE iid = ".$group_id;
586
587
        $db_result = Database::query($sql);
588
        $db_object = Database::fetch_object($db_result);
589
590
        $result = [];
591
        if ($db_object) {
592
            $result['id'] = $db_object->iid;
593
            $result['iid'] = $db_object->iid;
594
            $result['name'] = $db_object->name;
595
            $result['status'] = $db_object->status;
596
            $result['description'] = $db_object->description;
597
            $result['maximum_number_of_students'] = $db_object->max_student;
598
            $result['max_student'] = $db_object->max_student;
599
            $result['doc_state'] = $db_object->doc_state;
600
            $result['work_state'] = $db_object->work_state;
601
            $result['calendar_state'] = $db_object->calendar_state;
602
            $result['announcements_state'] = $db_object->announcements_state;
603
            $result['forum_state'] = $db_object->forum_state;
604
            $result['wiki_state'] = $db_object->wiki_state;
605
            $result['chat_state'] = $db_object->chat_state;
606
            $result['directory'] = $db_object->secret_directory;
607
            $result['self_registration_allowed'] = $db_object->self_registration_allowed;
608
            $result['self_unregistration_allowed'] = $db_object->self_unregistration_allowed;
609
            $result['count_users'] = count(
610
                self::get_subscribed_users($result)
611
            );
612
            $result['count_tutor'] = count(
613
                self::get_subscribed_tutors($result)
614
            );
615
            $result['count_all'] = $result['count_users'] + $result['count_tutor'];
616
            $result['document_access'] = isset($db_object->document_access) ? $db_object->document_access : self::DOCUMENT_MODE_SHARE;
617
        }
618
619
        return $result;
620
    }
621
622
    /**
623
     * @param string $name
624
     * @param string $courseCode
625
     * @param int    $sessionId
626
     *
627
     * @return array
628
     */
629
    public static function getGroupByName($name, $courseCode = null, $sessionId = 0)
630
    {
631
        $name = trim($name);
632
633
        if (empty($name)) {
634
            return [];
635
        }
636
637
        $course_info = api_get_course_info($courseCode);
638
        $course_id = $course_info['real_id'];
639
        $name = Database::escape_string($name);
640
        $sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
641
        $sessionCondition = api_get_session_condition($sessionId);
642
643
        $table = Database::get_course_table(TABLE_GROUP);
644
        $sql = "SELECT * FROM $table
645
                WHERE
646
                  c_id = $course_id AND
647
                  name = '$name'
648
                  $sessionCondition
649
                LIMIT 1";
650
        $res = Database::query($sql);
651
        $group = [];
652
        if (Database::num_rows($res)) {
653
            $group = Database::fetch_array($res, 'ASSOC');
654
        }
655
656
        return $group;
657
    }
658
659
    /**
660
     * @param int    $courseId
661
     * @param int    $categoryId
662
     * @param string $name
663
     *
664
     * @return array
665
     */
666
    public static function getGroupListFilterByName($name, $categoryId, $courseId)
667
    {
668
        $name = trim($name);
669
        $name = Database::escape_string($name);
670
        $categoryId = (int) $categoryId;
671
        $courseId = (int) $courseId;
672
673
        if (empty($name)) {
674
            return [];
675
        }
676
        $table_group = Database::get_course_table(TABLE_GROUP);
677
        $sql = "SELECT * FROM $table_group
678
                WHERE c_id = $courseId AND name LIKE '%$name%'";
679
680
        if (!empty($categoryId)) {
681
            $sql .= " AND category_id = $categoryId";
682
        }
683
        $sql .= ' ORDER BY name';
684
        $result = Database::query($sql);
685
686
        return Database::store_result($result, 'ASSOC');
687
    }
688
689
    /**
690
     * Set group properties
691
     * Changes the group's properties.
692
     *
693
     * @param int       Group Id
694
     * @param string    Group name
695
     * @param string    Group description
696
     * @param int       Max number of students in group
697
     * @param int       Document tool's visibility (0=none,1=private,2=public)
698
     * @param int       Work tool's visibility (0=none,1=private,2=public)
699
     * @param int       Calendar tool's visibility (0=none,1=private,2=public)
700
     * @param int       Announcement tool's visibility (0=none,1=private,2=public)
701
     * @param int       Forum tool's visibility (0=none,1=private,2=public)
702
     * @param int       Wiki tool's visibility (0=none,1=private,2=public)
703
     * @param int       Chat tool's visibility (0=none,1=private,2=public)
704
     * @param bool Whether self registration is allowed or not
705
     * @param bool Whether self unregistration is allowed or not
706
     * @param int $categoryId
707
     * @param int $documentAccess
708
     *
709
     * @return bool TRUE if properties are successfully changed, false otherwise
710
     */
711
    public static function set_group_properties(
712
        $group_id,
713
        $name,
714
        $description,
715
        $maxStudent,
716
        $docState,
717
        $workState,
718
        $calendarState,
719
        $anonuncementState,
720
        $forumState,
721
        $wikiState,
722
        $chatState,
723
        $selfRegistrationAllowed,
724
        $selfUnRegistrationAllowed,
725
        $categoryId = null,
726
        $documentAccess = 0
727
    ) {
728
        $table_group = Database::get_course_table(TABLE_GROUP);
729
        $table_forum = Database::get_course_table(TABLE_FORUM);
730
        $categoryId = (int) $categoryId;
731
        $group_id = (int) $group_id;
732
        $repo = Container::getGroupRepository();
733
734
        /** @var CGroup $group */
735
        $group = $repo->find($group_id);
736
737
        $category = null;
738
        if (!empty($categoryId)) {
739
            $category = Container::getGroupCategoryRepository()->find($categoryId);
740
        }
741
742
        $group
743
            ->setName($name)
744
            ->setCategory($category)
745
            ->setMaxStudent($maxStudent)
746
            ->setDocState($docState)
747
            ->setCalendarState($calendarState)
748
            ->setWorkState($workState)
749
            ->setForumState($forumState)
750
            ->setWikiState($wikiState)
751
            ->setAnnouncementsState($anonuncementState)
752
            ->setChatState($chatState)
753
            ->setSelfRegistrationAllowed($selfRegistrationAllowed)
754
            ->setSelfUnregistrationAllowed($selfUnRegistrationAllowed)
755
            ->setDocumentAccess($documentAccess)
756
        ;
757
758
        $repo->getEntityManager()->persist($group);
759
        $repo->getEntityManager()->flush();
760
761
        /* Here we are updating a field in the table forum_forum that perhaps
762
        duplicates the table group_info.forum_state cvargas*/
763
        $forumState = (int) $forumState;
764
        $sql2 = "UPDATE $table_forum SET ";
765
        if (1 === $forumState) {
766
            $sql2 .= " forum_group_public_private='public' ";
767
        } elseif (2 === $forumState) {
768
            $sql2 .= " forum_group_public_private='private' ";
769
        } elseif (0 === $forumState) {
770
            $sql2 .= " forum_group_public_private='unavailable' ";
771
        }
772
        $sql2 .= ' WHERE forum_of_group='.$group_id;
773
        Database::query($sql2);
774
775
        return true;
776
    }
777
778
    /**
779
     * Get the total number of groups for the current course.
780
     *
781
     * @return int the number of groups for the current course
782
     */
783
    public static function get_number_of_groups()
784
    {
785
        $repo = Container::getGroupRepository();
786
787
        $course = api_get_course_entity(api_get_course_int_id());
788
        $session = api_get_session_entity(api_get_session_id());
789
        $group = api_get_group_entity(api_get_group_id());
790
791
        $qb = $repo->getResourcesByCourse($course, $session, $group);
792
        $qb->select('count(resource)');
793
794
        return $qb->getQuery()->getSingleScalarResult();
795
796
        $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...
797
        $table = Database::get_course_table(TABLE_GROUP);
798
        $sql = "SELECT COUNT(id) AS number_of_groups
799
                FROM $table
800
                WHERE c_id = $courseId ";
801
        $res = Database::query($sql);
802
        $obj = Database::fetch_object($res);
803
804
        return $obj->number_of_groups;
805
    }
806
807
    /**
808
     * Get all categories.
809
     */
810
    public static function get_categories(Course $course = null): array
811
    {
812
        $repo = Container::getGroupCategoryRepository();
813
814
        if (null === $course) {
815
            $course = api_get_course_entity(api_get_course_int_id());
816
        }
817
818
        $session = api_get_session_entity(api_get_session_id());
819
        $group = api_get_group_entity(api_get_group_id());
820
821
        $qb = $repo->getResourcesByCourse($course, $session, $group);
822
823
        return $qb->getQuery()->getArrayResult();
824
825
        $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...
826
        $courseId = $course_info['real_id'];
827
        $table = Database::get_course_table(TABLE_GROUP_CATEGORY);
828
        $sql = "SELECT * FROM $table
829
                WHERE c_id = $courseId
830
                ORDER BY display_order";
831
        $res = Database::query($sql);
832
        $cats = [];
833
        while ($cat = Database::fetch_array($res)) {
834
            $cats[] = $cat;
835
        }
836
837
        return $cats;
838
    }
839
840
    /**
841
     * Get a group category.
842
     *
843
     * @param int    $id          The category id
844
     * @param string $course_code The course (default = current course)
845
     *
846
     * @return array
847
     */
848
    public static function get_category($id, $course_code = null)
849
    {
850
        if (empty($id)) {
851
            return [];
852
        }
853
854
        $courseInfo = api_get_course_info($course_code);
855
        $courseId = $courseInfo['real_id'];
856
        $id = intval($id);
857
        $table = Database::get_course_table(TABLE_GROUP_CATEGORY);
858
        $sql = "SELECT * FROM $table
859
                WHERE  iid = $id
860
                LIMIT 1";
861
        $res = Database::query($sql);
862
863
        return Database::fetch_array($res);
864
    }
865
866
    /**
867
     * Get a group category.
868
     *
869
     * @param string $title
870
     * @param string $course_code The course (default = current course)
871
     *
872
     * @return array
873
     */
874
    public static function getCategoryByTitle($title, $course_code = null)
875
    {
876
        $title = trim($title);
877
878
        if (empty($title)) {
879
            return [];
880
        }
881
882
        $course_info = api_get_course_info($course_code);
883
        $courseId = $course_info['real_id'];
884
        $title = Database::escape_string($title);
885
        $table = Database::get_course_table(TABLE_GROUP_CATEGORY);
886
        $sql = "SELECT * FROM $table
887
                WHERE c_id = $courseId AND title = '$title'
888
                LIMIT 1";
889
        $res = Database::query($sql);
890
        $category = [];
891
        if (Database::num_rows($res)) {
892
            $category = Database::fetch_array($res, 'ASSOC');
893
        }
894
895
        return $category;
896
    }
897
898
    /**
899
     * Get the unique category of a given group.
900
     *
901
     * @param int    $group_id    The iid of the group
902
     * @param string $course_code The course in which the group is (default =
903
     *                            current course)
904
     *
905
     * @return array The category
906
     */
907
    public static function get_category_from_group($group_id, $course_code = '')
908
    {
909
        $table_group = Database::get_course_table(TABLE_GROUP);
910
        $table_group_cat = Database::get_course_table(TABLE_GROUP_CATEGORY);
911
912
        $group_id = (int) $group_id;
913
914
        if (empty($group_id)) {
915
            return [];
916
        }
917
918
        $course_info = api_get_course_info($course_code);
919
920
        if (empty($course_info)) {
921
            return false;
922
        }
923
924
        $courseId = $course_info['real_id'];
925
        $sql = "SELECT gc.* FROM $table_group_cat gc
926
                INNER JOIN $table_group g
927
                ON (gc.iid = g.category_id)
928
                WHERE
929
                    g.iid = $group_id
930
                LIMIT 1";
931
        $res = Database::query($sql);
932
        $cat = [];
933
        if (Database::num_rows($res)) {
934
            $cat = Database::fetch_array($res);
935
        }
936
937
        return $cat;
938
    }
939
940
    /**
941
     * Delete a group category.
942
     *
943
     * @param int    $cat_id      The id of the category to delete
944
     * @param string $course_code The code in which the category should be
945
     *                            deleted (default = current course)
946
     *
947
     * @return bool
948
     */
949
    public static function delete_category($cat_id, $course_code = '')
950
    {
951
        $course_info = api_get_course_info($course_code);
952
        if (empty($course_info)) {
953
            return false;
954
        }
955
        $course_id = $course_info['real_id'];
956
957
        $table_group = Database::get_course_table(TABLE_GROUP);
958
        $table_group_cat = Database::get_course_table(TABLE_GROUP_CATEGORY);
959
        $cat_id = (int) $cat_id;
960
        $sql = "SELECT iid FROM $table_group
961
                WHERE c_id = $course_id AND category_id='".$cat_id."'";
962
        $res = Database::query($sql);
963
        if (Database::num_rows($res) > 0) {
964
            while ($group = Database::fetch_object($res)) {
965
                // Delete all groups in category
966
                /*$groupInfo = self::get_group_properties($group->iid, true);
967
                self::deleteGroup($groupInfo, $course_code);
968
                */
969
                // Set the category to NULL to avoid losing groups in sessions.
970
                $sql = "UPDATE $table_group SET category_id = NULL WHERE iid = ".$group->iid;
971
                Database::query($sql);
972
            }
973
        }
974
        $sql = "DELETE FROM $table_group_cat
975
                WHERE c_id = $course_id  AND iid='".$cat_id."'";
976
        Database::query($sql);
977
978
        return true;
979
    }
980
981
    /**
982
     * Create group category.
983
     *
984
     * @param string $title                      The title of the new category
985
     * @param string $description                The description of the new category
986
     * @param int    $doc_state
987
     * @param int    $work_state
988
     * @param int    $calendar_state
989
     * @param int    $announcements_state
990
     * @param int    $forum_state
991
     * @param int    $wiki_state
992
     * @param int    $chat_state
993
     * @param int    $selfRegistrationAllowed    allow users to self register
994
     * @param int    $selfUnRegistrationAllowed  allow user to self unregister
995
     * @param int    $maximum_number_of_students
996
     * @param int    $groups_per_user
997
     * @param int    $documentAccess             document access
998
     *
999
     * @return mixed
1000
     */
1001
    public static function create_category(
1002
        $title,
1003
        $description,
1004
        $docState,
1005
        $workState,
1006
        $calendarState,
1007
        $anonuncementState,
1008
        $forumState,
1009
        $wikiState,
1010
        $chatState = 1,
1011
        $selfRegistrationAllowed = 0,
1012
        $selfUnRegistrationAllowed = 0,
1013
        $maxStudent = 8,
1014
        $groupsPerUser = 0,
1015
        $documentAccess = 0
1016
    ) {
1017
        if (empty($title)) {
1018
            return false;
1019
        }
1020
        /*$sql = "SELECT MAX(display_order)+1 as new_order
1021
                FROM $table
1022
                WHERE c_id = $course_id ";
1023
        $res = Database::query($sql);
1024
        $obj = Database::fetch_object($res);
1025
        if (!isset($obj->new_order)) {
1026
            $obj->new_order = 1;
1027
        }*/
1028
1029
        $course = api_get_course_entity(api_get_course_int_id());
1030
        $session = api_get_session_entity(api_get_session_id());
1031
1032
        $category = new CGroupCategory();
1033
        $category
1034
            ->setTitle($title)
1035
            ->setDescription($description)
1036
            ->setMaxStudent($maxStudent)
1037
            ->setDocState($docState)
1038
            ->setCalendarState($calendarState)
1039
            ->setWorkState($workState)
1040
            ->setForumState($forumState)
1041
            ->setWikiState($wikiState)
1042
            ->setAnnouncementsState($anonuncementState)
1043
            ->setChatState($chatState)
1044
            ->setSelfRegAllowed($selfRegistrationAllowed)
1045
            ->setSelfUnregAllowed($selfUnRegistrationAllowed)
1046
            ->setDocumentAccess($documentAccess)
1047
            ->setGroupsPerUser($groupsPerUser)
1048
            ->setParent($course)
1049
            ->addCourseLink($course, $session)
1050
        ;
1051
1052
        $repo = Container::getGroupCategoryRepository();
1053
        $repo->getEntityManager()->persist($category);
1054
        $repo->getEntityManager()->flush();
1055
1056
        return $category->getIid();
1057
    }
1058
1059
    /**
1060
     * Update group category.
1061
     *
1062
     * @param int    $id
1063
     * @param string $title
1064
     * @param string $description
1065
     * @param $doc_state
1066
     * @param $work_state
1067
     * @param $calendar_state
1068
     * @param $announcements_state
1069
     * @param $forum_state
1070
     * @param $wiki_state
1071
     * @param $chat_state
1072
     * @param $selfRegistrationAllowed
1073
     * @param $selfUnRegistrationAllowed
1074
     * @param $maximum_number_of_students
1075
     * @param $groups_per_user
1076
     * @param $documentAccess
1077
     */
1078
    public static function update_category(
1079
        $id,
1080
        $title,
1081
        $description,
1082
        $doc_state,
1083
        $work_state,
1084
        $calendar_state,
1085
        $announcements_state,
1086
        $forum_state,
1087
        $wiki_state,
1088
        $chat_state,
1089
        $selfRegistrationAllowed,
1090
        $selfUnRegistrationAllowed,
1091
        $maximum_number_of_students,
1092
        $groups_per_user,
1093
        $documentAccess
1094
    ) {
1095
        $table = Database::get_course_table(TABLE_GROUP_CATEGORY);
1096
        $id = (int) $id;
1097
1098
        $courseId = api_get_course_int_id();
1099
1100
        $allowDocumentAccess = api_get_configuration_value('group_category_document_access');
1101
        $documentCondition = '';
1102
        if ($allowDocumentAccess) {
1103
            $documentAccess = (int) $documentAccess;
1104
            $documentCondition = " document_access = $documentAccess, ";
1105
        }
1106
1107
        $sql = 'UPDATE '.$table." SET
1108
                    title='".Database::escape_string($title)."',
1109
                    description='".Database::escape_string($description)."',
1110
                    doc_state = '".Database::escape_string($doc_state)."',
1111
                    work_state = '".Database::escape_string($work_state)."',
1112
                    calendar_state = '".Database::escape_string($calendar_state)."',
1113
                    announcements_state = '".Database::escape_string($announcements_state)."',
1114
                    forum_state = '".Database::escape_string($forum_state)."',
1115
                    wiki_state = '".Database::escape_string($wiki_state)."',
1116
                    chat_state = '".Database::escape_string($chat_state)."',
1117
                    groups_per_user   = '".Database::escape_string($groups_per_user)."',
1118
                    self_reg_allowed = '".Database::escape_string($selfRegistrationAllowed)."',
1119
                    self_unreg_allowed = '".Database::escape_string($selfUnRegistrationAllowed)."',
1120
                    $documentCondition
1121
                    max_student = ".intval($maximum_number_of_students)."
1122
                WHERE iid = $id";
1123
1124
        Database::query($sql);
1125
1126
        // Updating all groups inside this category
1127
        $groups = self::get_group_list($id);
1128
1129
        if (!empty($groups)) {
1130
            foreach ($groups as $group) {
1131
                self::set_group_properties(
1132
                    $group['iid'],
1133
                    $group['name'],
1134
                    $group['description'],
1135
                    $maximum_number_of_students,
1136
                    $doc_state,
1137
                    $work_state,
1138
                    $calendar_state,
1139
                    $announcements_state,
1140
                    $forum_state,
1141
                    $wiki_state,
1142
                    $chat_state,
1143
                    $selfRegistrationAllowed,
1144
                    $selfUnRegistrationAllowed,
1145
                    $id,
1146
                    $documentAccess
1147
                );
1148
            }
1149
        }
1150
    }
1151
1152
    /**
1153
     * Returns the number of groups of the user with the greatest number of
1154
     * subscriptions in the given category.
1155
     */
1156
    public static function get_current_max_groups_per_user($category_id = null, $course_code = null)
1157
    {
1158
        $course_info = api_get_course_info($course_code);
1159
        $group_table = Database::get_course_table(TABLE_GROUP);
1160
1161
        $group_user_table = Database::get_course_table(TABLE_GROUP_USER);
1162
        $sql = "SELECT COUNT(gu.group_id) AS current_max
1163
                FROM $group_user_table gu
1164
                INNER JOIN $group_table g
1165
                ON (gu.group_id = g.iid)
1166
                WHERE 1= 1 ";
1167
        if (null != $category_id) {
1168
            $category_id = intval($category_id);
1169
            $sql .= ' AND g.category_id = '.$category_id;
1170
        }
1171
        $sql .= ' GROUP BY gu.user_id
1172
                  ORDER BY current_max DESC LIMIT 1';
1173
1174
        $res = Database::query($sql);
1175
        $obj = Database::fetch_object($res);
1176
1177
        if ($obj) {
1178
            return $obj->current_max;
1179
        }
1180
1181
        return 0;
1182
    }
1183
1184
    /**
1185
     * Swaps the display-order of two categories.
1186
     *
1187
     * @param int $id1 The id of the first category
1188
     * @param int $id2 The id of the second category
1189
     */
1190
    public static function swap_category_order($id1, $id2)
1191
    {
1192
        $table = Database::get_course_table(TABLE_GROUP_CATEGORY);
1193
        $id1 = intval($id1);
1194
        $id2 = intval($id2);
1195
        $course_id = api_get_course_int_id();
1196
1197
        $sql = "SELECT id, display_order FROM $table
1198
                WHERE id IN ($id1,$id2) AND c_id = $course_id ";
1199
        $res = Database::query($sql);
1200
        $cat1 = Database::fetch_object($res);
1201
        $cat2 = Database::fetch_object($res);
1202
        if ($cat1 && $cat2) {
1203
            $sql = "UPDATE $table SET display_order=$cat2->display_order
1204
                    WHERE id = $cat1->id AND c_id = $course_id ";
1205
            Database::query($sql);
1206
1207
            $sql = "UPDATE $table SET display_order=$cat1->display_order
1208
                    WHERE id = $cat2->id AND c_id = $course_id ";
1209
            Database::query($sql);
1210
        }
1211
    }
1212
1213
    /**
1214
     * Get all users from a given group.
1215
     *
1216
     * @param int  $group_id        The group
1217
     * @param bool $load_extra_info
1218
     * @param int  $start
1219
     * @param int  $limit
1220
     * @param bool $getCount
1221
     * @param int  $courseId
1222
     * @param $column
1223
     * @param $direction
1224
     *
1225
     * @return array list of user id
1226
     */
1227
    public static function get_users(
1228
        $group_id,
1229
        $load_extra_info = false,
1230
        $start = null,
1231
        $limit = null,
1232
        $getCount = false,
1233
        $courseId = null,
1234
        $column = null,
1235
        $direction = null
1236
    ) {
1237
        $group_user_table = Database::get_course_table(TABLE_GROUP_USER);
1238
        $groupTable = Database::get_course_table(TABLE_GROUP);
1239
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
1240
        $group_id = intval($group_id);
1241
1242
        if (empty($courseId)) {
1243
            $courseId = api_get_course_int_id();
1244
        } else {
1245
            $courseId = intval($courseId);
1246
        }
1247
1248
        $select = ' SELECT u.id, firstname, lastname ';
1249
        if ($getCount) {
1250
            $select = ' SELECT count(u.id) count';
1251
        }
1252
        $sql = "$select
1253
                FROM $group_user_table gu
1254
                INNER JOIN $groupTable g
1255
                ON (gu.group_id = g.id and g.c_id = gu.c_id)
1256
                INNER JOIN $user_table u
1257
                ON (u.id = gu.user_id)
1258
                WHERE
1259
                    gu.c_id = $courseId AND
1260
                    g.id = $group_id";
1261
1262
        if (!empty($column) && !empty($direction)) {
1263
            $column = Database::escape_string($column, null, false);
1264
            $direction = ('ASC' == $direction ? 'ASC' : 'DESC');
1265
            $sql .= " ORDER BY $column $direction";
1266
        }
1267
1268
        if (!empty($start) && !empty($limit)) {
1269
            $start = (int) $start;
1270
            $limit = (int) $limit;
1271
            $sql .= " LIMIT $start, $limit";
1272
        }
1273
        $res = Database::query($sql);
1274
        $users = [];
1275
        while ($obj = Database::fetch_object($res)) {
1276
            if ($getCount) {
1277
                return $obj->count;
1278
                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...
1279
            }
1280
            if ($load_extra_info) {
1281
                $users[] = api_get_user_info($obj->id);
1282
            } else {
1283
                $users[] = $obj->id;
1284
            }
1285
        }
1286
1287
        return $users;
1288
    }
1289
1290
    /**
1291
     * @param int $group_id id
1292
     *
1293
     * @return array
1294
     */
1295
    public static function getStudentsAndTutors($group_id)
1296
    {
1297
        $group_user_table = Database::get_course_table(TABLE_GROUP_USER);
1298
        $tutor_user_table = Database::get_course_table(TABLE_GROUP_TUTOR);
1299
        $groupTable = Database::get_course_table(TABLE_GROUP);
1300
1301
        $course_id = api_get_course_int_id();
1302
        $group_id = (int) $group_id;
1303
1304
        $sql = "SELECT user_id
1305
                FROM $group_user_table gu
1306
                INNER JOIN $groupTable g
1307
                ON (gu.group_id = g.iid)
1308
                WHERE g.iid = $group_id";
1309
        $res = Database::query($sql);
1310
        $users = [];
1311
1312
        while ($obj = Database::fetch_object($res)) {
1313
            $users[] = api_get_user_info($obj->user_id);
1314
        }
1315
1316
        $sql = "SELECT user_id
1317
                FROM $tutor_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
        while ($obj = Database::fetch_object($res)) {
1323
            $users[] = api_get_user_info($obj->user_id);
1324
        }
1325
1326
        return $users;
1327
    }
1328
1329
    /**
1330
     * Get only tutors from a group.
1331
     *
1332
     * @param array $groupInfo
1333
     *
1334
     * @return array
1335
     */
1336
    public static function getTutors($groupInfo)
1337
    {
1338
        $groupTable = Database::get_course_table(TABLE_GROUP);
1339
        $tutor_user_table = Database::get_course_table(TABLE_GROUP_TUTOR);
1340
        $course_id = api_get_course_int_id();
1341
        $group_id = (int) $groupInfo['iid'];
1342
1343
        $sql = "SELECT user_id
1344
                FROM $tutor_user_table gu
1345
                INNER JOIN $groupTable g
1346
                ON (gu.group_id = g.iid)
1347
                WHERE g.iid = $group_id";
1348
        $res = Database::query($sql);
1349
1350
        $users = [];
1351
        while ($obj = Database::fetch_object($res)) {
1352
            $users[] = api_get_user_info($obj->user_id);
1353
        }
1354
1355
        return $users;
1356
    }
1357
1358
    /**
1359
     * Get only students from a group (not tutors).
1360
     *
1361
     * @param int  $group_id         iid
1362
     * @param bool $filterOnlyActive
1363
     *
1364
     * @return array
1365
     */
1366
    public static function getStudents($groupId, $filterOnlyActive = false)
1367
    {
1368
        $groupId = (int) $groupId;
1369
1370
        $activeCondition = $filterOnlyActive ? 'AND u.active = 1' : '';
1371
1372
        $em = Database::getManager();
1373
        $subscriptions = $em
1374
            ->createQuery("
1375
                SELECT u.id FROM ChamiloCoreBundle:User u
1376
                INNER JOIN ChamiloCourseBundle:CGroupRelUser gu
1377
                    WITH u.id = gu.user
1378
                INNER JOIN ChamiloCourseBundle:CGroup g
1379
                WITH gu.group = g.iid
1380
                WHERE g.iid = :group
1381
                    $activeCondition
1382
            ")
1383
            ->setParameters([
1384
                'group' => $groupId,
1385
            ])
1386
            ->getResult();
1387
1388
        $users = [];
1389
        foreach ($subscriptions as $subscription) {
1390
            $users[] = api_get_user_info($subscription['id']);
1391
        }
1392
1393
        return $users;
1394
    }
1395
1396
    /**
1397
     * Returns users belonging to any of the group.
1398
     *
1399
     * @param array $groups list of group ids
1400
     *
1401
     * @return array list of user ids
1402
     */
1403
    public static function get_groups_users($groups = [])
1404
    {
1405
        $result = [];
1406
        $table = Database::get_course_table(TABLE_GROUP_USER);
1407
        $course_id = api_get_course_int_id();
1408
1409
        $groups = array_map('intval', $groups);
1410
        // protect individual elements with surrounding quotes
1411
        $groups = implode(', ', $groups);
1412
        $sql = "SELECT DISTINCT user_id
1413
                FROM $table gu
1414
                WHERE gu.group_id IN ($groups)";
1415
        $rs = Database::query($sql);
1416
        while ($row = Database::fetch_array($rs)) {
1417
            $result[] = $row['user_id'];
1418
        }
1419
1420
        return $result;
1421
    }
1422
1423
    /**
1424
     * Fill the groups with students.
1425
     * The algorithm takes care to first fill the groups with the least # of users.
1426
     * Analysis
1427
     * There was a problem with the "ALL" setting.
1428
     * When max # of groups is set to all, the value is sometimes NULL and sometimes ALL
1429
     * and in both cased the query does not work as expected.
1430
     * Stupid solution (currently implemented: set ALL to a big number (INFINITE) and things are solved :)
1431
     * Better solution: that's up to you.
1432
     *
1433
     * Note
1434
     * Throughout Dokeos there is some confusion about "course id" and "course code"
1435
     * The code is e.g. TEST101, but sometimes a variable that is called courseID also contains a course code string.
1436
     * However, there is also a integer course_id that uniquely identifies the course.
1437
     * ywarnier:> Now the course_id has been removed (25/1/2005)
1438
     * The databases are als very inconsistent in this.
1439
     *
1440
     * @param array $groupInfo
1441
     *
1442
     * @author Chrisptophe Gesche <[email protected]>,
1443
     *         Hugues Peeters     <[email protected]> - original version
1444
     * @author Roan Embrechts - virtual course support, code cleaning
1445
     * @author Bart Mollet - code cleaning, use other GroupManager-functions
1446
     *
1447
     * @return bool
1448
     */
1449
    public static function fillGroupWithUsers($groupInfo)
1450
    {
1451
        $_course = api_get_course_info();
1452
        if (empty($_course) || empty($groupInfo)) {
1453
            return false;
1454
        }
1455
        $session_id = api_get_session_id();
1456
        $complete_user_list = CourseManager::get_user_list_from_course_code(
1457
            $_course['code'],
1458
            $session_id
1459
        );
1460
        $groupIid = $groupInfo['iid'];
1461
        $category = self::get_category_from_group($groupIid);
1462
1463
        // Getting max numbers of user from group
1464
        $maxNumberStudents = empty($groupInfo['maximum_number_of_students']) ? self::INFINITE : $groupInfo['maximum_number_of_students'];
1465
        $groupsPerUser = self::INFINITE;
1466
        $categoryId = 0;
1467
        if ($category) {
1468
            $groupsPerUser = empty($category['groups_per_user']) ? self::INFINITE : $category['groups_per_user'];
1469
            $maxNumberStudentsCategory = empty($category['max_student']) ? self::INFINITE : $category['max_student'];
1470
            $categoryId = $category['id'];
1471
            if ($maxNumberStudentsCategory < $maxNumberStudents) {
1472
                $maxNumberStudents = $maxNumberStudentsCategory;
1473
            }
1474
        }
1475
1476
        $usersToAdd = [];
1477
        foreach ($complete_user_list as $userInfo) {
1478
            $isSubscribed = self::is_subscribed($userInfo['user_id'], $groupInfo);
1479
            if ($isSubscribed) {
1480
                continue;
1481
            }
1482
            $numberOfGroups = self::user_in_number_of_groups(
1483
                $userInfo['user_id'],
1484
                $categoryId
1485
            );
1486
            if ($groupsPerUser > $numberOfGroups) {
1487
                $usersToAdd[] = $userInfo['user_id'];
1488
            }
1489
            if (count($usersToAdd) == $maxNumberStudents) {
1490
                break;
1491
            }
1492
        }
1493
1494
        foreach ($usersToAdd as $userId) {
1495
            self::subscribe_users($userId, $groupInfo);
1496
        }
1497
    }
1498
1499
    /**
1500
     * Get the number of students in a group.
1501
     *
1502
     * @param int $group_id id
1503
     *
1504
     * @return int number of students in the given group
1505
     */
1506
    public static function number_of_students($group_id, $course_id = null)
1507
    {
1508
        $table = Database::get_course_table(TABLE_GROUP_USER);
1509
        $group_id = (int) $group_id;
1510
        $course_id = (int) $course_id;
1511
1512
        if (empty($course_id)) {
1513
            $course_id = api_get_course_int_id();
1514
        }
1515
        $sql = "SELECT COUNT(*) AS number_of_students
1516
                FROM $table
1517
                WHERE c_id = $course_id AND group_id = $group_id";
1518
        $result = Database::query($sql);
1519
        $db_object = Database::fetch_object($result);
1520
1521
        return $db_object->number_of_students;
1522
    }
1523
1524
    /**
1525
     * Maximum number of students in a group.
1526
     *
1527
     * @param int $group_id iid
1528
     *
1529
     * @return int maximum number of students in the given group
1530
     */
1531
    public static function maximum_number_of_students($group_id)
1532
    {
1533
        $table = Database::get_course_table(TABLE_GROUP);
1534
        $group_id = (int) $group_id;
1535
        $course_id = api_get_course_int_id();
1536
        $sql = "SELECT max_student FROM $table
1537
                WHERE iid = $group_id";
1538
        $db_result = Database::query($sql);
1539
        $db_object = Database::fetch_object($db_result);
1540
        if (0 == $db_object->max_student) {
1541
            return self::INFINITE;
1542
        }
1543
1544
        return $db_object->max_student;
1545
    }
1546
1547
    /**
1548
     * Number of groups of a user.
1549
     *
1550
     * @param int $user_id
1551
     * @param int $cat_id
1552
     *
1553
     * @return int the number of groups the user is subscribed in
1554
     */
1555
    public static function user_in_number_of_groups($user_id, $cat_id = 0)
1556
    {
1557
        $table_group_user = Database::get_course_table(TABLE_GROUP_USER);
1558
        $table_group = Database::get_course_table(TABLE_GROUP);
1559
        $user_id = (int) $user_id;
1560
        $cat_id = (int) $cat_id;
1561
1562
        $course_id = api_get_course_int_id();
1563
        $cat_condition = '';
1564
        if (!empty($cat_id)) {
1565
            $cat_condition = " AND g.category_id =  $cat_id ";
1566
        }
1567
1568
        $sql = "SELECT COUNT(*) AS number_of_groups
1569
                FROM $table_group_user gu
1570
                INNER JOIN $table_group g
1571
                ON (g.iid = gu.group_id)
1572
                WHERE
1573
                    gu.user_id = $user_id
1574
                    $cat_condition";
1575
1576
        $result = Database::query($sql);
1577
        $db_object = Database::fetch_object($result);
1578
1579
        return $db_object->number_of_groups;
1580
    }
1581
1582
    /**
1583
     * Is sef-registration allowed?
1584
     *
1585
     * @param int   $user_id
1586
     * @param array $groupInfo
1587
     *
1588
     * @return bool TRUE if self-registration is allowed in the given group
1589
     */
1590
    public static function is_self_registration_allowed($user_id, $groupInfo)
1591
    {
1592
        $course_id = api_get_course_int_id();
1593
        if (empty($user_id)) {
1594
            return false;
1595
        }
1596
1597
        $groupIid = $groupInfo['iid'];
1598
        $table = Database::get_course_table(TABLE_GROUP);
1599
        if (isset($groupIid)) {
1600
            $sql = "SELECT status, self_registration_allowed
1601
                    FROM $table
1602
                    WHERE iid = $groupIid";
1603
            $result = Database::query($sql);
1604
            $group = Database::fetch_object($result);
1605
1606
            if (0 == $group->status || 1 != $group->self_registration_allowed) {
1607
                return false;
1608
            }
1609
1610
            return self::canUserSubscribe($user_id, $groupInfo);
1611
        }
1612
1613
        return false;
1614
    }
1615
1616
    /**
1617
     * Is sef-unregistration allowed?
1618
     *
1619
     * @param int   $user_id
1620
     * @param array $groupInfo
1621
     *
1622
     * @return bool TRUE if self-unregistration is allowed in the given group
1623
     */
1624
    public static function is_self_unregistration_allowed($user_id, $groupInfo)
1625
    {
1626
        if (empty($user_id) || empty($groupInfo)) {
1627
            return false;
1628
        }
1629
        $groupIid = $groupInfo['iid'];
1630
        $table = Database::get_course_table(TABLE_GROUP);
1631
        $course_id = api_get_course_int_id();
1632
1633
        $sql = "SELECT status, self_unregistration_allowed
1634
                FROM $table
1635
                WHERE iid = $groupIid";
1636
        $result = Database::query($sql);
1637
        $group = Database::fetch_object($result);
1638
1639
        if (0 == $group->status || 1 != $group->self_unregistration_allowed) {
1640
            return false;
1641
        }
1642
1643
        return self::is_subscribed($user_id, $groupInfo);
1644
    }
1645
1646
    /**
1647
     * Is user subscribed in group?
1648
     *
1649
     * @param int   $user_id
1650
     * @param array $groupInfo
1651
     *
1652
     * @return bool TRUE if given user is subscribed in given group
1653
     */
1654
    public static function is_subscribed($user_id, $groupInfo)
1655
    {
1656
        $course_id = api_get_course_int_id();
1657
        if (empty($user_id) || empty($groupInfo) || empty($course_id)) {
1658
            return false;
1659
        }
1660
        $table = Database::get_course_table(TABLE_GROUP_USER);
1661
        $group_id = intval($groupInfo['iid']);
1662
        $user_id = intval($user_id);
1663
1664
        $sql = "SELECT 1 FROM $table
1665
                WHERE
1666
                    group_id = $group_id AND
1667
                    user_id = $user_id
1668
                ";
1669
        $result = Database::query($sql);
1670
1671
        return Database::num_rows($result) > 0;
1672
    }
1673
1674
    /**
1675
     * Can a user subscribe to a specified group in a course.
1676
     *
1677
     * @param int   $user_id
1678
     * @param array $groupInfo
1679
     * @param bool  $checkMaxNumberStudents
1680
     *
1681
     * @return bool TRUE if given user  can be subscribed in given group
1682
     */
1683
    public static function canUserSubscribe(
1684
        $user_id,
1685
        $groupInfo,
1686
        $checkMaxNumberStudents = true
1687
    ) {
1688
        $group_id = $groupInfo['id'];
1689
        $groupIid = $groupInfo['iid'];
1690
        if ($checkMaxNumberStudents) {
1691
            $category = self::get_category_from_group($groupIid);
1692
            if ($category) {
1693
                if (self::GROUP_PER_MEMBER_NO_LIMIT == $category['groups_per_user']) {
1694
                    $category['groups_per_user'] = self::INFINITE;
1695
                }
1696
                $result = self::user_in_number_of_groups($user_id, $category['iid']) < $category['groups_per_user'];
1697
                if (false == $result) {
1698
                    return false;
1699
                }
1700
            }
1701
1702
            $result = self::number_of_students($group_id) < self::maximum_number_of_students($groupIid);
1703
1704
            if (false == $result) {
1705
                return false;
1706
            }
1707
        }
1708
1709
        $result = self::is_tutor_of_group($user_id, $groupInfo);
1710
1711
        if ($result) {
1712
            return false;
1713
        }
1714
1715
        $result = self::is_subscribed($user_id, $groupInfo);
1716
1717
        if ($result) {
1718
            return false;
1719
        }
1720
1721
        return true;
1722
    }
1723
1724
    /**
1725
     * Get all subscribed users (members) from a group.
1726
     *
1727
     * @param array $groupInfo
1728
     *
1729
     * @return array An array with information of all users from the given group.
1730
     *               (user_id, firstname, lastname, email)
1731
     */
1732
    public static function get_subscribed_users($groupInfo)
1733
    {
1734
        if (empty($groupInfo)) {
1735
            return [];
1736
        }
1737
1738
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1739
        $table_group_user = Database::get_course_table(TABLE_GROUP_USER);
1740
        $order_clause = api_sort_by_first_name() ? ' ORDER BY u.firstname, u.lastname' : ' ORDER BY u.lastname, u.firstname';
1741
        $orderListByOfficialCode = api_get_setting('order_user_list_by_official_code');
1742
        if ('true' === $orderListByOfficialCode) {
1743
            $order_clause = ' ORDER BY u.official_code, u.firstname, u.lastname';
1744
        }
1745
1746
        $group_id = (int) $groupInfo['iid'];
1747
1748
        if (empty($group_id)) {
1749
            return [];
1750
        }
1751
1752
        $course_id = api_get_course_int_id();
1753
1754
        $sql = "SELECT
1755
                    ug.iid,
1756
                    u.id as user_id,
1757
                    u.lastname,
1758
                    u.firstname,
1759
                    u.email,
1760
                    u.username
1761
                FROM $table_user u
1762
                INNER JOIN $table_group_user ug
1763
                ON (ug.user_id = u.id)
1764
                WHERE
1765
                      ug.group_id = $group_id
1766
                $order_clause";
1767
1768
        $db_result = Database::query($sql);
1769
        $users = [];
1770
        while ($user = Database::fetch_object($db_result)) {
1771
            $users[$user->user_id] = [
1772
                'user_id' => $user->user_id,
1773
                'firstname' => $user->firstname,
1774
                'lastname' => $user->lastname,
1775
                'email' => $user->email,
1776
                'username' => $user->username,
1777
            ];
1778
        }
1779
1780
        return $users;
1781
    }
1782
1783
    /**
1784
     * @author Patrick Cool <[email protected]>, Ghent University
1785
     * Get all subscribed tutors of a group
1786
     *
1787
     * @param array $groupInfo
1788
     *
1789
     * @return array An array with information of all users from the given group.
1790
     *               (user_id, firstname, lastname, email)
1791
     */
1792
    public static function get_subscribed_tutors($groupInfo, $id_only = false)
1793
    {
1794
        if (empty($groupInfo)) {
1795
            return [];
1796
        }
1797
1798
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
1799
        $table_group_tutor = Database::get_course_table(TABLE_GROUP_TUTOR);
1800
        $order_clause = api_sort_by_first_name() ? ' ORDER BY u.firstname, u.lastname' : ' ORDER BY u.lastname, u.firstname';
1801
1802
        $orderListByOfficialCode = api_get_setting('order_user_list_by_official_code');
1803
        if ('true' === $orderListByOfficialCode) {
1804
            $order_clause = ' ORDER BY u.official_code, u.firstname, u.lastname';
1805
        }
1806
1807
        $group_id = (int) $groupInfo['iid'];
1808
        $course_id = api_get_course_int_id();
1809
1810
        $sql = "SELECT u.id, u.lastname, u.firstname, u.email
1811
                FROM $table_user u
1812
                INNER JOIN $table_group_tutor tg
1813
                ON (tg.user_id = u.id)
1814
                WHERE
1815
                    tg.group_id = $group_id
1816
                    $order_clause
1817
                ";
1818
        $db_result = Database::query($sql);
1819
        $users = [];
1820
        while ($user = Database::fetch_object($db_result)) {
1821
            if (!$id_only) {
1822
                $member['user_id'] = $user->id;
1823
                $member['firstname'] = $user->firstname;
1824
                $member['lastname'] = $user->lastname;
1825
                $member['email'] = $user->email;
1826
                $users[] = $member;
1827
            } else {
1828
                $users[] = $user->id;
1829
            }
1830
        }
1831
1832
        return $users;
1833
    }
1834
1835
    /**
1836
     * Subscribe user(s) to a specified group in current course (as a student).
1837
     *
1838
     * @param mixed $user_ids  Can be an array with user-id's or a single user-id
1839
     * @param array $groupInfo
1840
     * @param int   $course_id
1841
     *
1842
     * @return bool TRUE if successful
1843
     */
1844
    public static function subscribe_users($user_ids, $groupInfo, $course_id = null)
1845
    {
1846
        $user_ids = is_array($user_ids) ? $user_ids : [$user_ids];
1847
        $course_id = empty($course_id) ? api_get_course_int_id() : (int) $course_id;
1848
        $group_id = $groupInfo['id'];
1849
1850
        if (!empty($user_ids)) {
1851
            $table = Database::get_course_table(TABLE_GROUP_USER);
1852
            foreach ($user_ids as $user_id) {
1853
                if (self::canUserSubscribe($user_id, $groupInfo)) {
1854
                    $user_id = (int) $user_id;
1855
                    $sql = "INSERT INTO $table (c_id, user_id, group_id, status, role)
1856
                            VALUES ('$course_id', '".$user_id."', '".$group_id."', 0, '')";
1857
                    Database::query($sql);
1858
                }
1859
            }
1860
        }
1861
1862
        return true;
1863
    }
1864
1865
    /**
1866
     * Subscribe tutor(s) to a specified group in current course.
1867
     *
1868
     * @param mixed $user_ids  Can be an array with user-id's or a single user-id
1869
     * @param array $groupInfo
1870
     * @param int   $course_id
1871
     *
1872
     * @author Patrick Cool <[email protected]>, Ghent University
1873
     *
1874
     * @see subscribe_users. This function is almost an exact copy of that function.
1875
     *
1876
     * @return bool TRUE if successful
1877
     */
1878
    public static function subscribe_tutors($user_ids, $groupInfo, $course_id = 0)
1879
    {
1880
        $user_ids = is_array($user_ids) ? $user_ids : [$user_ids];
1881
        $result = true;
1882
        $course_id = isset($course_id) && !empty($course_id) ? intval($course_id) : api_get_course_int_id();
1883
        $table_group_tutor = Database::get_course_table(TABLE_GROUP_TUTOR);
1884
        $groupId = (int) $groupInfo['id'];
1885
1886
        foreach ($user_ids as $user_id) {
1887
            $user_id = intval($user_id);
1888
            if (self::canUserSubscribe($user_id, $groupInfo, false)) {
1889
                $sql = 'INSERT INTO '.$table_group_tutor." (c_id, user_id, group_id)
1890
                        VALUES ('$course_id', '".$user_id."', '".$groupId."')";
1891
                $result = Database::query($sql);
1892
            }
1893
        }
1894
1895
        return $result;
1896
    }
1897
1898
    /**
1899
     * Unsubscribe user(s) from a specified group in current course.
1900
     *
1901
     * @param mixed $user_ids  Can be an array with user-id's or a single user-id
1902
     * @param array $groupInfo
1903
     *
1904
     * @return bool TRUE if successful
1905
     */
1906
    public static function unsubscribe_users($user_ids, $groupInfo)
1907
    {
1908
        $user_ids = is_array($user_ids) ? $user_ids : [$user_ids];
1909
        $table_group_user = Database::get_course_table(TABLE_GROUP_USER);
1910
        $group_id = intval($groupInfo['id']);
1911
        $course_id = api_get_course_int_id();
1912
        $sql = 'DELETE FROM '.$table_group_user.'
1913
                WHERE
1914
                    group_id = '.$group_id.' AND
1915
                    user_id IN ('.implode(',', $user_ids).')
1916
                ';
1917
        Database::query($sql);
1918
    }
1919
1920
    /**
1921
     * Unsubscribe all users from one or more groups.
1922
     *
1923
     * @param array $groupInfo
1924
     *
1925
     * @return bool TRUE if successful
1926
     */
1927
    public static function unsubscribe_all_users($groupInfo)
1928
    {
1929
        $course_id = api_get_course_int_id();
1930
        $groupId = (int) $groupInfo['id'];
1931
        if (empty($course_id) || empty($groupId)) {
1932
            return false;
1933
        }
1934
1935
        $table_group_user = Database::get_course_table(TABLE_GROUP_USER);
1936
        $sql = "DELETE FROM $table_group_user
1937
                WHERE
1938
                    group_id = $groupId ";
1939
1940
        return Database::query($sql);
1941
    }
1942
1943
    /**
1944
     * Unsubscribe all tutors from one or more groups.
1945
     *
1946
     * @param int $groupId iid
1947
     *
1948
     * @see unsubscribe_all_users. This function is almost an exact copy of that function.
1949
     *
1950
     * @return bool TRUE if successful
1951
     *
1952
     * @author Patrick Cool <[email protected]>, Ghent University
1953
     */
1954
    public static function unsubscribe_all_tutors($groupId)
1955
    {
1956
        $courseId = api_get_course_int_id();
1957
        $groupId = (int) $groupId;
1958
1959
        if (empty($courseId) || empty($groupId)) {
1960
            return false;
1961
        }
1962
1963
        if (!empty($groupId)) {
1964
            $table_group_tutor = Database::get_course_table(TABLE_GROUP_TUTOR);
1965
            $sql = "DELETE FROM $table_group_tutor
1966
                    WHERE group_id = $groupId ";
1967
            $result = Database::query($sql);
1968
1969
            return $result;
1970
        }
1971
1972
        return true;
1973
    }
1974
1975
    /**
1976
     * Is the user a tutor of this group?
1977
     *
1978
     * @param int   $user_id   the id of the user
1979
     * @param array $groupInfo
1980
     * @param int   $courseId
1981
     *
1982
     * @return bool true/false
1983
     *
1984
     * @todo use the function user_has_access that includes this function
1985
     *
1986
     * @author Patrick Cool <[email protected]>, Ghent University
1987
     */
1988
    public static function is_tutor_of_group($user_id, $groupInfo, $courseId = 0)
1989
    {
1990
        if (empty($groupInfo)) {
1991
            return false;
1992
        }
1993
1994
        $courseId = empty($courseId) ? api_get_course_int_id() : (int) $courseId;
1995
        if (empty($courseId)) {
1996
            return false;
1997
        }
1998
1999
        $user_id = (int) $user_id;
2000
        $group_id = (int) $groupInfo['id'];
2001
2002
        $table = Database::get_course_table(TABLE_GROUP_TUTOR);
2003
2004
        $sql = "SELECT * FROM $table
2005
                WHERE
2006
                    user_id = $user_id AND
2007
                    group_id = $group_id";
2008
        $result = Database::query($sql);
2009
        if (Database::num_rows($result) > 0) {
2010
            return true;
2011
        }
2012
2013
        return false;
2014
    }
2015
2016
    /**
2017
     * Is the user part of this group? This can be a tutor or a normal member
2018
     * you should use this function if the access to a tool or functionality is
2019
     * restricted to the people who are actually in the group
2020
     * before you had to check if the user was
2021
     * 1. a member of the group OR
2022
     * 2. a tutor of the group. This function combines both.
2023
     *
2024
     * @param int   $user_id   the id of the user
2025
     * @param array $groupInfo
2026
     *
2027
     * @return bool true/false
2028
     *
2029
     * @author Patrick Cool <[email protected]>, Ghent University
2030
     */
2031
    public static function is_user_in_group($user_id, $groupInfo)
2032
    {
2033
        $member = self::is_subscribed($user_id, $groupInfo);
2034
        if ($member) {
2035
            return true;
2036
        }
2037
2038
        $tutor = self::is_tutor_of_group($user_id, $groupInfo);
2039
        if ($tutor) {
2040
            return true;
2041
        }
2042
2043
        return false;
2044
    }
2045
2046
    /**
2047
     * Get all group's from a given course in which a given user is unsubscribed.
2048
     *
2049
     * @author  Patrick Cool
2050
     *
2051
     * @param int $course_id retrieve the groups for
2052
     * @param int $user_id   the ID of the user you want to know all its group memberships
2053
     *
2054
     * @return array
2055
     */
2056
    public static function get_group_ids($course_id, $user_id)
2057
    {
2058
        $groups = [];
2059
        $tbl_group = Database::get_course_table(TABLE_GROUP_USER);
2060
        $tbl_group_tutor = Database::get_course_table(TABLE_GROUP_TUTOR);
2061
        $user_id = intval($user_id);
2062
        $course_id = intval($course_id);
2063
2064
        $sql = "SELECT group_id FROM $tbl_group
2065
                WHERE user_id = '$user_id'";
2066
        $result = Database::query($sql);
2067
2068
        if ($result) {
2069
            while ($row = Database::fetch_array($result)) {
2070
                $groups[] = $row['group_id'];
2071
            }
2072
        }
2073
2074
        //Also loading if i'm the tutor
2075
        $sql = "SELECT group_id FROM $tbl_group_tutor
2076
                WHERE user_id = '$user_id'";
2077
        $result = Database::query($sql);
2078
        if ($result) {
2079
            while ($row = Database::fetch_array($result)) {
2080
                $groups[] = $row['group_id'];
2081
            }
2082
        }
2083
        if (!empty($groups)) {
2084
            array_filter($groups);
2085
        }
2086
2087
        return $groups;
2088
    }
2089
2090
    /**
2091
     * Check if a user has access to a certain group tool.
2092
     *
2093
     * @param int    $user_id  The user id
2094
     * @param int    $group_id The group iid
2095
     * @param string $tool     The tool to check the access rights. This should be
2096
     *                         one of constants: GROUP_TOOL_DOCUMENTS
2097
     *
2098
     * @return bool true if the given user has access to the given tool in the
2099
     *              given course
2100
     */
2101
    public static function user_has_access($user_id, $group_id, $tool)
2102
    {
2103
        // Admin have access everywhere
2104
        if (api_is_platform_admin()) {
2105
            return true;
2106
        }
2107
2108
        // Course admin also have access to everything
2109
        if (api_is_allowed_to_edit(false, true, true)) {
2110
            return true;
2111
        }
2112
2113
        switch ($tool) {
2114
            case self::GROUP_TOOL_FORUM:
2115
                $key = 'forum_state';
2116
                break;
2117
            case self::GROUP_TOOL_DOCUMENTS:
2118
                $key = 'doc_state';
2119
                break;
2120
            case self::GROUP_TOOL_CALENDAR:
2121
                $key = 'calendar_state';
2122
                break;
2123
            case self::GROUP_TOOL_ANNOUNCEMENT:
2124
                $key = 'announcements_state';
2125
                break;
2126
            case self::GROUP_TOOL_WORK:
2127
                $key = 'work_state';
2128
                break;
2129
            case self::GROUP_TOOL_WIKI:
2130
                $key = 'wiki_state';
2131
                break;
2132
            case self::GROUP_TOOL_CHAT:
2133
                $key = 'chat_state';
2134
                break;
2135
            default:
2136
                return false;
2137
        }
2138
2139
        // Check group properties
2140
        $groupInfo = self::get_group_properties($group_id, true);
2141
2142
        if (empty($groupInfo)) {
2143
            return false;
2144
        }
2145
2146
        if (0 == $groupInfo['status']) {
2147
            return false;
2148
        }
2149
2150
        if (!isset($groupInfo[$key])) {
2151
            return false;
2152
        }
2153
2154
        $status = $groupInfo[$key];
2155
2156
        switch ($status) {
2157
            case self::TOOL_NOT_AVAILABLE:
2158
                return false;
2159
                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...
2160
            case self::TOOL_PUBLIC:
2161
                return true;
2162
                break;
2163
            case self::TOOL_PRIVATE:
2164
                $userIsInGroup = self::is_user_in_group($user_id, $groupInfo);
2165
                if ($userIsInGroup) {
2166
                    return true;
2167
                }
2168
                break;
2169
            case self::TOOL_PRIVATE_BETWEEN_USERS:
2170
                // Only works for announcements for now
2171
                $userIsInGroup = self::is_user_in_group($user_id, $groupInfo);
2172
                if ($userIsInGroup && self::GROUP_TOOL_ANNOUNCEMENT == $tool) {
2173
                    return true;
2174
                }
2175
                break;
2176
        }
2177
2178
        return false;
2179
    }
2180
2181
    /**
2182
     * @param int   $userId
2183
     * @param array $groupInfo
2184
     * @param int   $sessionId
2185
     *
2186
     * @return bool
2187
     */
2188
    public static function userHasAccessToBrowse($userId, $groupInfo, $sessionId = 0)
2189
    {
2190
        if (empty($groupInfo)) {
2191
            return false;
2192
        }
2193
2194
        if (api_is_platform_admin()) {
2195
            return true;
2196
        }
2197
2198
        if (api_is_allowed_to_edit(false, true, true)) {
2199
            return true;
2200
        }
2201
2202
        if (!empty($sessionId)) {
2203
            if (api_is_coach($sessionId, api_get_course_int_id())) {
2204
                return true;
2205
            }
2206
2207
            if (api_is_drh()) {
2208
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
2209
                    return true;
2210
                }
2211
            }
2212
        }
2213
2214
        $groupId = $groupInfo['iid'];
2215
        if (self::is_tutor_of_group($userId, $groupInfo)) {
2216
            return true;
2217
        }
2218
2219
        if (0 == $groupInfo['status']) {
2220
            return false;
2221
        }
2222
2223
        if (self::user_has_access($userId, $groupId, self::GROUP_TOOL_FORUM) ||
2224
            self::user_has_access($userId, $groupId, self::GROUP_TOOL_DOCUMENTS) ||
2225
            self::user_has_access($userId, $groupId, self::GROUP_TOOL_CALENDAR) ||
2226
            self::user_has_access($userId, $groupId, self::GROUP_TOOL_ANNOUNCEMENT) ||
2227
            self::user_has_access($userId, $groupId, self::GROUP_TOOL_WORK) ||
2228
            self::user_has_access($userId, $groupId, self::GROUP_TOOL_WIKI) ||
2229
            self::user_has_access($userId, $groupId, self::GROUP_TOOL_CHAT)
2230
        ) {
2231
            return true;
2232
        }
2233
2234
        if (api_is_session_general_coach() && $groupInfo['session_id'] == $sessionId) {
2235
            return true;
2236
        }
2237
2238
        return false;
2239
    }
2240
2241
    /**
2242
     * Get all groups where a specific user is subscribed.
2243
     *
2244
     * @param int $user_id
2245
     *
2246
     * @return array
2247
     */
2248
    public static function get_user_group_name($user_id)
2249
    {
2250
        $table_group_user = Database::get_course_table(TABLE_GROUP_USER);
2251
        $table_group = Database::get_course_table(TABLE_GROUP);
2252
        $user_id = intval($user_id);
2253
        $course_id = api_get_course_int_id();
2254
        $sql = "SELECT name
2255
                FROM $table_group g
2256
                INNER JOIN $table_group_user gu
2257
                ON (gu.group_id = g.iid)
2258
                WHERE
2259
                  gu.user_id = $user_id";
2260
        $res = Database::query($sql);
2261
        $groups = [];
2262
        while ($group = Database::fetch_array($res)) {
2263
            $groups[] .= $group['name'];
2264
        }
2265
2266
        return $groups;
2267
    }
2268
2269
    /**
2270
     * Get all groups where a specific user is subscribed.
2271
     *
2272
     * @param int      $user_id
2273
     * @param int      $courseId
2274
     * @param int|null $sessionId
2275
     *
2276
     * @return array
2277
     */
2278
    public static function getAllGroupPerUserSubscription($user_id, $courseId = 0, $sessionId = null)
2279
    {
2280
        $table_group_user = Database::get_course_table(TABLE_GROUP_USER);
2281
        $table_tutor_user = Database::get_course_table(TABLE_GROUP_TUTOR);
2282
        $table_group = Database::get_course_table(TABLE_GROUP);
2283
        $user_id = (int) $user_id;
2284
        $courseId = empty($courseId) ? api_get_course_int_id() : (int) $courseId;
2285
2286
        $sql = "SELECT DISTINCT g.*
2287
               FROM $table_group g
2288
               LEFT JOIN $table_group_user gu
2289
               ON (gu.group_id = g.iid AND g.c_id = gu.c_id)
2290
               LEFT JOIN $table_tutor_user tu
2291
               ON (tu.group_id = g.iid AND g.c_id = tu.c_id)
2292
               WHERE
2293
                  g.c_id = $courseId AND
2294
                  (gu.user_id = $user_id OR tu.user_id = $user_id) ";
2295
2296
        if (null !== $sessionId) {
2297
            $sessionId = (int) $sessionId;
2298
            $sql .= " AND g.session_id = $sessionId ";
2299
        }
2300
2301
        $res = Database::query($sql);
2302
        $groups = [];
2303
        while ($group = Database::fetch_array($res, 'ASSOC')) {
2304
            $groups[] = $group;
2305
        }
2306
2307
        return $groups;
2308
    }
2309
2310
    /**
2311
     * @param array $group_list
2312
     * @param int   $category_id
2313
     *
2314
     * @return string
2315
     */
2316
    public static function process_groups($group_list, $category_id = 0)
2317
    {
2318
        $charset = 'UTF-8';
2319
        $category_id = (int) $category_id;
2320
        $totalRegistered = 0;
2321
        $group_data = [];
2322
        $user_info = api_get_user_info();
2323
        $session_id = api_get_session_id();
2324
        $user_id = $user_info['user_id'];
2325
        $hideGroup = api_get_setting('hide_course_group_if_no_tools_available');
2326
        $extraField = new ExtraField('survey');
2327
        $surveyGroupExists = $extraField->get_handler_field_info_by_field_variable('group_id') ? true : false;
2328
        $url = api_get_path(WEB_CODE_PATH).'group/';
2329
2330
        foreach ($group_list as $this_group) {
2331
            $groupId = $this_group['iid'];
2332
            // Validation when belongs to a session
2333
            $session_img = '';
2334
            //$session_img = api_get_session_image($this_group['session_id'], $user_info['status']);
2335
2336
            // All the tutors of this group
2337
            $tutors = self::get_subscribed_tutors($this_group, true);
2338
            $isMember = self::is_subscribed($user_id, $this_group);
2339
2340
            // Create a new table-row
2341
            $row = [];
2342
            // Checkbox
2343
            if (api_is_allowed_to_edit(false, true) && count($group_list) > 1) {
2344
                $row[] = $this_group['iid'];
2345
            }
2346
2347
            if (self::userHasAccessToBrowse($user_id, $this_group, $session_id)) {
2348
                // Group name
2349
                $groupNameClass = null;
2350
                if (0 == $this_group['status']) {
2351
                    $groupNameClass = 'muted';
2352
                }
2353
2354
                $group_name = '<a
2355
                    class="'.$groupNameClass.'"
2356
                    href="group_space.php?'.api_get_cidreq(true, false).'&gid='.$groupId.'">'.
2357
                    Security::remove_XSS($this_group['name']).'</a> ';
2358
2359
                $group_name2 = '';
2360
                if (api_get_configuration_value('extra')) {
2361
                    $group_name2 = '<a href="group_space_tracking.php?cid='.api_get_course_int_id().'&gid='
2362
                        .$groupId.'">'.get_lang('suivi_de').''.stripslashes($this_group['name']).'</a>';
2363
                }
2364
2365
                if (!empty($user_id) && !empty($this_group['id_tutor']) && $user_id == $this_group['id_tutor']) {
2366
                    $group_name .= Display::label(get_lang('my supervision'), 'success');
2367
                } elseif ($isMember) {
2368
                    $group_name .= Display::label(get_lang('my group'), 'success');
2369
                }
2370
2371
                if (api_is_allowed_to_edit() && !empty($this_group['session_name'])) {
2372
                    $group_name .= ' ('.$this_group['session_name'].')';
2373
                }
2374
                $group_name .= $session_img;
2375
                $row[] = $group_name.$group_name2.'<br />'.stripslashes(trim($this_group['description']));
2376
            } else {
2377
                if ('true' === $hideGroup) {
2378
                    continue;
2379
                }
2380
                $row[] = $this_group['name'].'<br />'.stripslashes(trim($this_group['description']));
2381
            }
2382
2383
            // Tutor name
2384
            $tutor_info = '';
2385
            if (count($tutors) > 0) {
2386
                foreach ($tutors as $tutor_id) {
2387
                    $tutor = api_get_user_info($tutor_id);
2388
                    $username = api_htmlentities(
2389
                        sprintf(get_lang('Login: %s'), $tutor['username']),
2390
                        ENT_QUOTES
2391
                    );
2392
                    if ('true' === api_get_setting('show_email_addresses')) {
2393
                        $tutor_info .= Display::tag(
2394
                            'span',
2395
                            Display::encrypted_mailto_link(
2396
                                $tutor['mail'],
2397
                                $tutor['complete_name']
2398
                            ),
2399
                            ['title' => $username]
2400
                        ).', ';
2401
                    } else {
2402
                        if (api_is_allowed_to_edit()) {
2403
                            $tutor_info .= Display::tag(
2404
                            'span',
2405
                                Display::encrypted_mailto_link(
2406
                                    $tutor['mail'],
2407
                                    $tutor['complete_name_with_username']
2408
                                ),
2409
                                ['title' => $username]
2410
                            ).', ';
2411
                        } else {
2412
                            $tutor_info .= Display::tag(
2413
                                'span',
2414
                                $tutor['complete_name'],
2415
                                ['title' => $username]
2416
                            ).', ';
2417
                        }
2418
                    }
2419
                }
2420
            }
2421
2422
            $tutor_info = api_substr(
2423
                $tutor_info,
2424
                0,
2425
                api_strlen($tutor_info) - 2
2426
            );
2427
            $row[] = $tutor_info;
2428
2429
            // Max number of members in group
2430
            $max_members = self::MEMBER_PER_GROUP_NO_LIMIT == $this_group['maxStudent'] ? ' ' : ' / '.$this_group['maxStudent'];
2431
2432
            // Number of members in group
2433
            $row[] = $this_group['maxStudent'].$max_members;
2434
2435
            // Self-registration / unregistration
2436
            if (!api_is_allowed_to_edit(false, true)) {
2437
                if (self::is_self_registration_allowed($user_id, $this_group)) {
2438
                    $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>';
2439
                } elseif (self::is_self_unregistration_allowed($user_id, $this_group)) {
2440
                    $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>';
2441
                } else {
2442
                    $row[] = '-';
2443
                }
2444
            }
2445
2446
            // Edit-links
2447
            if (api_is_allowed_to_edit(false, true) &&
2448
                !(api_is_session_general_coach() && intval($this_group['session_id']) != $session_id)
2449
            ) {
2450
                $edit_actions = '<a href="'.$url.'settings.php?'.api_get_cidreq(true, false).'&gid='.$groupId.'"  title="'.get_lang('Edit').'">'.
2451
                    Display::return_icon('edit.png', get_lang('Edit this group'), '', ICON_SIZE_SMALL).'</a>&nbsp;';
2452
2453
                if (1 == $this_group['status']) {
2454
                    $edit_actions .= '<a href="'.api_get_self().'?'.api_get_cidreq(true, false).'&category='.$category_id.'&action=set_invisible&id='.$groupId.'" title="'.get_lang('Hide').'">'.
2455
                        Display::return_icon('visible.png', get_lang('Hide'), '', ICON_SIZE_SMALL).'</a>&nbsp;';
2456
                } else {
2457
                    $edit_actions .= '<a href="'.api_get_self().'?'.api_get_cidreq(true, false).'&category='.$category_id.'&action=set_visible&id='.$groupId.'" title="'.get_lang('Show').'">'.
2458
                        Display::return_icon('invisible.png', get_lang('Show'), '', ICON_SIZE_SMALL).'</a>&nbsp;';
2459
                }
2460
2461
                $edit_actions .= '<a href="'.$url.'member_settings.php?'.api_get_cidreq(true, false).'&gid='.$groupId.'"  title="'.get_lang('Group members').'">'.
2462
                    Display::return_icon('user.png', get_lang('Group members'), '', ICON_SIZE_SMALL).'</a>&nbsp;';
2463
2464
                $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').'">'.
2465
                    Display::return_icon('export_excel.png', get_lang('Export'), '', ICON_SIZE_SMALL).'</a>&nbsp;';
2466
2467
                if ($surveyGroupExists) {
2468
                    $edit_actions .= Display::url(
2469
                            Display::return_icon('survey.png', get_lang('ExportSurveyResults'), '', ICON_SIZE_SMALL),
2470
                            $url.'group_overview.php?action=export_surveys&'.api_get_cidreq(true, false).'&id='.$groupId
2471
                        ).'&nbsp;';
2472
                }
2473
                $edit_actions .= '<a href="'.api_get_self().'?'.api_get_cidreq(true, false).'&category='.$category_id.'&action=fill_one&id='.$groupId.'"
2474
                    onclick="javascript: if(!confirm('."'".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES))."'".')) return false;" title="'.get_lang('FillGroup').'">'.
2475
                    Display::return_icon('fill.png', get_lang('FillGroup'), '', ICON_SIZE_SMALL).'</a>&nbsp;';
2476
2477
                $edit_actions .= '<a href="'.api_get_self().'?'.api_get_cidreq(true, false).'&category='.$category_id.'&action=delete_one&id='.$groupId.'"
2478
                    onclick="javascript: if(!confirm('."'".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES))."'".')) return false;" title="'.get_lang('Delete').'">'.
2479
                    Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL).'</a>&nbsp;';
2480
2481
                $row[] = $edit_actions;
2482
            }
2483
            if (!empty($this_group['nbMember'])) {
2484
                $totalRegistered = $totalRegistered + $this_group['nbMember'];
2485
            }
2486
            $group_data[] = $row;
2487
        } // end loop
2488
2489
        // If no groups then don't show the table (only for students)
2490
        if (!api_is_allowed_to_edit(true, false)) {
2491
            if (empty($group_data)) {
2492
                return '';
2493
            }
2494
        }
2495
2496
        $table = new SortableTableFromArrayConfig(
2497
            $group_data,
2498
            1,
2499
            20,
2500
            'group_category_'.$category_id
2501
        );
2502
        $table->set_additional_parameters(['category' => $category_id]);
2503
        $column = 0;
2504
        if (api_is_allowed_to_edit(false, true) and count($group_list) > 1) {
2505
            $table->set_header($column++, '', false);
2506
        }
2507
        $table->set_header($column++, get_lang('Groups'));
2508
        $table->set_header($column++, get_lang('Group tutor'));
2509
        $table->set_header($column++, get_lang('Registered'), false);
2510
2511
        if (!api_is_allowed_to_edit(false, true)) {
2512
            // If self-registration allowed
2513
            $table->set_header($column++, get_lang('Registration'), false);
2514
        }
2515
2516
        if (api_is_allowed_to_edit(false, true)) {
2517
            // Only for course administrator
2518
            $table->set_header($column++, get_lang('Edit'), false);
2519
            $form_actions = [];
2520
            $form_actions['fill_selected'] = get_lang('Fill the group randomly with course students');
2521
            $form_actions['empty_selected'] = get_lang('unsubscribe all users');
2522
            $form_actions['delete_selected'] = get_lang('Delete');
2523
            if (count($group_list) > 1) {
2524
                $table->set_form_actions($form_actions, 'group');
2525
            }
2526
        }
2527
2528
        return $table->return_table();
2529
    }
2530
2531
    /**
2532
     * @param array $groupData
2533
     * @param bool  $deleteNotInArray
2534
     *
2535
     * @return array
2536
     */
2537
    public static function importCategoriesAndGroupsFromArray($groupData, $deleteNotInArray = false)
2538
    {
2539
        $result = [];
2540
        $elementsFound = [
2541
            'categories' => [],
2542
            'groups' => [],
2543
        ];
2544
2545
        $courseCode = api_get_course_id();
2546
        $sessionId = api_get_session_id();
2547
        $groupCategories = self::get_categories();
2548
2549
        if (empty($groupCategories)) {
2550
            $result['error'][] = get_lang('Create a category');
2551
2552
            return $result;
2553
        }
2554
2555
        foreach ($groupData as $data) {
2556
            $isCategory = empty($data['group']) ? true : false;
2557
            if ($isCategory) {
2558
                $categoryInfo = self::getCategoryByTitle($data['category']);
2559
                $categoryId = $categoryInfo['id'];
2560
2561
                if (!empty($categoryInfo)) {
2562
                    // Update
2563
                    self::update_category(
2564
                        $categoryId,
2565
                        $data['category'],
2566
                        $data['description'],
2567
                        $data['doc_state'],
2568
                        $data['work_state'],
2569
                        $data['calendar_state'],
2570
                        $data['announcements_state'],
2571
                        $data['forum_state'],
2572
                        $data['wiki_state'],
2573
                        $data['chat_state'],
2574
                        $data['self_reg_allowed'],
2575
                        $data['self_unreg_allowed'],
2576
                        $data['max_student'],
2577
                        $data['groups_per_user'],
2578
                        $data['document_access']
2579
                    );
2580
                    $data['category_id'] = $categoryId;
2581
                    $result['updated']['category'][] = $data;
2582
                } else {
2583
                    // Add
2584
                    $categoryId = self::create_category(
2585
                        $data['category'],
2586
                        $data['description'],
2587
                        $data['doc_state'],
2588
                        $data['work_state'],
2589
                        $data['calendar_state'],
2590
                        $data['announcements_state'],
2591
                        $data['forum_state'],
2592
                        $data['wiki_state'],
2593
                        $data['chat_state'],
2594
                        $data['self_reg_allowed'],
2595
                        $data['self_unreg_allowed'],
2596
                        $data['max_student'],
2597
                        $data['groups_per_user']
2598
                    );
2599
2600
                    if ($categoryId) {
2601
                        $data['category_id'] = $categoryId;
2602
                        $result['added']['category'][] = $data;
2603
                    }
2604
                }
2605
                $elementsFound['categories'][] = $categoryId;
2606
            } else {
2607
                $groupInfo = self::getGroupByName($data['group']);
2608
                $categoryInfo = [];
2609
                if (isset($data['category'])) {
2610
                    $categoryInfo = self::getCategoryByTitle($data['category']);
2611
                }
2612
                $categoryId = null;
2613
                if (!empty($categoryInfo)) {
2614
                    $categoryId = $categoryInfo['id'];
2615
                } else {
2616
                    if (!empty($groupCategories) && isset($groupCategories[0])) {
2617
                        $defaultGroupCategory = $groupCategories[0];
2618
                        $categoryId = $defaultGroupCategory['id'];
2619
                    }
2620
                }
2621
2622
                if (empty($groupInfo)) {
2623
                    // Add
2624
                    $groupId = self::create_group(
2625
                        $data['group'],
2626
                        $categoryId,
2627
                        null,
2628
                        $data['max_student']
2629
                    );
2630
2631
                    if ($groupId) {
2632
                        self::set_group_properties(
2633
                            $groupId,
2634
                            $data['group'],
2635
                            $data['description'],
2636
                            $data['max_student'],
2637
                            $data['doc_state'],
2638
                            $data['work_state'],
2639
                            $data['calendar_state'],
2640
                            $data['announcements_state'],
2641
                            $data['forum_state'],
2642
                            $data['wiki_state'],
2643
                            $data['chat_state'],
2644
                            $data['self_reg_allowed'],
2645
                            $data['self_unreg_allowed'],
2646
                            $categoryId
2647
                        );
2648
                        $data['group_id'] = $groupId;
2649
                        $result['added']['group'][] = $data;
2650
                    }
2651
                    $groupInfo = self::get_group_properties($groupId, true);
2652
                } else {
2653
                    // Update
2654
                    $groupId = $groupInfo['id'];
2655
                    self::set_group_properties(
2656
                        $groupId,
2657
                        $data['group'],
2658
                        $data['description'],
2659
                        $data['max_student'],
2660
                        $data['doc_state'],
2661
                        $data['work_state'],
2662
                        $data['calendar_state'],
2663
                        $data['announcements_state'],
2664
                        $data['forum_state'],
2665
                        $data['wiki_state'],
2666
                        $data['chat_state'],
2667
                        $data['self_reg_allowed'],
2668
                        $data['self_unreg_allowed'],
2669
                        $categoryId
2670
                    );
2671
2672
                    $data['group_id'] = $groupId;
2673
                    $result['updated']['group'][] = $data;
2674
                    $groupInfo = self::get_group_properties($groupId);
2675
                }
2676
2677
                $students = isset($data['students']) ? explode(',', $data['students']) : [];
2678
                if (!empty($students)) {
2679
                    $studentUserIdList = [];
2680
                    foreach ($students as $student) {
2681
                        $userInfo = api_get_user_info_from_username($student);
2682
2683
                        if (!$userInfo) {
2684
                            continue;
2685
                        }
2686
2687
                        if (!CourseManager::is_user_subscribed_in_course(
2688
                                $userInfo['user_id'],
2689
                                $courseCode,
2690
                                !empty($sessionId),
2691
                                $sessionId
2692
                            )
2693
                        ) {
2694
                            Display::addFlash(
2695
                                Display::return_message(
2696
                                    sprintf(
2697
                                        get_lang('Student %s is no subscribed to this course'),
2698
                                        $userInfo['complete_name']
2699
                                    ),
2700
                                    'warning'
2701
                                )
2702
                            );
2703
                            continue;
2704
                        }
2705
2706
                        $studentUserIdList[] = $userInfo['user_id'];
2707
                    }
2708
                    self::subscribe_users($studentUserIdList, $groupInfo);
2709
                }
2710
2711
                $tutors = isset($data['tutors']) ? explode(',', $data['tutors']) : [];
2712
                if (!empty($tutors)) {
2713
                    $tutorIdList = [];
2714
                    foreach ($tutors as $tutor) {
2715
                        $userInfo = api_get_user_info_from_username($tutor);
2716
2717
                        if (!$userInfo) {
2718
                            continue;
2719
                        }
2720
2721
                        if (!CourseManager::is_user_subscribed_in_course(
2722
                                $userInfo['user_id'],
2723
                                $courseCode,
2724
                                !empty($sessionId),
2725
                                $sessionId
2726
                            )
2727
                        ) {
2728
                            Display::addFlash(
2729
                                Display::return_message(
2730
                                    sprintf(get_lang('Tutor %s is no subscribed to this course'), $userInfo['complete_name']),
2731
                                    'warning'
2732
                                )
2733
                            );
2734
2735
                            continue;
2736
                        }
2737
2738
                        $tutorIdList[] = $userInfo['user_id'];
2739
                    }
2740
                    self::subscribe_tutors($tutorIdList, $groupInfo);
2741
                }
2742
2743
                $elementsFound['groups'][] = $groupId;
2744
            }
2745
        }
2746
2747
        if ($deleteNotInArray) {
2748
            // Check categories
2749
            $categories = self::get_categories();
2750
            foreach ($categories as $category) {
2751
                if (!in_array($category['id'], $elementsFound['categories'])) {
2752
                    self::delete_category($category['id']);
2753
                    $category['category'] = $category['title'];
2754
                    $result['deleted']['category'][] = $category;
2755
                }
2756
            }
2757
2758
            $groups = self::get_groups();
2759
            foreach ($groups as $group) {
2760
                if (!in_array($group['iid'], $elementsFound['groups'])) {
2761
                    self::deleteGroup($group);
2762
                    $group['group'] = $group['name'];
2763
                    $result['deleted']['group'][] = $group;
2764
                }
2765
            }
2766
        }
2767
2768
        return $result;
2769
    }
2770
2771
    /**
2772
     * Export all categories/group from a course to an array.
2773
     * This function works only in a context of a course.
2774
     *
2775
     * @param int  $groupId
2776
     * @param bool $loadUsers
2777
     *
2778
     * @return array
2779
     */
2780
    public static function exportCategoriesAndGroupsToArray($groupId = null, $loadUsers = false)
2781
    {
2782
        $data = [];
2783
        $data[] = [
2784
            'category',
2785
            'group',
2786
            'description',
2787
            'announcements_state',
2788
            'calendar_state',
2789
            'chat_state',
2790
            'doc_state',
2791
            'forum_state',
2792
            'work_state',
2793
            'wiki_state',
2794
            'max_student',
2795
            'self_reg_allowed',
2796
            'self_unreg_allowed',
2797
            'groups_per_user',
2798
        ];
2799
2800
        $count = 1;
2801
2802
        if ($loadUsers) {
2803
            $data[0][] = 'students';
2804
            $data[0][] = 'tutors';
2805
        }
2806
2807
        if (false == $loadUsers) {
2808
            $categories = self::get_categories();
2809
2810
            foreach ($categories as $categoryInfo) {
2811
                $data[$count] = [
2812
                    $categoryInfo['title'],
2813
                    null,
2814
                    $categoryInfo['description'],
2815
                    $categoryInfo['announcements_state'],
2816
                    $categoryInfo['calendar_state'],
2817
                    $categoryInfo['chat_state'],
2818
                    $categoryInfo['doc_state'],
2819
                    $categoryInfo['forum_state'],
2820
                    $categoryInfo['work_state'],
2821
                    $categoryInfo['wiki_state'],
2822
                    $categoryInfo['max_student'],
2823
                    $categoryInfo['self_reg_allowed'],
2824
                    $categoryInfo['self_unreg_allowed'],
2825
                    $categoryInfo['groups_per_user'],
2826
                ];
2827
                ++$count;
2828
            }
2829
        }
2830
2831
        $groups = self::get_group_list();
2832
2833
        foreach ($groups as $groupInfo) {
2834
            $groupId = $groupInfo['iid'];
2835
            $categoryTitle = null;
2836
            $categoryInfo = [];
2837
            if (isset($groupInfo['category'])) {
2838
                $categoryInfo = self::get_category($groupInfo['category']);
2839
            }
2840
2841
            $groupSettings = self::get_group_properties($groupId);
2842
            if (!empty($categoryInfo)) {
2843
                $categoryTitle = $categoryInfo['title'];
2844
            }
2845
2846
            $users = self::getStudents($groupId);
2847
            $userList = [];
2848
            foreach ($users as $user) {
2849
                $user = api_get_user_info($user['user_id']);
2850
                $userList[] = $user['username'];
2851
            }
2852
2853
            $tutors = self::getTutors($groupInfo);
2854
            $tutorList = [];
2855
            foreach ($tutors as $user) {
2856
                $user = api_get_user_info($user['user_id']);
2857
                $tutorList[] = $user['username'];
2858
            }
2859
2860
            $userListToString = null;
2861
            if (!empty($userList)) {
2862
                $userListToString = implode(',', $userList);
2863
            }
2864
2865
            $tutorListToString = null;
2866
            if (!empty($tutorList)) {
2867
                $tutorListToString = implode(',', $tutorList);
2868
            }
2869
2870
            $data[$count] = [
2871
                $categoryTitle,
2872
                $groupSettings['name'],
2873
                $groupSettings['description'],
2874
                $groupSettings['announcements_state'],
2875
                $groupSettings['calendar_state'],
2876
                $groupSettings['chat_state'],
2877
                $groupSettings['doc_state'],
2878
                $groupSettings['forum_state'],
2879
                $groupSettings['work_state'],
2880
                $groupSettings['wiki_state'],
2881
                $groupSettings['maximum_number_of_students'],
2882
                $groupSettings['self_registration_allowed'],
2883
                $groupSettings['self_unregistration_allowed'],
2884
                null,
2885
            ];
2886
2887
            if ($loadUsers) {
2888
                $data[$count][] = $userListToString;
2889
                $data[$count][] = $tutorListToString;
2890
            }
2891
2892
            if (!empty($groupId)) {
2893
                if ($groupId == $groupInfo['iid']) {
2894
                    break;
2895
                }
2896
            }
2897
            ++$count;
2898
        }
2899
2900
        return $data;
2901
    }
2902
2903
    /**
2904
     * @param string $default
2905
     */
2906
    public static function getSettingBar($default)
2907
    {
2908
        $activeSettings = null;
2909
        $activeTutor = null;
2910
        $activeMember = null;
2911
2912
        switch ($default) {
2913
            case 'settings':
2914
                $activeSettings = 'active';
2915
                break;
2916
            case'tutor':
2917
                $activeTutor = 'active';
2918
                break;
2919
            case 'member':
2920
                $activeMember = 'active';
2921
                break;
2922
        }
2923
2924
        $url = api_get_path(WEB_CODE_PATH).'group/%s?'.api_get_cidreq();
2925
2926
        echo '
2927
            <ul class="toolbar-groups nav nav-tabs">
2928
                <li class="'.$activeSettings.'">
2929
                    <a id="group_settings_tab" href="'.sprintf($url, 'settings.php').'">
2930
                    '.Display::return_icon('settings.png').' '.get_lang('Settings').'
2931
                    </a>
2932
                </li>
2933
                <li class="'.$activeMember.'">
2934
                    <a id="group_members_tab" href="'.sprintf($url, 'member_settings.php').'">
2935
                    '.Display::return_icon('user.png').' '.get_lang('Group members').'</a>
2936
                </li>
2937
                <li class="'.$activeTutor.'">
2938
                    <a id="group_tutors_tab" href="'.sprintf($url, 'tutor_settings.php').'">
2939
                    '.Display::return_icon('teacher.png').' '.get_lang('Group tutors').'
2940
                    </a>
2941
                </li>
2942
            </ul>';
2943
    }
2944
2945
    /**
2946
     * @param int    $courseId
2947
     * @param string $keyword
2948
     *
2949
     * @return string
2950
     */
2951
    public static function getOverview($courseId, $keyword = '')
2952
    {
2953
        $content = null;
2954
        $categories = self::get_categories();
2955
        if (!empty($categories)) {
2956
            foreach ($categories as $category) {
2957
                if ('true' == api_get_setting('allow_group_categories')) {
2958
                    $content .= '<h2>'.$category['title'].'</h2>';
2959
                }
2960
                if (!empty($keyword)) {
2961
                    $groups = self::getGroupListFilterByName(
2962
                        $keyword,
2963
                        $category['id'],
2964
                        $courseId
2965
                    );
2966
                } else {
2967
                    $groups = self::get_group_list($category['id']);
2968
                }
2969
2970
                if (empty($groups)) {
2971
                    $groups = self::get_group_list();
2972
                }
2973
2974
                $content .= '<ul>';
2975
                if (!empty($groups)) {
2976
                    foreach ($groups as $group) {
2977
                        $content .= '<li>';
2978
                        $content .= Display::tag(
2979
                            'h3',
2980
                            Security::remove_XSS($group['name'])
2981
                        );
2982
                        $users = self::getTutors($group);
2983
                        if (!empty($users)) {
2984
                            $content .= '<ul>';
2985
                            $content .= '<li>'.Display::tag('h4', get_lang('Coaches')).'</li><ul>';
2986
                            foreach ($users as $user) {
2987
                                $user_info = api_get_user_info($user['user_id']);
2988
                                $content .= '<li title="'.$user_info['username'].'">'.
2989
                                    $user_info['complete_name_with_username'].
2990
                                '</li>';
2991
                            }
2992
                            $content .= '</ul>';
2993
                            $content .= '</ul>';
2994
                        }
2995
2996
                        $users = self::getStudents($group['id']);
2997
                        if (!empty($users)) {
2998
                            $content .= '<ul>';
2999
                            $content .= '<li>'.Display::tag('h4', get_lang('Learners')).'</li><ul>';
3000
                            foreach ($users as $user) {
3001
                                $user_info = api_get_user_info($user['user_id']);
3002
                                $content .= '<li title="'.$user_info['username'].'">'.
3003
                                    $user_info['complete_name_with_username'].
3004
                                    '</li>';
3005
                            }
3006
                            $content .= '</ul>';
3007
                            $content .= '</ul>';
3008
                        }
3009
                        $content .= '</li>';
3010
                    }
3011
                }
3012
                $content .= '</ul>';
3013
            }
3014
        }
3015
3016
        return $content;
3017
    }
3018
3019
    /**
3020
     * Returns the search form.
3021
     *
3022
     * @return string
3023
     */
3024
    public static function getSearchForm()
3025
    {
3026
        $url = api_get_path(WEB_CODE_PATH).'group/group_overview.php?'.api_get_cidreq();
3027
        $form = new FormValidator(
3028
            'search_groups',
3029
            'get',
3030
            $url,
3031
            null,
3032
            ['class' => 'form-search'],
3033
            FormValidator::LAYOUT_INLINE
3034
        );
3035
        $form->addElement('text', 'keyword');
3036
        $form->addButtonSearch();
3037
3038
        return $form->toHtml();
3039
    }
3040
3041
    /**
3042
     * @param int $groupId
3043
     * @param int $status
3044
     */
3045
    public static function setStatus($groupId, $status)
3046
    {
3047
        $groupInfo = self::get_group_properties($groupId);
3048
3049
        $courseId = api_get_course_int_id();
3050
        if (!empty($groupInfo)) {
3051
            $table = Database::get_course_table(TABLE_GROUP);
3052
            $params = [
3053
                'status' => intval($status),
3054
            ];
3055
            Database::update(
3056
                $table,
3057
                $params,
3058
                ['c_id = ? AND id = ?' => [$courseId, $groupId]]
3059
            );
3060
        }
3061
    }
3062
3063
    /**
3064
     * @param int $groupId
3065
     */
3066
    public static function setVisible($groupId)
3067
    {
3068
        self::setStatus($groupId, 1);
3069
    }
3070
3071
    /**
3072
     * @param int $groupId
3073
     */
3074
    public static function setInvisible($groupId)
3075
    {
3076
        self::setStatus($groupId, 0);
3077
    }
3078
3079
    /**
3080
     * @param int   $userId
3081
     * @param int   $courseId
3082
     * @param array $groupInfo
3083
     * @param array $documentInfoToBeCheck
3084
     * @param bool  $blockPage
3085
     *
3086
     * @return bool
3087
     */
3088
    public static function allowUploadEditDocument(
3089
        $userId,
3090
        $courseId,
3091
        $groupInfo,
3092
        $documentInfoToBeCheck = null,
3093
        $blockPage = false
3094
    ) {
3095
        // Admin and teachers can make any change no matter what
3096
        if (api_is_platform_admin() || api_is_allowed_to_edit(false, true)) {
3097
            return true;
3098
        }
3099
3100
        if (empty($groupInfo) || !isset($groupInfo['id'])) {
3101
            if ($blockPage) {
3102
                api_not_allowed(true);
3103
            }
3104
3105
            return false;
3106
        }
3107
3108
        // Tutor can also make any change
3109
        $isTutor = self::is_tutor_of_group($userId, $groupInfo, $courseId);
3110
3111
        if ($isTutor) {
3112
            return true;
3113
        }
3114
3115
        // Just in case also check if document in group is available
3116
        if (0 == $groupInfo['doc_state']) {
3117
            if ($blockPage) {
3118
                api_not_allowed(true);
3119
            }
3120
3121
            return false;
3122
        }
3123
3124
        // Default behaviour
3125
        $documentAccess = self::DOCUMENT_MODE_SHARE;
3126
3127
        // Check category document access
3128
        /*$allowCategoryGroupDocumentAccess = api_get_configuration_value('group_category_document_access');
3129
        if ($allowCategoryGroupDocumentAccess) {
3130
            $category = GroupManager::get_category_from_group($groupInfo['iid']);
3131
            if (!empty($category) && isset($category['document_access'])) {
3132
                $documentAccess = (int) $category['document_access'];
3133
            }
3134
        }*/
3135
3136
        // Check group document access
3137
        $allow = api_get_configuration_value('group_document_access');
3138
        if ($allow) {
3139
            if (isset($groupInfo['document_access'])) {
3140
                $documentAccess = (int) $groupInfo['document_access'];
3141
            }
3142
        }
3143
3144
        // Check access for students
3145
        $result = false;
3146
        switch ($documentAccess) {
3147
            case self::DOCUMENT_MODE_SHARE:
3148
                // Default chamilo behaviour
3149
                // Student can upload his own content, cannot modify another content.
3150
                $isMember = self::is_subscribed($userId, $groupInfo);
3151
                if ($isMember) {
3152
                    // No document to check, allow access to document feature.
3153
                    if (empty($documentInfoToBeCheck)) {
3154
                        $result = true;
3155
                    } else {
3156
                        // Member can only edit his own document
3157
                        $authorId = isset($documentInfoToBeCheck['insert_user_id']) ? $documentInfoToBeCheck['insert_user_id'] : 0;
3158
                        // If "insert_user_id" is not set, check the author id from c_item_property
3159
                        if (empty($authorId) && isset($documentInfoToBeCheck['id'])) {
3160
                            // @todo use resources
3161
                            /*$documentInfo = api_get_item_property_info(
3162
                                $courseId,
3163
                                'document',
3164
                                $documentInfoToBeCheck['id'],
3165
                                0
3166
                            );
3167
                            // Try to find this document in the session
3168
                            if (!empty($sessionId)) {
3169
                                $documentInfo = api_get_item_property_info(
3170
                                    $courseId,
3171
                                    'document',
3172
                                    $documentInfoToBeCheck['id'],
3173
                                    api_get_session_id()
3174
                                );
3175
                            }
3176
3177
                            if (!empty($documentInfo) && isset($documentInfo['insert_user_id'])) {
3178
                                $authorId = $documentInfo['insert_user_id'];
3179
                            }*/
3180
                        }
3181
3182
                        if ($authorId == $userId) {
3183
                            $result = true;
3184
                        }
3185
                    }
3186
                }
3187
                break;
3188
            case self::DOCUMENT_MODE_READ_ONLY:
3189
                // Student cannot upload content, cannot modify another content.
3190
                $result = false;
3191
                break;
3192
            case self::DOCUMENT_MODE_COLLABORATION:
3193
                // Student can upload content, can modify another content.
3194
                $isMember = self::is_subscribed($userId, $groupInfo);
3195
                if ($isMember) {
3196
                    $result = true;
3197
                }
3198
                break;
3199
        }
3200
3201
        if ($blockPage && false == $result) {
3202
            api_not_allowed(true);
3203
        }
3204
3205
        return $result;
3206
    }
3207
}
3208