Passed
Push — master ( 39ba65...4e7d2f )
by Julito
10:09
created

GroupManager::create_subgroups()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 41
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

    return false;
}

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

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