Completed
Push — master ( a638fe...506c79 )
by Julito
08:40
created

sendAlertToUsers()   C

Complexity

Conditions 12
Paths 25

Size

Total Lines 80
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 50
nc 25
nop 4
dl 0
loc 80
rs 6.9666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\ResourceLink;
6
use Chamilo\CoreBundle\Framework\Container;
7
use Chamilo\CourseBundle\Entity\CStudentPublication;
8
use Chamilo\CourseBundle\Entity\CStudentPublicationComment;
9
use ChamiloSession as Session;
10
11
/**
12
 *  @author Thomas, Hugues, Christophe - original version
13
 *  @author Patrick Cool <[email protected]>, Ghent University -
14
 * ability for course admins to specify wether uploaded documents are visible or invisible by default.
15
 *  @author Roan Embrechts, code refactoring and virtual course support
16
 *  @author Frederic Vauthier, directories management
17
 *  @author Julio Montoya <[email protected]> BeezNest 2011 LOTS of bug fixes
18
 *
19
 *  @todo   this lib should be convert in a static class and moved to main/inc/lib
20
 */
21
22
/**
23
 * Displays action links (for admins, authorized groups members and authorized students).
24
 *
25
 * @param   int Whether to show tool options
26
 * @param   int Whether to show upload form option
27
 * @param bool $isTutor
28
 */
29
function displayWorkActionLinks($id, $action, $isTutor)
30
{
31
    $id = $my_back_id = (int) $id;
32
    if ('list' == $action) {
33
        $my_back_id = 0;
34
    }
35
36
    $output = '';
37
    $origin = api_get_origin();
38
39
    if (!empty($id)) {
40
        $output .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&id='.$my_back_id.'">'.
41
            Display::return_icon('back.png', get_lang('Back to Assignments list'), '', ICON_SIZE_MEDIUM).
42
            '</a>';
43
    }
44
45
    if (($isTutor || api_is_allowed_to_edit(null, true)) &&
46
        'learnpath' != $origin
47
    ) {
48
        // Create dir
49
        if (empty($id)) {
50
            $output .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=create_dir">';
51
            $output .= Display::return_icon(
52
                'new_work.png',
53
                get_lang('Create assignment'),
54
                '',
55
                ICON_SIZE_MEDIUM
56
            );
57
            $output .= '</a>';
58
        }
59
    }
60
61
    if (api_is_allowed_to_edit(null, true) && 'learnpath' != $origin && 'list' == $action) {
62
        $output .= '<a id="open-view-list" href="#">'.
63
            Display::return_icon(
64
                'listwork.png',
65
                get_lang('View students'),
66
                '',
67
                ICON_SIZE_MEDIUM
68
            ).
69
            '</a>';
70
    }
71
72
    if ('' != $output) {
73
        echo '<div class="actions">';
74
        echo $output;
75
        echo '</div>';
76
    }
77
}
78
79
/**
80
 * @param string $path
81
 * @param int    $courseId
82
 *
83
 * @return array
84
 */
85
function get_work_data_by_path($path, $courseId = 0)
86
{
87
    $path = Database::escape_string($path);
88
    $courseId = (int) $courseId;
89
    if (empty($courseId)) {
90
        $courseId = api_get_course_int_id();
91
    }
92
93
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
94
    $sql = "SELECT *  FROM $table
95
            WHERE url = '$path' AND c_id = $courseId ";
96
    $result = Database::query($sql);
97
    $return = [];
98
    if (Database::num_rows($result)) {
99
        $return = Database::fetch_array($result, 'ASSOC');
100
    }
101
102
    return $return;
103
}
104
105
/**
106
 * @param int $id
107
 * @param int $courseId
108
 * @param int $sessionId
109
 *
110
 * @return array
111
 */
112
function get_work_data_by_id($id, $courseId = 0, $sessionId = 0)
113
{
114
    $id = (int) $id;
115
    $webCodePath = api_get_path(WEB_CODE_PATH);
116
117
    $repo = Container::getStudentPublicationRepository();
118
    /** @var CStudentPublication $studentPublication */
119
    $studentPublication = $repo->find($id);
120
121
    if (empty($studentPublication)) {
122
        return [];
123
    }
124
125
    $router = Container::getRouter();
126
127
    $work = [];
128
    if ($studentPublication) {
0 ignored issues
show
introduced by
$studentPublication is of type Chamilo\CourseBundle\Entity\CStudentPublication, thus it always evaluated to true.
Loading history...
129
        $workId = $studentPublication->getIid();
130
        $work['id'] = $workId;
131
        $work['iid'] = $workId;
132
        $work['description'] = $studentPublication->getDescription();
133
        $work['url'] = $studentPublication->getUrl();
134
        $work['active'] = $studentPublication->getActive();
135
        $work['allow_text_assignment'] = $studentPublication->getAllowTextAssignment();
136
        $work['c_id'] = $studentPublication->getCId();
137
        $work['user_id'] = $studentPublication->getUserId();
138
        $work['parent_id'] = $studentPublication->getParentId();
139
        $work['qualification'] = $studentPublication->getQualification();
140
        $work['contains_file'] = $studentPublication->getContainsFile();
141
        $work['title'] = $studentPublication->getTitle();
142
        if (empty($studentPublication->getTitle())) {
143
            $work['title'] = basename($studentPublication->getUrl());
144
        }
145
        $work['download_url'] = $router->generate(
146
                'chamilo_core_resource_download',
147
                [
148
                    'id' => $studentPublication->getResourceNode()->getId(),
149
                    'tool' => 'student_publication',
150
                    'type' => 'student_publications',
151
                ]
152
            ).'?'.api_get_cidreq();
153
154
        $work['view_url'] = $webCodePath.'work/view.php?id='.$workId.'&'.api_get_cidreq();
155
        $showUrl = $work['show_url'] = $webCodePath.'work/show_file.php?id='.$workId.'&'.api_get_cidreq();
156
        $work['show_content'] = '';
157
        if ($studentPublication->getContainsFile()) {
158
            $fileType = '';
159
            if (in_array($fileType, ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'])) {
160
                $work['show_content'] = Display::img($showUrl, $studentPublication->getTitle(), null, false);
161
            } elseif (false !== strpos($fileType, 'video/')) {
162
                $work['show_content'] = Display::tag(
163
                    'video',
164
                    get_lang('File format not supported'),
165
                    ['src' => $showUrl]
166
                );
167
            }
168
        }
169
170
        $fieldValue = new ExtraFieldValue('work');
171
        $work['extra'] = $fieldValue->getAllValuesForAnItem($id, true);
172
    }
173
174
    return $work;
175
}
176
177
/**
178
 * @param int $user_id
179
 * @param int $work_id
180
 *
181
 * @return int
182
 */
183
function get_work_count_by_student($user_id, $work_id)
184
{
185
    $user_id = (int) $user_id;
186
    $work_id = (int) $work_id;
187
    $course_id = api_get_course_int_id();
188
    $session_id = api_get_session_id();
189
    $sessionCondition = api_get_session_condition($session_id);
190
191
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
192
    $sql = "SELECT COUNT(*) as count
193
            FROM  $table
194
            WHERE
195
                c_id = $course_id AND
196
                parent_id = $work_id AND
197
                user_id = $user_id AND
198
                active IN (0, 1)
199
                $sessionCondition";
200
    $result = Database::query($sql);
201
    $return = 0;
202
    if (Database::num_rows($result)) {
203
        $return = Database::fetch_row($result, 'ASSOC');
204
        $return = (int) ($return[0]);
205
    }
206
207
    return $return;
208
}
209
210
/**
211
 * @param int $id
212
 * @param int $courseId
213
 *
214
 * @return array
215
 */
216
function get_work_assignment_by_id($id, $courseId = 0)
217
{
218
    $courseId = (int) $courseId;
219
    if (empty($courseId)) {
220
        $courseId = api_get_course_int_id();
221
    }
222
    $id = (int) $id;
223
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
224
    $sql = "SELECT * FROM $table
225
            WHERE c_id = $courseId AND publication_id = $id";
226
    $result = Database::query($sql);
227
    $return = [];
228
    if (Database::num_rows($result)) {
229
        $return = Database::fetch_array($result, 'ASSOC');
230
    }
231
232
    return $return;
233
}
234
235
/**
236
 * @param int    $id
237
 * @param array  $my_folder_data
238
 * @param string $add_in_where_query
239
 * @param int    $course_id
240
 * @param int    $session_id
241
 *
242
 * @return array
243
 */
244
function getWorkList($id, $my_folder_data, $add_in_where_query = null, $course_id = 0, $session_id = 0)
245
{
246
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
247
248
    $course_id = $course_id ?: api_get_course_int_id();
249
    $session_id = $session_id ?: api_get_session_id();
250
    $condition_session = api_get_session_condition($session_id);
251
    $group_id = api_get_group_id();
252
253
    $groupIid = 0;
254
    if ($group_id) {
255
        $groupInfo = GroupManager::get_group_properties($group_id);
256
        if ($groupInfo) {
257
            $groupIid = $groupInfo['iid'];
258
        }
259
    }
260
261
    $is_allowed_to_edit = api_is_allowed_to_edit(null, true);
262
    $linkInfo = GradebookUtils::isResourceInCourseGradebook(
263
        api_get_course_id(),
264
        3,
265
        $id,
266
        api_get_session_id()
267
    );
268
269
    if ($linkInfo) {
270
        $workInGradeBookLinkId = $linkInfo['id'];
271
        if ($workInGradeBookLinkId) {
272
            if ($is_allowed_to_edit) {
273
                if (0 == (int) ($my_folder_data['qualification'])) {
274
                    echo Display::return_message(
275
                        get_lang('Max weight need to be provided'),
276
                        'warning'
277
                    );
278
                }
279
            }
280
        }
281
    }
282
283
    $contains_file_query = '';
284
    // Get list from database
285
    if ($is_allowed_to_edit) {
286
        $active_condition = ' active IN (0, 1)';
287
        $sql = "SELECT * FROM $work_table
288
                WHERE
289
                    c_id = $course_id
290
                    $add_in_where_query
291
                    $condition_session AND
292
                    $active_condition AND
293
                    (parent_id = 0)
294
                    $contains_file_query AND
295
                    post_group_id = $groupIid
296
                ORDER BY sent_date DESC";
297
    } else {
298
        if (!empty($group_id)) {
299
            // set to select only messages posted by the user's group
300
            $group_query = " WHERE c_id = $course_id AND post_group_id = $groupIid";
301
            $subdirs_query = ' AND parent_id = 0';
302
        } else {
303
            $group_query = " WHERE c_id = $course_id AND (post_group_id = '0' OR post_group_id is NULL) ";
304
            $subdirs_query = ' AND parent_id = 0';
305
        }
306
        //@todo how we can active or not an assignment?
307
        $active_condition = ' AND active IN (1, 0)';
308
        $sql = "SELECT * FROM  $work_table
309
                $group_query
310
                $subdirs_query
311
                $add_in_where_query
312
                $active_condition
313
                $condition_session
314
                ORDER BY title";
315
    }
316
317
    $work_parents = [];
318
319
    $sql_result = Database::query($sql);
320
    if (Database::num_rows($sql_result)) {
321
        while ($work = Database::fetch_object($sql_result)) {
322
            if (0 == $work->parent_id) {
323
                $work_parents[] = $work;
324
            }
325
        }
326
    }
327
328
    return $work_parents;
329
}
330
331
/**
332
 * @param int $userId
333
 * @param int $courseId
334
 * @param int $sessionId
335
 *
336
 * @return array
337
 */
338
function getWorkPerUser($userId, $courseId = 0, $sessionId = 0)
339
{
340
    $works = getWorkList(null, null, null, $courseId, $sessionId);
341
    $result = [];
342
    if (!empty($works)) {
343
        foreach ($works as $workData) {
344
            $workId = $workData->id;
345
            $result[$workId]['work'] = $workData;
346
            $result[$workId]['work']->user_results = get_work_user_list(
347
                0,
348
                100,
349
                null,
350
                null,
351
                $workId,
352
                null,
353
                $userId,
354
                false,
355
                $courseId,
356
                $sessionId
357
            );
358
        }
359
    }
360
361
    return $result;
362
}
363
364
/**
365
 * @param int $workId
366
 * @param int $groupId
367
 * @param int $course_id
368
 * @param int $sessionId
369
 */
370
function getUniqueStudentAttemptsTotal($workId, $groupId, $course_id, $sessionId)
371
{
372
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
373
    $user_table = Database::get_main_table(TABLE_MAIN_USER);
374
    $course_id = (int) $course_id;
375
    $workId = (int) $workId;
376
    $sessionId = (int) $sessionId;
377
    $groupId = (int) $groupId;
378
    $sessionCondition = api_get_session_condition(
379
        $sessionId,
380
        true,
381
        false,
382
        'w.session_id'
383
    );
384
385
    $groupIid = 0;
386
    if ($groupId) {
387
        $groupInfo = GroupManager::get_group_properties($groupId);
388
        $groupIid = $groupInfo['iid'];
389
    }
390
391
    $sql = "SELECT count(DISTINCT u.id)
392
            FROM $work_table w
393
            INNER JOIN $user_table u
394
            ON w.user_id = u.id
395
            WHERE
396
                w.c_id = $course_id
397
                $sessionCondition AND
398
                w.parent_id = $workId AND
399
                w.post_group_id = $groupIid AND
400
                w.active IN (0, 1)
401
            ";
402
403
    $res_document = Database::query($sql);
404
    $rowCount = Database::fetch_row($res_document);
405
406
    return $rowCount[0];
407
}
408
409
/**
410
 * @param mixed $workId
411
 * @param int   $groupId
412
 * @param int   $course_id
413
 * @param int   $sessionId
414
 * @param int   $userId       user id to filter
415
 * @param array $onlyUserList only parse this user list
416
 *
417
 * @return mixed
418
 */
419
function getUniqueStudentAttempts(
420
    $workId,
421
    $groupId,
422
    $course_id,
423
    $sessionId,
424
    $userId = null,
425
    $onlyUserList = []
426
) {
427
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
428
    $user_table = Database::get_main_table(TABLE_MAIN_USER);
429
430
    $course_id = (int) $course_id;
431
    $workCondition = null;
432
    if (is_array($workId)) {
433
        $workId = array_map('intval', $workId);
434
        $workId = implode("','", $workId);
435
        $workCondition = " w.parent_id IN ('".$workId."') AND";
436
    } else {
437
        $workId = (int) $workId;
438
        $workCondition = ' w.parent_id = '.$workId.' AND';
439
    }
440
441
    $sessionId = (int) $sessionId;
442
    $groupId = (int) $groupId;
443
    $studentCondition = null;
444
445
    if (!empty($onlyUserList)) {
446
        $onlyUserList = array_map('intval', $onlyUserList);
447
        $studentCondition = "AND u.id IN ('".implode("', '", $onlyUserList)."') ";
448
    } else {
449
        if (empty($userId)) {
450
            return 0;
451
        }
452
    }
453
454
    $groupIid = 0;
455
    if ($groupId) {
456
        $groupInfo = GroupManager::get_group_properties($groupId);
457
        $groupIid = $groupInfo['iid'];
458
    }
459
460
    $sessionCondition = api_get_session_condition(
461
        $sessionId,
462
        true,
463
        false,
464
        'w.session_id'
465
    );
466
467
    $sql = "SELECT count(*) FROM (
468
                SELECT count(*), w.parent_id
469
                FROM $work_table w
470
                INNER JOIN $user_table u
471
                ON w.user_id = u.id
472
                WHERE
473
                    w.filetype = 'file' AND
474
                    w.c_id = $course_id
475
                    $sessionCondition AND
476
                    $workCondition
477
                    w.post_group_id = $groupIid AND
478
                    w.active IN (0, 1) $studentCondition
479
                ";
480
    if (!empty($userId)) {
481
        $userId = (int) $userId;
482
        $sql .= ' AND u.id = '.$userId;
483
    }
484
    $sql .= ' GROUP BY u.id, w.parent_id) as t';
485
    $result = Database::query($sql);
486
    $row = Database::fetch_row($result);
487
488
    return $row[0];
489
}
490
491
/**
492
 * Shows the work list (student view).
493
 *
494
 * @return string
495
 */
496
function showStudentWorkGrid()
497
{
498
    $courseInfo = api_get_course_info();
499
    $url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_work_student&'.api_get_cidreq();
500
501
    $columns = [
502
        get_lang('Type'),
503
        get_lang('Title'),
504
        get_lang('Deadline'),
505
        get_lang('Feedback'),
506
        get_lang('Last upload'),
507
    ];
508
509
    $columnModel = [
510
        ['name' => 'type', 'index' => 'type', 'width' => '30', 'align' => 'center', 'sortable' => 'false'],
511
        ['name' => 'title', 'index' => 'title', 'width' => '250', 'align' => 'left'],
512
        ['name' => 'expires_on', 'index' => 'expires_on', 'width' => '80', 'align' => 'center', 'sortable' => 'false'],
513
        ['name' => 'feedback', 'index' => 'feedback', 'width' => '80', 'align' => 'center', 'sortable' => 'false'],
514
        ['name' => 'last_upload', 'index' => 'feedback', 'width' => '125', 'align' => 'center', 'sortable' => 'false'],
515
    ];
516
517
    if (0 == $courseInfo['show_score']) {
518
        $columnModel[] = [
519
            'name' => 'others',
520
            'index' => 'others',
521
            'width' => '80',
522
            'align' => 'left',
523
            'sortable' => 'false',
524
        ];
525
        $columns[] = get_lang('Others');
526
    }
527
528
    $params = [
529
        'autowidth' => 'true',
530
        'height' => 'auto',
531
    ];
532
533
    $html = '<script>
534
        $(function() {
535
            '.Display::grid_js('workList', $url, $columns, $columnModel, $params, [], null, true).'
536
        });
537
    </script>';
538
539
    $html .= Display::grid_html('workList');
540
541
    return $html;
542
}
543
544
/**
545
 * Shows the work list (student view).
546
 *
547
 * @return string
548
 */
549
function showStudentAllWorkGrid($withResults = 1)
550
{
551
    $withResults = (int) $withResults;
552
    $url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_all_work_student&with_results='.$withResults;
553
554
    $columns = [
555
        get_lang('Type'),
556
        get_lang('Title'),
557
        get_lang('HandOutDateLimit'),
558
    ];
559
560
    $id = 'workList';
561
    if ($withResults) {
562
        $id = 'workListWithResults';
563
        $columns[] = get_lang('Feedback');
564
        $columns[] = get_lang('LastUpload');
565
    }
566
567
    $columnModel = [
568
        ['name' => 'type', 'index' => 'type', 'width' => '50', 'align' => 'center', 'sortable' => 'false'],
569
        ['name' => 'title', 'index' => 'title', 'width' => '600', 'align' => 'left'],
570
        ['name' => 'expires_on', 'index' => 'expires_on', 'width' => '125', 'align' => 'center', 'sortable' => 'false'],
571
    ];
572
573
    if ($withResults) {
574
        $columnModel[] = [
575
            'name' => 'feedback',
576
            'index' => 'feedback',
577
            'width' => '150',
578
            'align' => 'center',
579
            'sortable' => 'false',
580
        ];
581
        $columnModel[] = [
582
            'name' => 'last_upload',
583
            'index' => 'last_upload',
584
            'width' => '150',
585
            'align' => 'center',
586
            'sortable' => 'false',
587
        ];
588
    }
589
590
    $params = [
591
        'autowidth' => 'true',
592
        'height' => 'auto',
593
    ];
594
595
    $html = '<script>
596
        $(function() {
597
            '.Display::grid_js($id, $url, $columns, $columnModel, $params, [], null, true).'
598
        });
599
    </script>';
600
601
    $html .= Display::grid_html($id);
602
603
    return $html;
604
}
605
606
/**
607
 * Shows the work list (teacher view).
608
 *
609
 * @return string
610
 */
611
function showTeacherWorkGrid()
612
{
613
    $columnModel = [
614
        [
615
            'name' => 'type',
616
            'index' => 'type',
617
            'width' => '35',
618
            'align' => 'center',
619
            'sortable' => 'false',
620
        ],
621
        [
622
            'name' => 'title',
623
            'index' => 'title',
624
            'width' => '300',
625
            'align' => 'left',
626
            'wrap_cell' => 'true',
627
        ],
628
        ['name' => 'sent_date', 'index' => 'sent_date', 'width' => '125', 'align' => 'center'],
629
        ['name' => 'expires_on', 'index' => 'expires_on', 'width' => '125', 'align' => 'center'],
630
        [
631
            'name' => 'amount',
632
            'index' => 'amount',
633
            'width' => '110',
634
            'align' => 'center',
635
            'sortable' => 'false',
636
        ],
637
        [
638
            'name' => 'actions',
639
            'index' => 'actions',
640
            'width' => '110',
641
            'align' => 'left',
642
            'sortable' => 'false',
643
        ],
644
    ];
645
    $url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_work_teacher&'.api_get_cidreq();
646
    $deleteUrl = api_get_path(WEB_AJAX_PATH).'work.ajax.php?a=delete_work&'.api_get_cidreq();
647
648
    $columns = [
649
        get_lang('Type'),
650
        get_lang('Title'),
651
        get_lang('Sent date'),
652
        get_lang('Deadline'),
653
        get_lang('Number submitted'),
654
        get_lang('Detail'),
655
    ];
656
657
    $params = [
658
        'multiselect' => true,
659
        'autowidth' => 'true',
660
        'height' => 'auto',
661
    ];
662
663
    $html = '<script>
664
    $(function() {
665
        '.Display::grid_js('workList', $url, $columns, $columnModel, $params, [], null, true).'
666
        $("#workList").jqGrid(
667
            "navGrid",
668
            "#workList_pager",
669
            { edit: false, add: false, del: true },
670
            { height:280, reloadAfterSubmit:false }, // edit options
671
            { height:280, reloadAfterSubmit:false }, // add options
672
            { reloadAfterSubmit:false, url: "'.$deleteUrl.'" }, // del options
673
            { width:500 } // search options
674
        );
675
    });
676
    </script>';
677
    $html .= Display::grid_html('workList');
678
679
    return $html;
680
}
681
682
/**
683
 * Builds the form that enables the user to
684
 * move a document from one directory to another
685
 * This function has been copied from the document/document.inc.php library.
686
 *
687
 * @param array  $folders
688
 * @param string $curdirpath
689
 * @param string $move_file
690
 * @param string $group_dir
691
 *
692
 * @return string html form
693
 */
694
function build_work_move_to_selector($folders, $curdirpath, $move_file, $group_dir = '')
695
{
696
    $course_id = api_get_course_int_id();
697
    $move_file = (int) $move_file;
698
    $tbl_work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
699
    $sql = "SELECT title, url FROM $tbl_work
700
            WHERE c_id = $course_id AND id ='".$move_file."'";
701
    $result = Database::query($sql);
702
    $row = Database::fetch_array($result, 'ASSOC');
703
    $title = empty($row['title']) ? basename($row['url']) : $row['title'];
704
705
    $form = new FormValidator(
706
        'move_to_form',
707
        'post',
708
        api_get_self().'?'.api_get_cidreq().'&curdirpath='.Security::remove_XSS($curdirpath)
709
    );
710
711
    $form->addHeader(get_lang('Move the file').' - '.Security::remove_XSS($title));
712
    $form->addHidden('item_id', $move_file);
713
    $form->addHidden('action', 'move_to');
714
715
    // Group documents cannot be uploaded in the root
716
    $options = [];
717
    if ('' == $group_dir) {
718
        if (is_array($folders)) {
719
            foreach ($folders as $fid => $folder) {
720
                //you cannot move a file to:
721
                //1. current directory
722
                //2. inside the folder you want to move
723
                //3. inside a subfolder of the folder you want to move
724
                if (($curdirpath != $folder) &&
725
                    ($folder != $move_file) &&
726
                    (substr($folder, 0, strlen($move_file) + 1) != $move_file.'/')
727
                ) {
728
                    $options[$fid] = $folder;
729
                }
730
            }
731
        }
732
    } else {
733
        if ('/' != $curdirpath) {
734
            $form .= '<option value="0">/ ('.get_lang('root').')</option>';
735
        }
736
        foreach ($folders as $fid => $folder) {
737
            if (($curdirpath != $folder) && ($folder != $move_file) &&
738
                (substr($folder, 0, strlen($move_file) + 1) != $move_file.'/')
739
            ) {
740
                //cannot copy dir into his own subdir
741
                $display_folder = substr($folder, strlen($group_dir));
742
                $display_folder = '' == $display_folder ? '/ ('.get_lang('root').')' : $display_folder;
743
                //$form .= '<option value="'.$fid.'">'.$display_folder.'</option>'."\n";
744
                $options[$fid] = $display_folder;
745
            }
746
        }
747
    }
748
749
    $form->addSelect('move_to_id', get_lang('Select'), $options);
750
    $form->addButtonSend(get_lang('Move the file'), 'move_file_submit');
751
752
    return $form->returnForm();
753
}
754
755
/**
756
 * creates a new directory trying to find a directory name
757
 * that doesn't already exist.
758
 *
759
 * @author Hugues Peeters <[email protected]>
760
 * @author Bert Vanderkimpen
761
 * @author Yannick Warnier <[email protected]> Adaptation for work tool
762
 *
763
 * @param string $workDir        Base work dir (.../work)
764
 * @param string $desiredDirName complete path of the desired name
765
 *
766
 * @return string actual directory name if it succeeds, boolean false otherwise
767
 */
768
function create_unexisting_work_directory($workDir, $desiredDirName)
769
{
770
    $counter = 0;
771
    $workDir = ('/' == substr($workDir, -1, 1) ? $workDir : $workDir.'/');
772
    $checkDirName = $desiredDirName;
773
    while (file_exists($workDir.$checkDirName)) {
774
        $counter++;
775
        $checkDirName = $desiredDirName.$counter;
776
    }
777
778
    if (@mkdir($workDir.$checkDirName, api_get_permissions_for_new_directories())) {
779
        return $checkDirName;
780
    } else {
781
        return false;
782
    }
783
}
784
785
/**
786
 * Delete a work-tool directory.
787
 *
788
 * @param int $id work directory id to delete
789
 *
790
 * @return int -1 on error
791
 */
792
function deleteDirWork($id)
793
{
794
    $locked = api_resource_is_locked_by_gradebook($id, LINK_STUDENTPUBLICATION);
795
796
    if (true == $locked) {
797
        echo Display::return_message(get_lang('This option is not available because this activity is contained by an assessment, which is currently locked. To unlock the assessment, ask your platform administrator.'), 'warning');
798
799
        return false;
800
    }
801
802
    $_course = api_get_course_info();
803
    $id = (int) $id;
804
    $work_data = get_work_data_by_id($id);
805
806
    if (empty($work_data)) {
807
        return false;
808
    }
809
810
    //$base_work_dir = api_get_path(SYS_COURSE_PATH).$_course['path'].'/work';
811
    //$work_data_url = $base_work_dir.$work_data['url'];
812
    //$check = Security::check_abs_path($work_data_url.'/', $base_work_dir.'/');
813
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
814
    $TSTDPUBASG = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
815
    $t_agenda = Database::get_course_table(TABLE_AGENDA);
816
    $course_id = api_get_course_int_id();
817
    $sessionId = api_get_session_id();
818
819
    if (!empty($work_data['url'])) {
820
        if ($check) {
821
            $consideredWorkingTime = api_get_configuration_value('considered_working_time');
822
            if (!empty($consideredWorkingTime)) {
823
                $fieldValue = new ExtraFieldValue('work');
824
                $resultExtra = $fieldValue->getAllValuesForAnItem(
825
                    $work_data['id'],
826
                    true
827
                );
828
829
                $workingTime = null;
830
                foreach ($resultExtra as $field) {
831
                    $field = $field['value'];
832
                    if ($consideredWorkingTime == $field->getField()->getVariable()) {
833
                        $workingTime = $field->getValue();
834
835
                        break;
836
                    }
837
                }
838
839
                $courseUsers = CourseManager::get_user_list_from_course_code($_course['code'], $sessionId);
840
                if (!empty($workingTime)) {
841
                    foreach ($courseUsers as $user) {
842
                        $userWorks = get_work_user_list(
843
                            0,
844
                            100,
845
                            null,
846
                            null,
847
                            $work_data['id'],
848
                            null,
849
                            $user['user_id'],
850
                            false,
851
                            $course_id,
852
                            $sessionId
853
                        );
854
855
                        if (1 != count($userWorks)) {
856
                            continue;
857
                        }
858
                        Event::eventRemoveVirtualCourseTime($course_id, $user['user_id'], $sessionId, $workingTime);
859
                    }
860
                }
861
            }
862
863
            // Deleting all contents inside the folder
864
            $sql = "UPDATE $table SET active = 2
865
                    WHERE c_id = $course_id AND filetype = 'folder' AND id = $id";
866
            Database::query($sql);
867
868
            $sql = "UPDATE $table SET active = 2
869
                    WHERE c_id = $course_id AND parent_id = $id";
870
            Database::query($sql);
871
872
            $new_dir = $work_data_url.'_DELETED_'.$id;
873
874
            if ('true' == api_get_setting('permanently_remove_deleted_files')) {
875
                my_delete($work_data_url);
876
            } else {
877
                if (file_exists($work_data_url)) {
878
                    rename($work_data_url, $new_dir);
879
                }
880
            }
881
882
            // Gets calendar_id from student_publication_assigment
883
            $sql = "SELECT add_to_calendar FROM $TSTDPUBASG
884
                    WHERE c_id = $course_id AND publication_id = $id";
885
            $res = Database::query($sql);
886
            $calendar_id = Database::fetch_row($res);
887
888
            // delete from agenda if it exists
889
            if (!empty($calendar_id[0])) {
890
                $sql = "DELETE FROM $t_agenda
891
                        WHERE c_id = $course_id AND id = '".$calendar_id[0]."'";
892
                Database::query($sql);
893
            }
894
            $sql = "DELETE FROM $TSTDPUBASG
895
                    WHERE c_id = $course_id AND publication_id = $id";
896
            Database::query($sql);
897
898
            Skill::deleteSkillsFromItem($id, ITEM_TYPE_STUDENT_PUBLICATION);
899
900
            Event::addEvent(
901
                LOG_WORK_DIR_DELETE,
902
                LOG_WORK_DATA,
903
                [
904
                    'id' => $work_data['id'],
905
                    'url' => $work_data['url'],
906
                    'title' => $work_data['title'],
907
                ],
908
                null,
909
                api_get_user_id(),
910
                api_get_course_int_id(),
911
                $sessionId
912
            );
913
914
            $linkInfo = GradebookUtils::isResourceInCourseGradebook(
915
                api_get_course_id(),
916
                3,
917
                $id,
918
                api_get_session_id()
919
            );
920
            $link_id = $linkInfo['id'];
921
            if (false !== $linkInfo) {
922
                GradebookUtils::remove_resource_from_course_gradebook($link_id);
923
            }
924
925
            return true;
926
        }
927
    }
928
}
929
930
/**
931
 * Get the path of a document in the student_publication table (path relative to the course directory).
932
 *
933
 * @param int $id
934
 *
935
 * @return string Path (or -1 on error)
936
 */
937
function get_work_path($id)
938
{
939
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
940
    $course_id = api_get_course_int_id();
941
    $sql = 'SELECT url FROM '.$table.'
942
            WHERE c_id = '.$course_id.' AND id='.(int) $id;
943
    $res = Database::query($sql);
944
    if (Database::num_rows($res)) {
945
        $row = Database::fetch_array($res);
946
947
        return $row['url'];
948
    }
949
950
    return -1;
951
}
952
953
/**
954
 * Update the url of a work in the student_publication table.
955
 *
956
 * @param int    $id        of the work to update
957
 * @param string $new_path  Destination directory where the work has been moved (must end with a '/')
958
 * @param int    $parent_id
959
 *
960
 * @return mixed Int -1 on error, sql query result on success
961
 */
962
function updateWorkUrl($id, $new_path, $parent_id)
963
{
964
    if (empty($id)) {
965
        return -1;
966
    }
967
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
968
    $course_id = api_get_course_int_id();
969
    $id = (int) $id;
970
    $parent_id = (int) $parent_id;
971
972
    $sql = "SELECT * FROM $table
973
            WHERE c_id = $course_id AND id = $id";
974
    $res = Database::query($sql);
975
    if (1 != Database::num_rows($res)) {
976
        return -1;
977
    } else {
978
        $row = Database::fetch_array($res);
979
        $filename = basename($row['url']);
980
        $new_url = $new_path.$filename;
981
        $new_url = Database::escape_string($new_url);
982
983
        $sql = "UPDATE $table SET
984
                   url = '$new_url',
985
                   parent_id = '$parent_id'
986
                WHERE c_id = $course_id AND id = $id";
987
988
        return Database::query($sql);
989
    }
990
}
991
992
/**
993
 * Update the url of a dir in the student_publication table.
994
 *
995
 * @param array  $work_data work original data
996
 * @param string $newPath   Example: "folder1"
997
 *
998
 * @return bool
999
 */
1000
function updateDirName($work_data, $newPath)
1001
{
1002
    $course_id = $work_data['c_id'];
1003
    $work_id = (int) ($work_data['iid']);
1004
    $oldPath = $work_data['url'];
1005
    $originalNewPath = Database::escape_string($newPath);
1006
    $newPath = Database::escape_string($newPath);
1007
    $newPath = api_replace_dangerous_char($newPath);
1008
    $newPath = disable_dangerous_file($newPath);
1009
1010
    if ($oldPath == '/'.$newPath) {
1011
        return true;
1012
    }
1013
1014
    if (!empty($newPath)) {
1015
        $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
1016
        $sql = "UPDATE $table SET
1017
                    title = '".$originalNewPath."'
1018
                WHERE
1019
                    c_id = $course_id AND
1020
                    iid = $work_id";
1021
        Database::query($sql);
1022
    }
1023
}
1024
1025
/**
1026
 * returns all the javascript that is required for easily
1027
 * validation when you create a work
1028
 * this goes into the $htmlHeadXtra[] array.
1029
 */
1030
function to_javascript_work()
1031
{
1032
    return '<script>
1033
        function updateDocumentTitle(value) {
1034
            var temp = value.indexOf("/");
1035
            //linux path
1036
            if(temp != -1){
1037
                temp=value.split("/");
1038
            } else {
1039
                temp=value.split("\\\");
1040
            }
1041
1042
            var fullFilename = temp[temp.length - 1];
1043
            var baseFilename = fullFilename;
1044
1045
            // get file extension
1046
            var fileExtension = "";
1047
            if (fullFilename.match(/\..+/)) {
1048
                fileInfo = fullFilename.match(/(.*)\.([^.]+)$/);
1049
                if (fileInfo.length > 1) {
1050
                    fileExtension = "."+fileInfo[fileInfo.length - 1];
1051
                    baseFilename = fileInfo[fileInfo.length - 2];
1052
                }
1053
            }
1054
1055
            document.getElementById("file_upload").value = baseFilename;
1056
            document.getElementById("file_extension").value = fileExtension;
1057
            $("#contains_file_id").attr("value", 1);
1058
        }
1059
        function setFocus() {
1060
            $("#work_title").focus();
1061
        }
1062
1063
        $(function() {
1064
            setFocus();
1065
            var checked = $("#expiry_date").attr("checked");
1066
            if (checked) {
1067
                $("#option2").show();
1068
            } else {
1069
                $("#option2").hide();
1070
            }
1071
1072
            var checkedEndDate = $("#end_date").attr("checked");
1073
            if (checkedEndDate) {
1074
                $("#option3").show();
1075
                $("#ends_on").attr("checked", true);
1076
            } else {
1077
                $("#option3").hide();
1078
                $("#ends_on").attr("checked", false);
1079
            }
1080
1081
            $("#expiry_date").click(function() {
1082
                $("#option2").toggle();
1083
            });
1084
1085
            $("#end_date").click(function() {
1086
                $("#option3").toggle();
1087
            });
1088
        });
1089
    </script>';
1090
}
1091
1092
/**
1093
 * Gets the id of a student publication with a given path.
1094
 *
1095
 * @param string $path
1096
 *
1097
 * @return true if is found / false if not found
1098
 */
1099
// TODO: The name of this function does not fit with the kind of information it returns.
1100
// Maybe check_work_id() or is_work_id()?
1101
function get_work_id($path)
1102
{
1103
    $TBL_STUDENT_PUBLICATION = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
1104
    $TBL_PROP_TABLE = Database::get_course_table(TABLE_ITEM_PROPERTY);
1105
    $course_id = api_get_course_int_id();
1106
    $path = Database::escape_string($path);
1107
1108
    if (api_is_allowed_to_edit()) {
1109
        $sql = "SELECT work.id
1110
                FROM $TBL_STUDENT_PUBLICATION AS work, $TBL_PROP_TABLE AS props
1111
                WHERE
1112
                    props.c_id = $course_id AND
1113
                    work.c_id = $course_id AND
1114
                    props.tool='work' AND
1115
                    work.id=props.ref AND
1116
                    work.url LIKE 'work/".$path."%' AND
1117
                    work.filetype='file' AND
1118
                    props.visibility<>'2'";
1119
    } else {
1120
        $sql = "SELECT work.id
1121
                FROM $TBL_STUDENT_PUBLICATION AS work, $TBL_PROP_TABLE AS props
1122
                WHERE
1123
                    props.c_id = $course_id AND
1124
                    work.c_id = $course_id AND
1125
                    props.tool='work' AND
1126
                    work.id=props.ref AND
1127
                    work.url LIKE 'work/".$path."%' AND
1128
                    work.filetype='file' AND
1129
                    props.visibility<>'2' AND
1130
                    props.lastedit_user_id = '".api_get_user_id()."'";
1131
    }
1132
    $result = Database::query($sql);
1133
    $num_rows = Database::num_rows($result);
1134
1135
    if ($result && $num_rows > 0) {
1136
        return true;
1137
    } else {
1138
        return false;
1139
    }
1140
}
1141
1142
/**
1143
 * @param int $work_id
1144
 * @param int $onlyMeUserId show only my works
1145
 * @param int $notMeUserId  show works from everyone except me
1146
 *
1147
 * @return int
1148
 */
1149
function get_count_work($work_id, $onlyMeUserId = null, $notMeUserId = null)
1150
{
1151
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
1152
    $user_table = Database::get_main_table(TABLE_MAIN_USER);
1153
1154
    $is_allowed_to_edit = api_is_allowed_to_edit(null, true) || api_is_coach();
1155
    $session_id = api_get_session_id();
1156
    $condition_session = api_get_session_condition(
1157
        $session_id,
1158
        true,
1159
        false,
1160
        'work.session_id'
1161
    );
1162
1163
    $group_id = api_get_group_id();
1164
    $course_info = api_get_course_info();
1165
    $course_id = $course_info['real_id'];
1166
    $work_id = (int) $work_id;
1167
1168
    $groupIid = 0;
1169
    if ($group_id) {
1170
        $groupInfo = GroupManager::get_group_properties($group_id);
1171
        if ($groupInfo && isset($groupInfo['iid'])) {
1172
            $groupIid = (int) $groupInfo['iid'];
1173
        }
1174
    }
1175
1176
    if (!empty($group_id)) {
1177
        // set to select only messages posted by the user's group
1178
        $extra_conditions = " work.post_group_id = '".$groupIid."' ";
1179
    } else {
1180
        $extra_conditions = " (work.post_group_id = '0' or work.post_group_id IS NULL) ";
1181
    }
1182
1183
    if ($is_allowed_to_edit) {
1184
        $extra_conditions .= ' AND work.active IN (0, 1) ';
1185
    } else {
1186
        $extra_conditions .= ' AND work.active IN (0, 1) AND accepted = 1';
1187
        if (isset($course_info['show_score']) && 1 == $course_info['show_score']) {
1188
            $extra_conditions .= ' AND work.user_id = '.api_get_user_id().' ';
1189
        } else {
1190
            $extra_conditions .= '';
1191
        }
1192
    }
1193
1194
    $extra_conditions .= ' AND work.parent_id  = '.$work_id.'  ';
1195
    $where_condition = null;
1196
    if (!empty($notMeUserId)) {
1197
        $where_condition .= ' AND u.id <> '.(int) $notMeUserId;
1198
    }
1199
1200
    if (!empty($onlyMeUserId)) {
1201
        $where_condition .= ' AND u.id =  '.(int) $onlyMeUserId;
1202
    }
1203
1204
    $repo = Container::getStudentPublicationRepository();
1205
    $typeId = $repo->getResourceType()->getId();
1206
    $visibility = ResourceLink::VISIBILITY_PUBLISHED;
1207
1208
    $sql = "SELECT count(*) as count
1209
            FROM resource_node node
1210
            INNER JOIN resource_link link
1211
            ON (link.resource_node_id = node.id)
1212
            INNER JOIN $work_table work
1213
            ON (node.id = work.resource_node_id)
1214
            INNER JOIN $user_table u
1215
            ON (work.user_id = u.id)
1216
            WHERE
1217
                link.c_id = $course_id AND
1218
                resource_type_id = $typeId AND
1219
                link.visibility = $visibility AND
1220
            $extra_conditions $where_condition $condition_session";
1221
1222
    $result = Database::query($sql);
1223
1224
    $users_with_work = 0;
1225
    if (Database::num_rows($result)) {
1226
        $result = Database::fetch_array($result);
1227
        $users_with_work = $result['count'];
1228
    }
1229
1230
    return $users_with_work;
1231
}
1232
1233
/**
1234
 * @param int    $start
1235
 * @param int    $limit
1236
 * @param string $column
1237
 * @param string $direction
1238
 * @param string $where_condition
1239
 * @param bool   $getCount
1240
 *
1241
 * @return array
1242
 */
1243
function getWorkListStudent(
1244
    $start,
1245
    $limit,
1246
    $column,
1247
    $direction,
1248
    $where_condition,
1249
    $getCount = false
1250
) {
1251
    $workTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
1252
    $workTableAssignment = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
1253
    $courseInfo = api_get_course_info();
1254
    $course_id = $courseInfo['real_id'];
1255
    $session_id = api_get_session_id();
1256
    $condition_session = api_get_session_condition($session_id);
1257
    $group_id = api_get_group_id();
1258
    $userId = api_get_user_id();
1259
1260
    $isDrhOfCourse = CourseManager::isUserSubscribedInCourseAsDrh(
1261
        $userId,
1262
        $courseInfo
1263
    );
1264
1265
    if (!in_array($direction, ['asc', 'desc'])) {
1266
        $direction = 'desc';
1267
    }
1268
    if (!empty($where_condition)) {
1269
        $where_condition = ' AND '.$where_condition;
1270
    }
1271
1272
    $column = !empty($column) ? Database::escape_string($column) : 'sent_date';
1273
    $start = (int) $start;
1274
    $limit = (int) $limit;
1275
1276
    $groupIid = 0;
1277
    if ($group_id) {
1278
        $groupInfo = GroupManager::get_group_properties($group_id);
1279
        if ($groupInfo) {
1280
            $groupIid = (int) $groupInfo['iid'];
1281
        }
1282
    }
1283
1284
    if (!empty($groupIid)) {
1285
        $group_query = " WHERE w.c_id = $course_id AND post_group_id = $groupIid";
1286
        $subdirs_query = 'AND w.parent_id = 0';
1287
    } else {
1288
        $group_query = " WHERE w.c_id = $course_id AND (post_group_id = '0' or post_group_id is NULL)  ";
1289
        $subdirs_query = 'AND w.parent_id = 0';
1290
    }
1291
1292
    $active_condition = ' AND active IN (1, 0)';
1293
1294
    if ($getCount) {
1295
        $select = 'SELECT count(w.id) as count ';
1296
    } else {
1297
        $select = 'SELECT w.*, a.expires_on, expires_on, ends_on, enable_qualification ';
1298
    }
1299
1300
    $sql = "$select
1301
            FROM $workTable w
1302
            LEFT JOIN $workTableAssignment a
1303
            ON (a.publication_id = w.id AND a.c_id = w.c_id)
1304
                $group_query
1305
                $subdirs_query
1306
                $active_condition
1307
                $condition_session
1308
                $where_condition
1309
            ";
1310
1311
    $sql .= " ORDER BY $column $direction ";
1312
1313
    if (!empty($start) && !empty($limit)) {
1314
        $sql .= " LIMIT $start, $limit";
1315
    }
1316
1317
    $result = Database::query($sql);
1318
1319
    if ($getCount) {
1320
        $row = Database::fetch_array($result);
1321
1322
        return $row['count'];
1323
    }
1324
1325
    $works = [];
1326
    $url = api_get_path(WEB_CODE_PATH).'work/work_list.php?'.api_get_cidreq();
1327
    if ($isDrhOfCourse) {
1328
        $url = api_get_path(WEB_CODE_PATH).'work/work_list_all.php?'.api_get_cidreq();
1329
    }
1330
1331
    $urlOthers = api_get_path(WEB_CODE_PATH).'work/work_list_others.php?'.api_get_cidreq().'&id=';
1332
    while ($work = Database::fetch_array($result, 'ASSOC')) {
1333
        $isSubscribed = userIsSubscribedToWork($userId, $work['id'], $course_id);
1334
        if (false == $isSubscribed) {
1335
            continue;
1336
        }
1337
1338
        /*$visibility = api_get_item_visibility($courseInfo, 'work', $work['id'], $session_id);
1339
        if ($visibility != 1) {
1340
            continue;
1341
        }*/
1342
1343
        $work['type'] = Display::return_icon('work.png');
1344
        $work['expires_on'] = empty($work['expires_on']) ? null : api_get_local_time($work['expires_on']);
1345
1346
        if (empty($work['title'])) {
1347
            $work['title'] = basename($work['url']);
1348
        }
1349
1350
        $whereCondition = " AND u.id = $userId ";
1351
1352
        $workList = get_work_user_list(
1353
            0,
1354
            1000,
1355
            null,
1356
            null,
1357
            $work['id'],
1358
            $whereCondition
1359
        );
1360
1361
        $count = getTotalWorkComment($workList, $courseInfo);
1362
        $lastWork = getLastWorkStudentFromParentByUser($userId, $work, $courseInfo);
1363
1364
        if (null !== $count && !empty($count)) {
1365
            $urlView = api_get_path(WEB_CODE_PATH).'work/view.php?id='.$lastWork['id'].'&'.api_get_cidreq();
1366
1367
            $feedback = '&nbsp;'.Display::url(
1368
                Display::returnFontAwesomeIcon('comments-o'),
1369
                $urlView,
1370
                ['title' => get_lang('View')]
1371
            );
1372
1373
            $work['feedback'] = ' '.Display::label($count.' '.get_lang('Feedback'), 'info').$feedback;
1374
        }
1375
1376
        if (!empty($lastWork)) {
1377
            $work['last_upload'] = !empty($lastWork['qualification']) ? $lastWork['qualification_rounded'].' - ' : '';
1378
            $work['last_upload'] .= api_get_local_time($lastWork['sent_date']);
1379
        }
1380
1381
        $work['title'] = Display::url($work['title'], $url.'&id='.$work['id']);
1382
        $work['others'] = Display::url(
1383
            Display::return_icon('group.png', get_lang('Others')),
1384
            $urlOthers.$work['id']
1385
        );
1386
        $works[] = $work;
1387
    }
1388
1389
    return $works;
1390
}
1391
1392
/**
1393
 * @param int    $start
1394
 * @param int    $limit
1395
 * @param string $column
1396
 * @param string $direction
1397
 * @param string $where_condition
1398
 * @param bool   $getCount
1399
 * @param int    $withResults
1400
 *
1401
 * @return array
1402
 */
1403
function getAllWorkListStudent(
1404
    $start,
1405
    $limit,
1406
    $column,
1407
    $direction,
1408
    $where_condition,
1409
    $getCount = false,
1410
    $withResults = 1
1411
) {
1412
    $workTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
1413
    $workTableAssignment = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
1414
    $userId = api_get_user_id();
1415
1416
    if (empty($userId)) {
1417
        return [];
1418
    }
1419
1420
    $courses = CourseManager::get_courses_list_by_user_id($userId, true);
1421
1422
    if (!empty($where_condition)) {
1423
        $where_condition = ' AND '.$where_condition;
1424
    }
1425
1426
    if (!in_array($direction, ['asc', 'desc'])) {
1427
        $direction = 'desc';
1428
    }
1429
1430
    $column = !empty($column) ? Database::escape_string($column) : 'sent_date';
1431
    $start = (int) $start;
1432
    $limit = (int) $limit;
1433
    $courseQuery = [];
1434
    $courseList = [];
1435
    foreach ($courses as $course) {
1436
        $course_id = $course['real_id'];
1437
        $courseInfo = api_get_course_info_by_id($course_id);
1438
        $session_id = isset($course['session_id']) ? $course['session_id'] : 0;
1439
        $conditionSession = api_get_session_condition($session_id, true, false, 'w.session_id');
1440
        $parentCondition = '';
1441
        if ($withResults) {
1442
            $parentCondition = 'AND ww.parent_id is NOT NULL';
1443
        }
1444
        $courseQuery[] = " (w.c_id = $course_id $conditionSession $parentCondition )";
1445
        $courseList[$course_id] = $courseInfo;
1446
    }
1447
1448
    $courseQueryToString = implode(' OR ', $courseQuery);
1449
1450
    if ($getCount) {
1451
        if (empty($courseQuery)) {
1452
            return 0;
1453
        }
1454
        $select = 'SELECT count(DISTINCT(w.id)) as count ';
1455
    } else {
1456
        if (empty($courseQuery)) {
1457
            return [];
1458
        }
1459
        $select = 'SELECT DISTINCT
1460
                        w.url,
1461
                        w.id,
1462
                        w.c_id,
1463
                        w.session_id,
1464
                        a.expires_on,
1465
                        a.ends_on,
1466
                        a.enable_qualification,
1467
                        w.qualification,
1468
                        a.publication_id';
1469
    }
1470
1471
    $checkSentWork = " LEFT JOIN $workTable ww
1472
                       ON (ww.c_id = w.c_id AND ww.parent_id = w.id AND ww.user_id = $userId ) ";
1473
    $where = ' AND ww.url IS NULL ';
1474
    $expirationCondition = " AND (a.expires_on IS NULL OR a.expires_on > '".api_get_utc_datetime()."') ";
1475
    if ($withResults) {
1476
        $where = '';
1477
        $checkSentWork = " LEFT JOIN $workTable ww
1478
                           ON (
1479
                            ww.c_id = w.c_id AND
1480
                            ww.parent_id = w.id AND
1481
                            ww.user_id = $userId AND
1482
                            a.expires_on IS NULL AND
1483
                            ww.parent_id is NOT NULL
1484
                        ) ";
1485
        $expirationCondition = " OR (
1486
                ww.parent_id is NULL AND
1487
                a.expires_on IS NOT NULL AND
1488
                a.expires_on < '".api_get_utc_datetime()."'
1489
            ) ";
1490
    }
1491
1492
    $sql = "$select
1493
            FROM $workTable w
1494
            LEFT JOIN $workTableAssignment a
1495
            ON (a.publication_id = w.id AND a.c_id = w.c_id)
1496
            $checkSentWork
1497
            WHERE
1498
                w.parent_id = 0 AND
1499
                w.active IN (1, 0) AND
1500
                ($courseQueryToString)
1501
                $where_condition
1502
                $expirationCondition
1503
                $where
1504
            ";
1505
1506
    $sql .= " ORDER BY $column $direction ";
1507
1508
    if (!empty($start) && !empty($limit)) {
1509
        $sql .= " LIMIT $start, $limit";
1510
    }
1511
1512
    $result = Database::query($sql);
1513
1514
    if ($getCount) {
1515
        $row = Database::fetch_array($result);
1516
1517
        if ($row) {
1518
            return (int) $row['count'];
1519
        }
1520
1521
        return 0;
1522
    }
1523
1524
    $works = [];
1525
    while ($work = Database::fetch_array($result, 'ASSOC')) {
1526
        $courseId = $work['c_id'];
1527
        $courseInfo = $courseList[$work['c_id']];
1528
        $courseCode = $courseInfo['code'];
1529
        $sessionId = $work['session_id'];
1530
1531
        $cidReq = api_get_cidreq_params($courseCode, $sessionId);
1532
        $url = api_get_path(WEB_CODE_PATH).'work/work_list.php?'.$cidReq;
1533
        $isSubscribed = userIsSubscribedToWork($userId, $work['id'], $courseId);
1534
        if ($isSubscribed == false) {
1535
            continue;
1536
        }
1537
1538
        $visibility = api_get_item_visibility($courseInfo, 'work', $work['id'], $sessionId);
1539
1540
        if ($visibility != 1) {
1541
            continue;
1542
        }
1543
1544
        $work['type'] = Display::return_icon('work.png');
1545
        $work['expires_on'] = empty($work['expires_on']) ? null : api_get_local_time($work['expires_on']);
1546
1547
        if (empty($work['title'])) {
1548
            $work['title'] = basename($work['url']);
1549
        }
1550
1551
        if ($withResults) {
1552
            $whereCondition = " AND u.user_id = $userId ";
1553
            $workList = get_work_user_list(
1554
                0,
1555
                1000,
1556
                null,
1557
                null,
1558
                $work['id'],
1559
                $whereCondition,
1560
                null,
1561
                false,
1562
                $courseId,
1563
                $sessionId
1564
            );
1565
1566
            $count = getTotalWorkComment($workList, $courseInfo);
1567
            $lastWork = getLastWorkStudentFromParentByUser($userId, $work, $courseInfo);
1568
1569
            if (!is_null($count) && !empty($count)) {
1570
                $urlView = api_get_path(WEB_CODE_PATH).'work/view.php?id='.$lastWork['id'].'&'.$cidReq;
1571
1572
                $feedback = '&nbsp;'.Display::url(
1573
                        Display::returnFontAwesomeIcon('comments-o'),
1574
                        $urlView,
1575
                        ['title' => get_lang('View')]
1576
                    );
1577
1578
                $work['feedback'] = ' '.Display::label($count.' '.get_lang('Feedback'), 'info').$feedback;
1579
            }
1580
1581
            if (!empty($lastWork)) {
1582
                $work['last_upload'] = (!empty($lastWork['qualification'])) ? $lastWork['qualification_rounded'].' - ' : '';
1583
                $work['last_upload'] .= api_get_local_time($lastWork['sent_date']);
1584
            }
1585
        }
1586
1587
        $work['title'] = Display::url($work['title'], $url.'&id='.$work['id']);
1588
        $works[] = $work;
1589
    }
1590
1591
    return $works;
1592
}
1593
1594
/**
1595
 * @param int    $start
1596
 * @param int    $limit
1597
 * @param string $column
1598
 * @param string $direction
1599
 * @param string $where_condition
1600
 * @param bool   $getCount
1601
 *
1602
 * @return array
1603
 */
1604
function getWorkListTeacher(
1605
    $start,
1606
    $limit,
1607
    $column,
1608
    $direction,
1609
    $where_condition,
1610
    $getCount = false
1611
) {
1612
    $workTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
1613
    $workTableAssignment = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
1614
1615
    $courseInfo = api_get_course_info();
1616
    $course_id = api_get_course_int_id();
1617
    $session_id = api_get_session_id();
1618
    $condition_session = api_get_session_condition($session_id);
1619
    $group_id = api_get_group_id();
1620
    $groupIid = 0;
1621
    if ($group_id) {
1622
        $groupInfo = GroupManager::get_group_properties($group_id);
1623
        $groupIid = $groupInfo['iid'];
1624
    }
1625
    $groupIid = (int) $groupIid;
1626
1627
    $is_allowed_to_edit = api_is_allowed_to_edit() || api_is_coach();
1628
    if (!in_array($direction, ['asc', 'desc'])) {
1629
        $direction = 'desc';
1630
    }
1631
    if (!empty($where_condition)) {
1632
        $where_condition = ' AND '.$where_condition;
1633
    }
1634
1635
    $column = !empty($column) ? Database::escape_string($column) : 'sent_date';
1636
    $start = (int) $start;
1637
    $limit = (int) $limit;
1638
    $works = [];
1639
1640
    // Get list from database
1641
    if ($is_allowed_to_edit) {
1642
        $active_condition = ' active IN (0, 1)';
1643
        if ($getCount) {
1644
            $select = ' SELECT count(w.id) as count';
1645
        } else {
1646
            $select = ' SELECT w.*, a.expires_on, expires_on, ends_on, enable_qualification ';
1647
        }
1648
        $sql = " $select
1649
                FROM $workTable w
1650
                LEFT JOIN $workTableAssignment a
1651
                ON (a.publication_id = w.id AND a.c_id = w.c_id)
1652
                WHERE
1653
                    w.c_id = $course_id
1654
                    $condition_session AND
1655
                    $active_condition AND
1656
                    parent_id = 0 AND
1657
                    post_group_id = $groupIid
1658
                    $where_condition
1659
                ORDER BY $column $direction
1660
                LIMIT $start, $limit";
1661
1662
        $result = Database::query($sql);
1663
1664
        if ($getCount) {
1665
            $row = Database::fetch_array($result);
1666
1667
            return (int) $row['count'];
1668
        }
1669
1670
        $url = api_get_path(WEB_CODE_PATH).'work/work_list_all.php?'.api_get_cidreq();
1671
        $blockEdition = api_get_configuration_value('block_student_publication_edition');
1672
        $repo = Container::getStudentPublicationRepository();
1673
        $courseEntity = api_get_course_entity($course_id);
1674
        $sessionEntity = api_get_session_entity($session_id);
1675
1676
        while ($work = Database::fetch_array($result, 'ASSOC')) {
1677
            /** @var CStudentPublication $studentPublication */
1678
            $studentPublication = $repo->find($work['iid']);
1679
            $workId = $studentPublication->getIid();
1680
1681
            $work['type'] = Display::return_icon('work.png');
1682
            $work['expires_on'] = empty($work['expires_on']) ? null : api_get_local_time($work['expires_on']);
1683
1684
            $countUniqueAttempts = getUniqueStudentAttemptsTotal(
1685
                $workId,
1686
                $group_id,
1687
                $course_id,
1688
                $session_id
1689
            );
1690
1691
            $totalUsers = getStudentSubscribedToWork(
1692
                $workId,
1693
                $course_id,
1694
                $group_id,
1695
                $session_id,
1696
                true
1697
            );
1698
1699
            $work['amount'] = Display::label(
1700
                $countUniqueAttempts.'/'.
1701
                $totalUsers,
1702
                'success'
1703
            );
1704
1705
            //$visibility = api_get_item_visibility($courseInfo, 'work', $workId, $session_id);
1706
            $isVisible = $studentPublication->isVisible($courseEntity, $sessionEntity);
1707
            if ($isVisible) {
1708
                $icon = 'visible.png';
1709
                $text = get_lang('Visible');
1710
                $action = 'invisible';
1711
                $class = '';
1712
            } else {
1713
                $icon = 'invisible.png';
1714
                $text = get_lang('invisible');
1715
                $action = 'visible';
1716
                $class = 'muted';
1717
            }
1718
1719
            $visibilityLink = Display::url(
1720
                Display::return_icon($icon, $text, [], ICON_SIZE_SMALL),
1721
                api_get_path(WEB_CODE_PATH).'work/work.php?id='.$workId.'&action='.$action.'&'.api_get_cidreq()
1722
            );
1723
1724
            if (empty($work['title'])) {
1725
                $work['title'] = basename($work['url']);
1726
            }
1727
            $work['title'] = Display::url($work['title'], $url.'&id='.$workId, ['class' => $class]);
1728
            $work['title'] .= ' '.Display::label(get_count_work($work['id']), 'success');
1729
            $work['sent_date'] = api_get_local_time($work['sent_date']);
1730
1731
            if ($blockEdition && !api_is_platform_admin()) {
1732
                $editLink = '';
1733
            } else {
1734
                $editLink = Display::url(
1735
                    Display::return_icon('edit.png', get_lang('Edit'), [], ICON_SIZE_SMALL),
1736
                    api_get_path(WEB_CODE_PATH).'work/edit_work.php?id='.$workId.'&'.api_get_cidreq()
1737
                );
1738
            }
1739
1740
            $correctionLink = '&nbsp;'.Display::url(
1741
                Display::return_icon('upload_package.png', get_lang('Upload corrections'), '', ICON_SIZE_SMALL),
1742
                api_get_path(WEB_CODE_PATH).'work/upload_corrections.php?'.api_get_cidreq().'&id='.$workId
1743
            ).'&nbsp;';
1744
1745
            if ($countUniqueAttempts > 0) {
1746
                $downloadLink = Display::url(
1747
                    Display::return_icon(
1748
                        'save_pack.png',
1749
                        get_lang('Save'),
1750
                        [],
1751
                        ICON_SIZE_SMALL
1752
                    ),
1753
                    api_get_path(WEB_CODE_PATH).'work/downloadfolder.inc.php?id='.$workId.'&'.api_get_cidreq()
1754
                );
1755
            } else {
1756
                $downloadLink = Display::url(
1757
                    Display::return_icon(
1758
                        'save_pack_na.png',
1759
                        get_lang('Save'),
1760
                        [],
1761
                        ICON_SIZE_SMALL
1762
                    ),
1763
                    '#'
1764
                );
1765
            }
1766
            if (!api_is_allowed_to_edit()) {
1767
                $editLink = null;
1768
            }
1769
            $work['actions'] = $visibilityLink.$correctionLink.$downloadLink.$editLink;
1770
            $works[] = $work;
1771
        }
1772
    }
1773
1774
    return $works;
1775
}
1776
1777
/**
1778
 * @param int    $start
1779
 * @param int    $limit
1780
 * @param string $column
1781
 * @param string $direction
1782
 * @param int    $workId
1783
 * @param int    $studentId
1784
 * @param string $whereCondition
1785
 * @param bool   $getCount
1786
 *
1787
 * @return array
1788
 */
1789
function get_work_user_list_from_documents(
1790
    $start,
1791
    $limit,
1792
    $column,
1793
    $direction,
1794
    $workId,
1795
    $studentId = null,
1796
    $whereCondition = '',
1797
    $getCount = false
1798
) {
1799
    if ($getCount) {
1800
        $select1 = ' SELECT count(u.id) as count ';
1801
        $select2 = ' SELECT count(u.id) as count ';
1802
    } else {
1803
        $select1 = ' SELECT DISTINCT
1804
                        u.firstname,
1805
                        u.lastname,
1806
                        u.id as user_id,
1807
                        w.title,
1808
                        w.parent_id,
1809
                        w.document_id document_id,
1810
                        w.id, qualification,
1811
                        qualificator_id,
1812
                        w.sent_date,
1813
                        w.contains_file,
1814
                        w.url
1815
                    ';
1816
        $select2 = ' SELECT DISTINCT
1817
                        u.firstname, u.lastname,
1818
                        u.id as user_id,
1819
                        d.title,
1820
                        w.parent_id,
1821
                        d.id document_id,
1822
                        0,
1823
                        0,
1824
                        0,
1825
                        w.sent_date,
1826
                        w.contains_file,
1827
                        w.url
1828
                    ';
1829
    }
1830
1831
    $documentTable = Database::get_course_table(TABLE_DOCUMENT);
1832
    $workTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
1833
    $workRelDocument = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
1834
    $userTable = Database::get_main_table(TABLE_MAIN_USER);
1835
1836
    $courseId = api_get_course_int_id();
1837
    $sessionId = api_get_session_id();
1838
1839
    if (empty($studentId)) {
1840
        $studentId = api_get_user_id();
1841
    }
1842
1843
    $studentId = (int) $studentId;
1844
    $workId = (int) $workId;
1845
1846
    $userCondition = " AND u.id = $studentId ";
1847
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'w.session_id');
1848
    $workCondition = " AND w_rel.work_id = $workId";
1849
    $workParentCondition = " AND w.parent_id = $workId";
1850
1851
    $sql = "(
1852
                $select1 FROM $userTable u
1853
                INNER JOIN $workTable w
1854
                ON (u.id = w.user_id AND w.active IN (0, 1) AND w.filetype = 'file')
1855
                WHERE
1856
                    w.c_id = $courseId
1857
                    $userCondition
1858
                    $sessionCondition
1859
                    $whereCondition
1860
                    $workParentCondition
1861
            ) UNION (
1862
                $select2 FROM $workTable w
1863
                INNER JOIN $workRelDocument w_rel
1864
                ON (w_rel.work_id = w.id AND w.active IN (0, 1) AND w_rel.c_id = w.c_id)
1865
                INNER JOIN $documentTable d
1866
                ON (w_rel.document_id = d.id AND d.c_id = w.c_id)
1867
                INNER JOIN $userTable u ON (u.id = $studentId)
1868
                WHERE
1869
                    w.c_id = $courseId
1870
                    $workCondition
1871
                    $sessionCondition AND
1872
                    d.id NOT IN (
1873
                        SELECT w.document_id id
1874
                        FROM $workTable w
1875
                        WHERE
1876
                            user_id = $studentId AND
1877
                            c_id = $courseId AND
1878
                            filetype = 'file' AND
1879
                            active IN (0, 1)
1880
                            $sessionCondition
1881
                            $workParentCondition
1882
                    )
1883
            )";
1884
1885
    $start = (int) $start;
1886
    $limit = (int) $limit;
1887
1888
    $direction = in_array(strtolower($direction), ['desc', 'asc']) ? $direction : 'desc';
1889
    $column = Database::escape_string($column);
1890
1891
    if ($getCount) {
1892
        $result = Database::query($sql);
1893
        $result = Database::fetch_array($result);
1894
1895
        return $result['count'];
1896
    }
1897
1898
    $sql .= " ORDER BY $column $direction";
1899
    $sql .= " LIMIT $start, $limit";
1900
1901
    $result = Database::query($sql);
1902
1903
    $currentUserId = api_get_user_id();
1904
    $work_data = get_work_data_by_id($workId);
1905
    $qualificationExists = false;
1906
1907
    if (!empty($work_data['qualification']) && (int) ($work_data['qualification']) > 0) {
1908
        $qualificationExists = true;
1909
    }
1910
1911
    $urlAdd = api_get_path(WEB_CODE_PATH).'work/upload_from_template.php?'.api_get_cidreq();
1912
    $urlEdit = api_get_path(WEB_CODE_PATH).'work/edit.php?'.api_get_cidreq();
1913
    $urlDelete = api_get_path(WEB_CODE_PATH).'work/work_list.php?action=delete&'.api_get_cidreq();
1914
    $urlView = api_get_path(WEB_CODE_PATH).'work/view.php?'.api_get_cidreq();
1915
    $urlDownload = api_get_path(WEB_CODE_PATH).'work/download.php?'.api_get_cidreq();
1916
1917
    $editIcon = Display::return_icon('edit.png', get_lang('Edit'));
1918
    $addIcon = Display::return_icon('add.png', get_lang('Add'));
1919
    $deleteIcon = Display::return_icon('delete.png', get_lang('Delete'));
1920
    $viewIcon = Display::return_icon('default.png', get_lang('View'));
1921
    $saveIcon = Display::return_icon(
1922
        'save.png',
1923
        get_lang('Save'),
1924
        [],
1925
        ICON_SIZE_SMALL
1926
    );
1927
    $allowEdition = 1 == api_get_course_setting('student_delete_own_publication');
1928
1929
    $workList = [];
1930
    while ($row = Database::fetch_array($result, 'ASSOC')) {
1931
        $userId = $row['user_id'];
1932
        $documentId = $row['document_id'];
1933
        $itemId = $row['id'];
1934
        $addLinkShowed = false;
1935
1936
        if (empty($documentId)) {
1937
            $url = $urlEdit.'&item_id='.$row['id'].'&id='.$workId;
1938
            $editLink = Display::url($editIcon, $url);
1939
            if (1 != $allowEdition) {
1940
                $editLink = null;
1941
            }
1942
        } else {
1943
            $documentToWork = getDocumentToWorkPerUser($documentId, $workId, $courseId, $sessionId, $userId);
1944
1945
            if (empty($documentToWork)) {
1946
                $url = $urlAdd.'&document_id='.$documentId.'&id='.$workId;
1947
                $editLink = Display::url($addIcon, $url);
1948
                $addLinkShowed = true;
1949
            } else {
1950
                $row['title'] = $documentToWork['title'];
1951
                $row['sent_date'] = $documentToWork['sent_date'];
1952
                $newWorkId = $documentToWork['id'];
1953
                $url = $urlEdit.'&item_id='.$newWorkId.'&id='.$workId;
1954
                $editLink = Display::url($editIcon, $url);
1955
1956
                if (1 != $allowEdition) {
1957
                    $editLink = '';
1958
                }
1959
            }
1960
        }
1961
1962
        $downloadLink = '';
1963
        // If URL is present then there's a file to download keep BC.
1964
        if ($row['contains_file'] || !empty($row['url'])) {
1965
            $downloadLink = Display::url($saveIcon, $urlDownload.'&id='.$row['id']).'&nbsp;';
1966
        }
1967
1968
        $viewLink = '';
1969
        if (!empty($itemId)) {
1970
            $viewLink = Display::url($viewIcon, $urlView.'&id='.$itemId);
1971
        }
1972
1973
        $deleteLink = '';
1974
        if (1 == $allowEdition && !empty($itemId)) {
1975
            $deleteLink = Display::url($deleteIcon, $urlDelete.'&item_id='.$itemId.'&id='.$workId);
1976
        }
1977
1978
        $row['type'] = null;
1979
1980
        if ($qualificationExists) {
1981
            if (empty($row['qualificator_id'])) {
1982
                $status = Display::label(get_lang('Not reviewed'), 'warning');
1983
            } else {
1984
                $status = Display::label(get_lang('Revised'), 'success');
1985
            }
1986
            $row['qualificator_id'] = $status;
1987
        }
1988
1989
        if (!empty($row['qualification'])) {
1990
            $row['qualification'] = Display::label($row['qualification'], 'info');
1991
        }
1992
1993
        if (!empty($row['sent_date'])) {
1994
            $row['sent_date'] = Display::dateToStringAgoAndLongDate($row['sent_date']);
1995
        }
1996
1997
        if ($userId == $currentUserId) {
1998
            $row['actions'] = $downloadLink.$viewLink.$editLink.$deleteLink;
1999
        }
2000
2001
        if ($addLinkShowed) {
2002
            $row['qualification'] = '';
2003
            $row['qualificator_id'] = '';
2004
        }
2005
2006
        $workList[] = $row;
2007
    }
2008
2009
    return $workList;
2010
}
2011
2012
/**
2013
 * @param int    $start
2014
 * @param int    $limit
2015
 * @param int    $column
2016
 * @param string $direction
2017
 * @param int    $work_id
2018
 * @param string $whereCondition
2019
 * @param int    $studentId
2020
 * @param bool   $getCount
2021
 * @param int    $courseId
2022
 * @param int    $sessionId
2023
 *
2024
 * @return array
2025
 */
2026
function get_work_user_list(
2027
    $start,
2028
    $limit,
2029
    $column,
2030
    $direction,
2031
    $work_id,
2032
    $whereCondition = '',
2033
    $studentId = null,
2034
    $getCount = false,
2035
    $courseId = 0,
2036
    $sessionId = 0
2037
) {
2038
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
2039
    $user_table = Database::get_main_table(TABLE_MAIN_USER);
2040
2041
    $session_id = $sessionId ? (int) $sessionId : api_get_session_id();
2042
    $group_id = api_get_group_id();
2043
    $course_info = api_get_course_info();
2044
    $course_info = empty($course_info) ? api_get_course_info_by_id($courseId) : $course_info;
2045
    $course_id = isset($course_info['real_id']) ? $course_info['real_id'] : $courseId;
2046
2047
    $work_id = (int) $work_id;
2048
    $start = (int) $start;
2049
    $limit = (int) $limit;
2050
2051
    $column = !empty($column) ? Database::escape_string($column) : 'sent_date';
2052
    $compilation = null;
2053
    if (api_get_configuration_value('allow_compilatio_tool')) {
2054
        $compilation = new Compilatio();
2055
    }
2056
2057
    if (!in_array($direction, ['asc', 'desc'])) {
2058
        $direction = 'desc';
2059
    }
2060
2061
    $work_data = get_work_data_by_id($work_id, $courseId, $sessionId);
2062
    $is_allowed_to_edit = api_is_allowed_to_edit() || api_is_coach();
2063
    $condition_session = api_get_session_condition(
2064
        $session_id,
2065
        true,
2066
        false,
2067
        'work.session_id'
2068
    );
2069
2070
    $locked = api_resource_is_locked_by_gradebook(
2071
        $work_id,
2072
        LINK_STUDENTPUBLICATION,
2073
        $course_info['code']
2074
    );
2075
2076
    $isDrhOfCourse = CourseManager::isUserSubscribedInCourseAsDrh(
2077
        api_get_user_id(),
2078
        $course_info
2079
    );
2080
2081
    $isDrhOfSession = !empty(SessionManager::getSessionFollowedByDrh(api_get_user_id(), $session_id));
2082
2083
    $groupIid = 0;
2084
    if ($group_id) {
2085
        $groupInfo = GroupManager::get_group_properties($group_id);
2086
        if ($groupInfo) {
2087
            $groupIid = $groupInfo['iid'];
2088
        }
2089
    }
2090
2091
    if (!empty($work_data)) {
2092
        if (!empty($group_id)) {
2093
            // set to select only messages posted by the user's group
2094
            $extra_conditions = " work.post_group_id = '".$groupIid."' ";
2095
        } else {
2096
            $extra_conditions = " (work.post_group_id = '0' OR work.post_group_id is NULL) ";
2097
        }
2098
2099
        if ($is_allowed_to_edit || $isDrhOfCourse || $isDrhOfSession) {
2100
            $extra_conditions .= ' AND work.active IN (0, 1) ';
2101
        } else {
2102
            if (isset($course_info['show_score']) &&
2103
                1 == $course_info['show_score']
2104
            ) {
2105
                $extra_conditions .= ' AND (u.id = '.api_get_user_id().' AND work.active IN (0, 1)) ';
2106
            } else {
2107
                $extra_conditions .= ' AND work.active IN (0, 1) ';
2108
            }
2109
        }
2110
2111
        $extra_conditions .= " AND parent_id  = $work_id ";
2112
2113
        $select = 'SELECT DISTINCT
2114
                        u.id as user_id,
2115
                        work.iid as id,
2116
                        title as title,
2117
                        description,
2118
                        url,
2119
                        sent_date,
2120
                        contains_file,
2121
                        has_properties,
2122
                        view_properties,
2123
                        qualification,
2124
                        weight,
2125
                        allow_text_assignment,
2126
                        u.firstname,
2127
                        u.lastname,
2128
                        u.username,
2129
                        parent_id,
2130
                        accepted,
2131
                        qualificator_id,
2132
                        url_correction,
2133
                        title_correction
2134
                        ';
2135
        if ($getCount) {
2136
            $select = 'SELECT DISTINCT count(u.id) as count ';
2137
        }
2138
2139
        $work_assignment = get_work_assignment_by_id($work_id, $courseId);
2140
2141
        if (!empty($studentId)) {
2142
            $studentId = (int) $studentId;
2143
            $whereCondition .= " AND u.id = $studentId ";
2144
        }
2145
2146
        $sql = " $select
2147
                FROM $work_table work
2148
                INNER JOIN $user_table u
2149
                ON (work.user_id = u.id)
2150
                WHERE
2151
                    work.c_id = $course_id AND
2152
                    $extra_conditions
2153
                    $whereCondition
2154
                    $condition_session
2155
                    AND u.status != ".INVITEE."
2156
                ORDER BY $column $direction";
2157
2158
        if (!empty($start) && !empty($limit)) {
2159
            $sql .= " LIMIT $start, $limit";
2160
        }
2161
        $result = Database::query($sql);
2162
        $works = [];
2163
2164
        if ($getCount) {
2165
            $work = Database::fetch_array($result, 'ASSOC');
2166
            if ($work) {
2167
                return (int) $work['count'];
2168
            }
2169
2170
            return 0;
2171
        }
2172
2173
        $url = api_get_path(WEB_CODE_PATH).'work/';
2174
        $unoconv = api_get_configuration_value('unoconv.binaries');
2175
        $loadingText = addslashes(get_lang('Loading'));
2176
        $uploadedText = addslashes(get_lang('Uploaded.'));
2177
        $failsUploadText = addslashes(get_lang('No file was uploaded..'));
2178
        $failsUploadIcon = Display::return_icon(
2179
            'closed-circle.png',
2180
            '',
2181
            [],
2182
            ICON_SIZE_TINY
2183
        );
2184
        $saveIcon = Display::return_icon(
2185
            'save.png',
2186
            get_lang('Save'),
2187
            [],
2188
            ICON_SIZE_SMALL
2189
        );
2190
2191
        $correctionIcon = Display::return_icon(
2192
            'check-circle.png',
2193
            get_lang('Correction'),
2194
            null,
2195
            ICON_SIZE_SMALL
2196
        );
2197
2198
        $correctionIconSmall = Display::return_icon(
2199
            'check-circle.png',
2200
            get_lang('Correction'),
2201
            null,
2202
            ICON_SIZE_TINY
2203
        );
2204
2205
        $rateIcon = Display::return_icon(
2206
            'rate_work.png',
2207
            get_lang('Correct and rate'),
2208
            [],
2209
            ICON_SIZE_SMALL
2210
        );
2211
2212
        $blockEdition = api_get_configuration_value('block_student_publication_edition');
2213
        $blockScoreEdition = api_get_configuration_value('block_student_publication_score_edition');
2214
        $loading = Display::returnFontAwesomeIcon('spinner', null, true, 'fa-spin');
2215
2216
        $router = Container::getRouter();
2217
        $repo = Container::getStudentPublicationRepository();
2218
        while ($work = Database::fetch_array($result, 'ASSOC')) {
2219
            /** @var CStudentPublication $studentPublication */
2220
            $studentPublication = $repo->find($work['id']);
2221
2222
            $item_id = $work['id'];
2223
            $dbTitle = $work['title'];
2224
            // Get the author ID for that document from the item_property table
2225
            $is_author = false;
2226
            $can_read = false;
2227
            $owner_id = $work['user_id'];
2228
2229
            /* Because a bug found when saving items using the api_item_property_update()
2230
               the field $item_property_data['insert_user_id'] is not reliable. */
2231
            if (!$is_allowed_to_edit && $owner_id == api_get_user_id()) {
2232
                $is_author = true;
2233
            }
2234
2235
            if (0 == $course_info['show_score']) {
2236
                $can_read = true;
2237
            }
2238
2239
            $qualification_exists = false;
2240
            if (!empty($work_data['qualification']) &&
2241
                (int) ($work_data['qualification']) > 0
2242
            ) {
2243
                $qualification_exists = true;
2244
            }
2245
2246
            $qualification_string = '';
2247
            if ($qualification_exists) {
2248
                if ('' == $work['qualification']) {
2249
                    $qualification_string = Display::label('-');
2250
                } else {
2251
                    $qualification_string = formatWorkScore($work['qualification'], $work_data['qualification']);
2252
                }
2253
            }
2254
2255
            $work['qualification_score'] = $work['qualification'];
2256
            $add_string = '';
2257
            $time_expires = '';
2258
            if (!empty($work_assignment['expires_on'])) {
2259
                $time_expires = api_strtotime(
2260
                    $work_assignment['expires_on'],
2261
                    'UTC'
2262
                );
2263
            }
2264
2265
            if (!empty($work_assignment['expires_on']) &&
2266
                !empty($time_expires) && ($time_expires < api_strtotime($work['sent_date'], 'UTC'))) {
2267
                $add_string = Display::label(get_lang('Expired'), 'important').' - ';
2268
            }
2269
2270
            if (($can_read && '1' == $work['accepted']) ||
2271
                ($is_author && in_array($work['accepted'], ['1', '0'])) ||
2272
                ($is_allowed_to_edit || api_is_drh())
2273
            ) {
2274
                // Firstname, lastname, username
2275
                $work['fullname'] = Display::div(
2276
                    api_get_person_name($work['firstname'], $work['lastname']),
2277
                    ['class' => 'work-name']
2278
                );
2279
                // Title
2280
                $work['title_clean'] = $work['title'];
2281
                $work['title'] = Security::remove_XSS($work['title']);
2282
                if (strlen($work['title']) > 30) {
2283
                    $short_title = substr($work['title'], 0, 27).'...';
2284
                    $work['title'] = Display::span($short_title, ['class' => 'work-title', 'title' => $work['title']]);
2285
                } else {
2286
                    $work['title'] = Display::div($work['title'], ['class' => 'work-title']);
2287
                }
2288
2289
                // Type.
2290
                $work['type'] = DocumentManager::build_document_icon_tag('file', $work['url']);
2291
2292
                // File name.
2293
                $linkToDownload = '';
2294
                // If URL is present then there's a file to download keep BC.
2295
                if ($work['contains_file']) {
2296
                    $downloadUrl = $router->generate('chamilo_core_resource_download',
2297
                            [
2298
                                'id' => $studentPublication->getResourceNode()->getId(),
2299
                                'tool' => 'student_publication',
2300
                                'type' => 'student_publications',
2301
                            ]
2302
                        ).'?'.api_get_cidreq();
2303
                    $linkToDownload = '<a href="'.$downloadUrl.'">'.$saveIcon.'</a> ';
2304
                }
2305
2306
                $feedback = '';
2307
                $count = getWorkCommentCount($item_id, $course_info);
2308
                if (null !== $count && !empty($count)) {
2309
                    if ($qualification_exists) {
2310
                        $feedback .= ' ';
2311
                    }
2312
                    $feedback .= Display::url(
2313
                        $count.' '.Display::returnFontAwesomeIcon('comments-o'),
2314
                        $url.'view.php?'.api_get_cidreq().'&id='.$item_id
2315
                    );
2316
                }
2317
2318
                $correction = '';
2319
                $hasCorrection = '';
2320
                if (!empty($work['url_correction'])) {
2321
                    $downloadUrl = $router->generate('chamilo_core_resource_download',
2322
                            [
2323
                                'id' => $studentPublication->getResourceNode()->getId(),
2324
                                'tool' => 'student_publication',
2325
                                'type' => 'student_publications',
2326
                            ]
2327
                        ).'?'.api_get_cidreq();
2328
                    $hasCorrection = Display::url(
2329
                        $correctionIcon,
2330
                        $downloadUrl
2331
                    );
2332
                }
2333
2334
                if ($qualification_exists) {
2335
                    $work['qualification'] = $qualification_string.$feedback;
2336
                } else {
2337
                    $work['qualification'] = $qualification_string.$feedback.$hasCorrection;
2338
                }
2339
2340
                $work['qualification_only'] = $qualification_string;
2341
2342
                // Date.
2343
                $work_date = api_get_local_time($work['sent_date']);
2344
                $date = date_to_str_ago($work['sent_date']).' '.$work_date;
2345
                $work['formatted_date'] = $work_date.' '.$add_string;
2346
                $work['expiry_note'] = $add_string;
2347
                $work['sent_date_from_db'] = $work['sent_date'];
2348
                $work['sent_date'] = '<div class="work-date" title="'.$date.'">'.
2349
                    $add_string.' '.Display::dateToStringAgoAndLongDate($work['sent_date']).'</div>';
2350
                $work['status'] = $hasCorrection;
2351
                $work['has_correction'] = $hasCorrection;
2352
2353
                // Actions.
2354
                $action = '';
2355
                if (api_is_allowed_to_edit()) {
2356
                    if ($blockScoreEdition && !api_is_platform_admin() && !empty($work['qualification_score'])) {
2357
                        $rateLink = '';
2358
                    } else {
2359
                        $rateLink = '<a href="'.$url.'view.php?'.api_get_cidreq().'&id='.$item_id.'" title="'.get_lang('View').'">'.
2360
                            $rateIcon.'</a> ';
2361
                    }
2362
                    $action .= $rateLink;
2363
2364
                    if ($unoconv && empty($work['contains_file'])) {
2365
                        $action .= '<a
2366
                            href="'.$url.'work_list_all.php?'.api_get_cidreq().'&id='.$work_id.'&action=export_to_doc&item_id='.$item_id.'"
2367
                            title="'.get_lang('Export to .doc').'" >'.
2368
                            Display::return_icon('export_doc.png', get_lang('Export to .doc'), [], ICON_SIZE_SMALL).'</a> ';
2369
                    }
2370
2371
                    $alreadyUploaded = '';
2372
                    if (!empty($work['url_correction'])) {
2373
                        $alreadyUploaded = '<br />'.$work['title_correction'].' '.$correctionIconSmall;
2374
                    }
2375
2376
                    $correction = '
2377
                        <form
2378
                        id="file_upload_'.$item_id.'"
2379
                        class="work_correction_file_upload file_upload_small fileinput-button"
2380
                        action="'.api_get_path(WEB_AJAX_PATH).'work.ajax.php?'.api_get_cidreq().'&a=upload_correction_file&item_id='.$item_id.'" method="POST" enctype="multipart/form-data"
2381
                        >
2382
                        <div id="progress_'.$item_id.'" class="text-center button-load">
2383
                            '.addslashes(get_lang('Click or drop one file here')).'
2384
                            '.Display::return_icon('upload_file.png', get_lang('Correction'), [], ICON_SIZE_TINY).'
2385
                            '.$alreadyUploaded.'
2386
                        </div>
2387
                        <input id="file_'.$item_id.'" type="file" name="file" class="" multiple>
2388
                        </form>
2389
                    ';
2390
2391
                    $correction .= "<script>
2392
                    $(function() {
2393
                        $('.work_correction_file_upload').each(function () {
2394
                            $(this).fileupload({
2395
                                dropZone: $(this)
2396
                            });
2397
                        });
2398
2399
                        $('#file_upload_".$item_id."').fileupload({
2400
                            add: function (e, data) {
2401
                                $('#progress_$item_id').html();
2402
                                data.context = $('#progress_$item_id').html('$loadingText <br /> <em class=\"fa fa-spinner fa-pulse fa-fw\"></em>');
2403
                                data.submit();
2404
                                $(this).removeClass('hover');
2405
                            },
2406
                            dragover: function (e, data) {
2407
                                $(this).addClass('hover');
2408
                            },
2409
                            done: function (e, data) {
2410
                                if (data._response.result.name) {
2411
                                    $('#progress_$item_id').html('$uploadedText '+data._response.result.result+'<br />'+data._response.result.name);
2412
                                } else {
2413
                                    $('#progress_$item_id').html('$failsUploadText $failsUploadIcon');
2414
                                }
2415
                                $(this).removeClass('hover');
2416
                            }
2417
                        });
2418
                        $('#file_upload_".$item_id."').on('dragleave', function (e) {
2419
                            // dragleave callback implementation
2420
                            $(this).removeClass('hover');
2421
                        });
2422
                    });
2423
                    </script>";
2424
2425
                    if ($locked) {
2426
                        if ($qualification_exists) {
2427
                            $action .= Display::return_icon(
2428
                                'edit_na.png',
2429
                                get_lang('Correct and rate'),
2430
                                [],
2431
                                ICON_SIZE_SMALL
2432
                            );
2433
                        } else {
2434
                            $action .= Display::return_icon('edit_na.png', get_lang('Comment'), [], ICON_SIZE_SMALL);
2435
                        }
2436
                    } else {
2437
                        if ($blockEdition && !api_is_platform_admin()) {
2438
                            $editLink = '';
2439
                        } else {
2440
                            if ($qualification_exists) {
2441
                                $editLink = '<a href="'.$url.'edit.php?'.api_get_cidreq(
2442
                                    ).'&item_id='.$item_id.'&id='.$work['parent_id'].'" title="'.get_lang(
2443
                                        'Edit'
2444
                                    ).'"  >'.
2445
                                    Display::return_icon('edit.png', get_lang('Edit'), [], ICON_SIZE_SMALL).'</a>';
2446
                            } else {
2447
                                $editLink = '<a href="'.$url.'edit.php?'.api_get_cidreq(
2448
                                    ).'&item_id='.$item_id.'&id='.$work['parent_id'].'" title="'.get_lang(
2449
                                        'Edit'
2450
                                    ).'">'.
2451
                                    Display::return_icon('edit.png', get_lang('Edit'), [], ICON_SIZE_SMALL).'</a>';
2452
                            }
2453
                        }
2454
                        $action .= $editLink;
2455
                    }
2456
2457
                    if ($work['contains_file']) {
2458
                        if ($locked) {
2459
                            $action .= Display::return_icon(
2460
                                'move_na.png',
2461
                                get_lang('Move'),
2462
                                [],
2463
                                ICON_SIZE_SMALL
2464
                            );
2465
                        } else {
2466
                            $action .= '<a href="'.$url.'work.php?'.api_get_cidreq().'&action=move&item_id='.$item_id.'&id='.$work['parent_id'].'" title="'.get_lang('Move').'">'.
2467
                                Display::return_icon('move.png', get_lang('Move'), [], ICON_SIZE_SMALL).'</a>';
2468
                        }
2469
                    }
2470
2471
                    if ('1' == $work['accepted']) {
2472
                        $action .= '<a href="'.$url.'work_list_all.php?'.api_get_cidreq().'&id='.$work_id.'&action=make_invisible&item_id='.$item_id.'" title="'.get_lang('invisible').'" >'.
2473
                            Display::return_icon('visible.png', get_lang('invisible'), [], ICON_SIZE_SMALL).'</a>';
2474
                    } else {
2475
                        $action .= '<a href="'.$url.'work_list_all.php?'.api_get_cidreq().'&id='.$work_id.'&action=make_visible&item_id='.$item_id.'" title="'.get_lang('Visible').'" >'.
2476
                            Display::return_icon('invisible.png', get_lang('Visible'), [], ICON_SIZE_SMALL).'</a> ';
2477
                    }
2478
2479
                    if ($locked) {
2480
                        $action .= Display::return_icon('delete_na.png', get_lang('Delete'), '', ICON_SIZE_SMALL);
2481
                    } else {
2482
                        $action .= '<a href="'.$url.'work_list_all.php?'.api_get_cidreq().'&id='.$work_id.'&action=delete&item_id='.$item_id.'" onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang('Please confirm your choice'), ENT_QUOTES))."'".')) return false;" title="'.get_lang('Delete').'" >'.
2483
                            Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL).'</a>';
2484
                    }
2485
                } elseif ($is_author && (empty($work['qualificator_id']) || 0 == $work['qualificator_id'])) {
2486
                    $action .= '<a href="'.$url.'view.php?'.api_get_cidreq().'&id='.$item_id.'" title="'.get_lang('View').'">'.
2487
                        Display::return_icon('default.png', get_lang('View'), [], ICON_SIZE_SMALL).'</a>';
2488
2489
                    if (1 == api_get_course_setting('student_delete_own_publication')) {
2490
                        if (api_is_allowed_to_session_edit(false, true)) {
2491
                            $action .= '<a href="'.$url.'edit.php?'.api_get_cidreq().'&item_id='.$item_id.'&id='.$work['parent_id'].'" title="'.get_lang('Edit').'">'.
2492
                                Display::return_icon('edit.png', get_lang('Comment'), [], ICON_SIZE_SMALL).'</a>';
2493
                        }
2494
                        $action .= ' <a href="'.$url.'work_list.php?'.api_get_cidreq().'&action=delete&item_id='.$item_id.'&id='.$work['parent_id'].'" onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang('Please confirm your choice'), ENT_QUOTES))."'".')) return false;" title="'.get_lang('Delete').'"  >'.
2495
                            Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL).'</a>';
2496
                    }
2497
                } else {
2498
                    $action .= '<a href="'.$url.'view.php?'.api_get_cidreq().'&id='.$item_id.'" title="'.get_lang('View').'">'.
2499
                        Display::return_icon('default.png', get_lang('View'), [], ICON_SIZE_SMALL).'</a>';
2500
                }
2501
2502
                // Status.
2503
                if (empty($work['qualificator_id'])) {
2504
                    $qualificator_id = Display::label(get_lang('Not reviewed'), 'warning');
2505
                } else {
2506
                    $qualificator_id = Display::label(get_lang('Revised'), 'success');
2507
                }
2508
                $work['qualificator_id'] = $qualificator_id.' '.$hasCorrection;
2509
                $work['actions'] = '<div class="work-action">'.$linkToDownload.$action.'</div>';
2510
                $work['correction'] = $correction;
2511
2512
                if (!empty($compilation)) {
2513
                    $compilationId = $compilation->getCompilatioId($item_id, $course_id);
2514
                    if ($compilationId) {
2515
                        $actionCompilatio = "<div id='id_avancement".$item_id."' class='compilation_block'>
2516
                            ".$loading.'&nbsp;'.get_lang('Connecting with the Compilatio server').'</div>';
2517
                    } else {
2518
                        $workDirectory = api_get_path(SYS_COURSE_PATH).$course_info['directory'];
2519
                        if (!Compilatio::verifiFileType($dbTitle)) {
2520
                            $actionCompilatio = get_lang('File format not supported');
2521
                        } elseif (filesize($workDirectory.'/'.$work['url']) > $compilation->getMaxFileSize()) {
2522
                            $sizeFile = round(filesize($workDirectory.'/'.$work['url']) / 1000000);
2523
                            $actionCompilatio = get_lang('The file is too big to upload.').': '.format_file_size($sizeFile).'<br />';
2524
                        } else {
2525
                            $actionCompilatio = "<div id='id_avancement".$item_id."' class='compilation_block'>";
2526
                            $actionCompilatio .= Display::url(
2527
                                get_lang('Analyse'),
2528
                                'javascript:void(0)',
2529
                                [
2530
                                    'class' => 'getSingleCompilatio btn btn-primary btn-xs',
2531
                                    'onclick' => "getSingleCompilatio($item_id);",
2532
                                ]
2533
                            );
2534
                            $actionCompilatio .= get_lang('with Compilatio');
2535
                        }
2536
                    }
2537
                    $work['compilatio'] = $actionCompilatio;
2538
                }
2539
                $works[] = $work;
2540
            }
2541
        }
2542
2543
        return $works;
2544
    }
2545
}
2546
2547
/**
2548
 * Send reminder to users who have not given the task.
2549
 *
2550
 * @param int
2551
 *
2552
 * @return array
2553
 *
2554
 * @author cvargas [email protected] cfasanando, [email protected]
2555
 */
2556
function send_reminder_users_without_publication($task_data)
2557
{
2558
    $_course = api_get_course_info();
2559
    $task_id = $task_data['id'];
2560
    $task_title = !empty($task_data['title']) ? $task_data['title'] : basename($task_data['url']);
2561
    $subject = '['.api_get_setting('siteName').'] ';
2562
2563
    // The body can be as long as you wish, and any combination of text and variables
2564
    $content = get_lang('Please remember you still have to send an assignment')."\n".get_lang('Course name').' : '.$_course['name']."\n";
2565
    $content .= get_lang('Assignment name').' : '.$task_title."\n";
2566
    $list_users = get_list_users_without_publication($task_id);
2567
    $mails_sent_to = [];
2568
    foreach ($list_users as $user) {
2569
        $name_user = api_get_person_name($user[1], $user[0], null, PERSON_NAME_EMAIL_ADDRESS);
2570
        $dear_line = get_lang('Dear').' '.api_get_person_name($user[1], $user[0]).", \n\n";
2571
        $body = $dear_line.$content;
2572
        MessageManager::send_message($user[3], $subject, $body);
2573
        $mails_sent_to[] = $name_user;
2574
    }
2575
2576
    return $mails_sent_to;
2577
}
2578
2579
/**
2580
 * @param int $workId    The work ID
2581
 * @param int $courseId  The course ID
2582
 * @param int $sessionId Optional. The session ID
2583
 */
2584
function sendEmailToDrhOnHomeworkCreation($workId, $courseId, $sessionId = 0)
2585
{
2586
    $courseInfo = api_get_course_info_by_id($courseId);
2587
    $assignment = get_work_assignment_by_id($workId, $courseId);
2588
    $work = get_work_data_by_id($workId, $courseId, $sessionId);
2589
    $workInfo = array_merge($assignment, $work);
2590
2591
    if (empty($sessionId)) {
2592
        $students = CourseManager::get_student_list_from_course_code($courseInfo['code']);
2593
    } else {
2594
        $students = CourseManager::get_student_list_from_course_code($courseInfo['code'], true, $sessionId);
2595
    }
2596
2597
    $bodyView = new Template(null, false, false, false, false, false);
2598
2599
    foreach ($students as $student) {
2600
        $studentInfo = api_get_user_info($student['user_id']);
2601
        if (empty($studentInfo)) {
2602
            continue;
2603
        }
2604
2605
        $hrms = UserManager::getDrhListFromUser($student['id']);
2606
        foreach ($hrms as $hrm) {
2607
            $hrmName = api_get_person_name($hrm['firstname'], $hrm['lastname'], null, PERSON_NAME_EMAIL_ADDRESS);
2608
2609
            $bodyView->assign('hrm_name', $hrmName);
2610
            $bodyView->assign('student', $studentInfo);
2611
            $bodyView->assign('course', $courseInfo);
2612
            $bodyView->assign('course_link', api_get_course_url($courseInfo['code'], $sessionId));
2613
            $bodyView->assign('work', $workInfo);
2614
2615
            $bodyTemplate = $bodyView->get_template('mail/new_work_alert_hrm.tpl');
2616
2617
            MessageManager::send_message(
2618
                $hrm['id'],
2619
                sprintf(
2620
                    get_lang('%s got a new assignment in course %s'),
2621
                    $student['firstname'],
2622
                    $courseInfo['title']
2623
                ),
2624
                $bodyView->fetch($bodyTemplate)
2625
            );
2626
        }
2627
    }
2628
}
2629
2630
/**
2631
 * Sends an email to the students of a course when a homework is created.
2632
 *
2633
 * @param int $workId
2634
 * @param int $courseId
2635
 * @param int $sessionId
2636
 *
2637
 * @author Guillaume Viguier <[email protected]>
2638
 * @author Julio Montoya <[email protected]> Adding session support - 2011
2639
 */
2640
function sendEmailToStudentsOnHomeworkCreation($workId, $courseId, $sessionId = 0)
2641
{
2642
    $courseInfo = api_get_course_info_by_id($courseId);
2643
    $courseCode = $courseInfo['code'];
2644
    // Get the students of the course
2645
    if (empty($sessionId)) {
2646
        $students = CourseManager::get_student_list_from_course_code($courseCode);
2647
    } else {
2648
        $students = CourseManager::get_student_list_from_course_code($courseCode, true, $sessionId);
2649
    }
2650
    $emailsubject = '['.api_get_setting('siteName').'] '.get_lang('An assignment was created');
2651
    $currentUser = api_get_user_info(api_get_user_id());
2652
    if (!empty($students)) {
2653
        foreach ($students as $student) {
2654
            $user_info = api_get_user_info($student['user_id']);
2655
            if (!empty($user_info)) {
2656
                $link = api_get_path(WEB_CODE_PATH).'work/work_list.php?'.api_get_cidreq().'&id='.$workId;
2657
                $emailbody = get_lang('Dear').' '.$user_info['complete_name'].",\n\n";
2658
                $emailbody .= get_lang('An assignment has been added to course').' '.$courseCode.'. '."\n\n".
2659
                    '<a href="'.$link.'">'.get_lang('Please check the assignments page.').'</a>';
2660
                $emailbody .= "\n\n".$currentUser['complete_name'];
2661
2662
                $additionalParameters = [
2663
                    'smsType' => SmsPlugin::ASSIGNMENT_BEEN_CREATED_COURSE,
2664
                    'userId' => $student['user_id'],
2665
                    'courseTitle' => $courseCode,
2666
                    'link' => $link,
2667
                ];
2668
2669
                MessageManager::send_message_simple(
2670
                    $student['user_id'],
2671
                    $emailsubject,
2672
                    $emailbody,
2673
                    null,
2674
                    false,
2675
                    false,
2676
                    $additionalParameters,
2677
                    false
2678
                );
2679
            }
2680
        }
2681
    }
2682
}
2683
2684
/**
2685
 * @param string $url
2686
 *
2687
 * @return bool
2688
 */
2689
function is_work_exist_by_url($url)
2690
{
2691
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
2692
    $url = Database::escape_string($url);
2693
    $sql = "SELECT id FROM $table WHERE url='$url'";
2694
    $result = Database::query($sql);
2695
    if (Database::num_rows($result) > 0) {
2696
        $row = Database::fetch_row($result);
2697
        if (empty($row)) {
2698
            return false;
2699
        } else {
2700
            return true;
2701
        }
2702
    } else {
2703
        return false;
2704
    }
2705
}
2706
2707
/**
2708
 * Check if a user is the author of a work document.
2709
 *
2710
 * @param int $itemId
2711
 * @param int $userId
2712
 * @param int $courseId
2713
 * @param int $sessionId
2714
 *
2715
 * @return bool
2716
 */
2717
function user_is_author($itemId, $userId = null, $courseId = 0, $sessionId = 0)
2718
{
2719
    $userId = (int) $userId;
2720
2721
    if (empty($itemId)) {
2722
        return false;
2723
    }
2724
2725
    if (empty($userId)) {
2726
        $userId = api_get_user_id();
2727
    }
2728
2729
    $isAuthor = false;
2730
    $is_allowed_to_edit = api_is_allowed_to_edit();
2731
2732
    if ($is_allowed_to_edit) {
2733
        $isAuthor = true;
2734
    } else {
2735
        if (empty($courseId)) {
2736
            $courseId = api_get_course_int_id();
2737
        }
2738
        if (empty($sessionId)) {
2739
            $sessionId = api_get_session_id();
2740
        }
2741
2742
        $repo = Container::getStudentPublicationRepository();
2743
        /** @var CStudentPublication $studentPublication */
2744
        $studentPublication = $repo->find($itemId);
2745
        if ($studentPublication->getResourceNode()->getCreator()->getId() === $userId) {
2746
            $isAuthor = true;
2747
        }
2748
2749
        /*$data = api_get_item_property_info($courseId, 'work', $itemId, $sessionId);
2750
        if ($data['insert_user_id'] == $userId) {
2751
            $isAuthor = true;
2752
        }*/
2753
2754
        $workData = get_work_data_by_id($itemId);
2755
        if ($workData['user_id'] == $userId) {
2756
            $isAuthor = true;
2757
        }
2758
    }
2759
2760
    if (!$isAuthor) {
2761
        return false;
2762
    }
2763
2764
    return $isAuthor;
2765
}
2766
2767
/**
2768
 * Get list of users who have not given the task.
2769
 *
2770
 * @param int
2771
 * @param int
2772
 *
2773
 * @return array
2774
 *
2775
 * @author cvargas
2776
 * @author Julio Montoya <[email protected]> Fixing query
2777
 */
2778
function get_list_users_without_publication($task_id, $studentId = 0)
2779
{
2780
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
2781
    $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2782
    $table_user = Database::get_main_table(TABLE_MAIN_USER);
2783
    $session_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2784
2785
    $users = getAllUserToWork($task_id, api_get_course_int_id());
2786
    $users = array_column($users, 'user_id');
2787
2788
    // Condition for the session
2789
    $session_id = api_get_session_id();
2790
    $course_id = api_get_course_int_id();
2791
    $task_id = (int) $task_id;
2792
    $sessionCondition = api_get_session_condition($session_id);
2793
2794
    if (0 == $session_id) {
2795
        $sql = "SELECT user_id as id FROM $work_table
2796
                WHERE
2797
                    c_id = $course_id AND
2798
                    parent_id = '$task_id' AND
2799
                    active IN (0, 1)";
2800
    } else {
2801
        $sql = "SELECT user_id as id FROM $work_table
2802
                WHERE
2803
                    c_id = $course_id AND
2804
                    parent_id = '$task_id' $sessionCondition AND
2805
                    active IN (0, 1)";
2806
    }
2807
2808
    $result = Database::query($sql);
2809
    $users_with_tasks = [];
2810
    while ($row = Database::fetch_array($result)) {
2811
        $users_with_tasks[] = $row['id'];
2812
    }
2813
2814
    if (0 == $session_id) {
2815
        $sql_users = "SELECT cu.user_id, u.lastname, u.firstname, u.email
2816
                      FROM $table_course_user AS cu, $table_user AS u
2817
                      WHERE u.status != 1 and cu.c_id='".$course_id."' AND u.id = cu.user_id";
2818
    } else {
2819
        $sql_users = "SELECT cu.user_id, u.lastname, u.firstname, u.email
2820
                      FROM $session_course_rel_user AS cu, $table_user AS u
2821
                      WHERE
2822
                        u.status != 1 AND
2823
                        cu.c_id='".$course_id."' AND
2824
                        u.id = cu.user_id AND
2825
                        cu.session_id = '".$session_id."'";
2826
    }
2827
2828
    if (!empty($studentId)) {
2829
        $sql_users .= ' AND u.id = '.(int) $studentId;
2830
    }
2831
2832
    $group_id = api_get_group_id();
2833
    $new_group_user_list = [];
2834
2835
    if ($group_id) {
2836
        $groupInfo = GroupManager::get_group_properties($group_id);
2837
        $group_user_list = GroupManager::get_subscribed_users($groupInfo);
2838
        if (!empty($group_user_list)) {
2839
            foreach ($group_user_list as $group_user) {
2840
                $new_group_user_list[] = $group_user['user_id'];
2841
            }
2842
        }
2843
    }
2844
2845
    $result_users = Database::query($sql_users);
2846
    $users_without_tasks = [];
2847
    while ($rowUsers = Database::fetch_array($result_users)) {
2848
        $userId = $rowUsers['user_id'];
2849
        if (in_array($userId, $users_with_tasks)) {
2850
            continue;
2851
        }
2852
2853
        if ($group_id && !in_array($userId, $new_group_user_list)) {
2854
            continue;
2855
        }
2856
2857
        if (!empty($users)) {
2858
            if (!in_array($userId, $users)) {
2859
                continue;
2860
            }
2861
        }
2862
2863
        $row_users = [];
2864
        $row_users[0] = $rowUsers['lastname'];
2865
        $row_users[1] = $rowUsers['firstname'];
2866
        $row_users[2] = Display::encrypted_mailto_link($rowUsers['email']);
2867
        $row_users[3] = $userId;
2868
        $users_without_tasks[] = $row_users;
2869
    }
2870
2871
    return $users_without_tasks;
2872
}
2873
2874
/**
2875
 * Display list of users who have not given the task.
2876
 *
2877
 * @param int task id
2878
 * @param int $studentId
2879
 *
2880
 * @author cvargas [email protected] cfasanando, [email protected]
2881
 * @author Julio Montoya <[email protected]> Fixes
2882
 */
2883
function display_list_users_without_publication($task_id, $studentId = null)
2884
{
2885
    $origin = api_get_origin();
2886
    $table_header[] = [get_lang('Last name'), true];
2887
    $table_header[] = [get_lang('First name'), true];
2888
    $table_header[] = [get_lang('e-mail'), true];
2889
2890
    $data = get_list_users_without_publication($task_id);
2891
2892
    $sorting_options = [];
2893
    $sorting_options['column'] = 1;
2894
    $paging_options = [];
2895
    $my_params = [];
2896
2897
    if (isset($_GET['edit_dir'])) {
2898
        $my_params['edit_dir'] = Security::remove_XSS($_GET['edit_dir']);
2899
    }
2900
    if (isset($_GET['list'])) {
2901
        $my_params['list'] = Security::remove_XSS($_GET['list']);
2902
    }
2903
    $my_params['origin'] = $origin;
2904
    $my_params['id'] = (int) ($_GET['id']);
2905
2906
    //$column_show
2907
    $column_show[] = 1;
2908
    $column_show[] = 1;
2909
    $column_show[] = 1;
2910
    Display::display_sortable_config_table(
2911
        'work',
2912
        $table_header,
2913
        $data,
2914
        $sorting_options,
2915
        $paging_options,
2916
        $my_params,
2917
        $column_show
2918
    );
2919
}
2920
2921
/**
2922
 * @param int $documentId
2923
 * @param int $workId
2924
 * @param int $courseId
2925
 */
2926
function addDocumentToWork($documentId, $workId, $courseId)
2927
{
2928
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
2929
    $params = [
2930
        'document_id' => $documentId,
2931
        'work_id' => $workId,
2932
        'c_id' => $courseId,
2933
    ];
2934
    Database::insert($table, $params);
2935
}
2936
2937
/**
2938
 * @param int $documentId
2939
 * @param int $workId
2940
 * @param int $courseId
2941
 *
2942
 * @return array
2943
 */
2944
function getDocumentToWork($documentId, $workId, $courseId)
2945
{
2946
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
2947
    $params = [
2948
        'document_id = ? and work_id = ? and c_id = ?' => [$documentId, $workId, $courseId],
2949
    ];
2950
2951
    return Database::select('*', $table, ['where' => $params]);
2952
}
2953
2954
/**
2955
 * @param int $documentId
2956
 * @param int $workId
2957
 * @param int $courseId
2958
 * @param int $sessionId
2959
 * @param int $userId
2960
 * @param int $active
2961
 *
2962
 * @return array
2963
 */
2964
function getDocumentToWorkPerUser($documentId, $workId, $courseId, $sessionId, $userId, $active = 1)
2965
{
2966
    $workRel = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
2967
    $work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
2968
2969
    $documentId = (int) $documentId;
2970
    $workId = (int) $workId;
2971
    $courseId = (int) $courseId;
2972
    $userId = (int) $userId;
2973
    $sessionId = (int) $sessionId;
2974
    $active = (int) $active;
2975
    $sessionCondition = api_get_session_condition($sessionId);
2976
2977
    $sql = "SELECT w.* FROM $work w
2978
            INNER JOIN $workRel rel
2979
            ON (w.parent_id = rel.work_id)
2980
            WHERE
2981
                w.document_id = $documentId AND
2982
                w.parent_id = $workId AND
2983
                w.c_id = $courseId
2984
                $sessionCondition AND
2985
                user_id = $userId AND
2986
                active = $active
2987
            ";
2988
2989
    $result = Database::query($sql);
2990
    $workInfo = [];
2991
    if (Database::num_rows($result)) {
2992
        $workInfo = Database::fetch_array($result, 'ASSOC');
2993
    }
2994
2995
    return $workInfo;
2996
}
2997
2998
/**
2999
 * @param int $workId
3000
 * @param int $courseId
3001
 *
3002
 * @return array
3003
 */
3004
function getAllDocumentToWork($workId, $courseId)
3005
{
3006
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
3007
    $params = [
3008
        'work_id = ? and c_id = ?' => [$workId, $courseId],
3009
    ];
3010
3011
    return Database::select('*', $table, ['where' => $params]);
3012
}
3013
3014
/**
3015
 * @param int $documentId
3016
 * @param int $workId
3017
 * @param int $courseId
3018
 */
3019
function deleteDocumentToWork($documentId, $workId, $courseId)
3020
{
3021
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
3022
    $params = [
3023
        'document_id = ? and work_id = ? and c_id = ?' => [$documentId, $workId, $courseId],
3024
    ];
3025
    Database::delete($table, $params);
3026
}
3027
3028
/**
3029
 * @param int $userId
3030
 * @param int $workId
3031
 * @param int $courseId
3032
 */
3033
function addUserToWork($userId, $workId, $courseId)
3034
{
3035
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_USER);
3036
    $params = [
3037
        'user_id' => $userId,
3038
        'work_id' => $workId,
3039
        'c_id' => $courseId,
3040
    ];
3041
    Database::insert($table, $params);
3042
}
3043
3044
/**
3045
 * @param int $userId
3046
 * @param int $workId
3047
 * @param int $courseId
3048
 *
3049
 * @return array
3050
 */
3051
function getUserToWork($userId, $workId, $courseId)
3052
{
3053
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_USER);
3054
    $params = [
3055
        'user_id = ? and work_id = ? and c_id = ?' => [$userId, $workId, $courseId],
3056
    ];
3057
3058
    return Database::select('*', $table, ['where' => $params]);
3059
}
3060
3061
/**
3062
 * @param int  $workId
3063
 * @param int  $courseId
3064
 * @param bool $getCount
3065
 *
3066
 * @return array|int
3067
 */
3068
function getAllUserToWork($workId, $courseId, $getCount = false)
3069
{
3070
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_USER);
3071
    $params = [
3072
        'work_id = ? and c_id = ?' => [$workId, $courseId],
3073
    ];
3074
    if ($getCount) {
3075
        $count = 0;
3076
        $result = Database::select(
3077
            'count(user_id) as count',
3078
            $table,
3079
            ['where' => $params],
3080
            'simple'
3081
        );
3082
        if (!empty($result)) {
3083
            $count = (int) ($result['count']);
3084
        }
3085
3086
        return $count;
3087
    } else {
3088
        return Database::select('*', $table, ['where' => $params]);
3089
    }
3090
}
3091
3092
/**
3093
 * @param int $userId
3094
 * @param int $workId
3095
 * @param int $courseId
3096
 */
3097
function deleteUserToWork($userId, $workId, $courseId)
3098
{
3099
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_USER);
3100
    $params = [
3101
        'user_id = ? and work_id = ? and c_id = ?' => [$userId, $workId, $courseId],
3102
    ];
3103
    Database::delete($table, $params);
3104
}
3105
3106
/**
3107
 * @param int $userId
3108
 * @param int $workId
3109
 * @param int $courseId
3110
 *
3111
 * @return bool
3112
 */
3113
function userIsSubscribedToWork($userId, $workId, $courseId)
3114
{
3115
    $subscribedUsers = getAllUserToWork($workId, $courseId);
3116
3117
    if (empty($subscribedUsers)) {
3118
        return true;
3119
    } else {
3120
        $subscribedUsersList = [];
3121
        foreach ($subscribedUsers as $item) {
3122
            $subscribedUsersList[] = $item['user_id'];
3123
        }
3124
        if (in_array($userId, $subscribedUsersList)) {
3125
            return true;
3126
        }
3127
    }
3128
3129
    return false;
3130
}
3131
3132
/**
3133
 * Get the list of students that have to submit their work.
3134
 *
3135
 * @param int  $workId    The internal ID of the assignment
3136
 * @param int  $courseId  The course ID
3137
 * @param int  $groupId   The group ID, if any
3138
 * @param int  $sessionId The session ID, if any
3139
 * @param bool $getCount  Whether we want just the amount or the full result
3140
 *
3141
 * @return array|int An integer (if we just asked for the count) or an array of users
3142
 */
3143
function getStudentSubscribedToWork(
3144
    $workId,
3145
    $courseId,
3146
    $groupId = null,
3147
    $sessionId = null,
3148
    $getCount = false
3149
) {
3150
    $usersInWork = null;
3151
    $usersInCourse = null;
3152
3153
    if (empty($groupId)) {
3154
        $courseInfo = api_get_course_info_by_id($courseId);
3155
        $status = STUDENT;
3156
        if (!empty($sessionId)) {
3157
            $status = 0;
3158
        }
3159
        $usersInCourse = CourseManager::get_user_list_from_course_code(
3160
            $courseInfo['code'],
3161
            $sessionId,
3162
            null,
3163
            null,
3164
            $status,
3165
            $getCount
3166
        );
3167
    } else {
3168
        $usersInCourse = GroupManager::get_users(
3169
            $groupId,
3170
            false,
3171
            null,
3172
            null,
3173
            $getCount,
3174
            $courseId
3175
        );
3176
    }
3177
3178
    $usersInWork = getAllUserToWork($workId, $courseId, $getCount);
3179
3180
    if (empty($usersInWork)) {
3181
        return $usersInCourse;
3182
    } else {
3183
        return $usersInWork;
3184
    }
3185
}
3186
3187
/**
3188
 * @param int  $userId
3189
 * @param int  $workId
3190
 * @param int  $courseId
3191
 * @param bool $forceAccessForCourseAdmins
3192
 *
3193
 * @return bool
3194
 */
3195
function allowOnlySubscribedUser($userId, $workId, $courseId, $forceAccessForCourseAdmins = false)
3196
{
3197
    if (api_is_platform_admin() || api_is_allowed_to_edit()) {
3198
        return true;
3199
    }
3200
3201
    if ($forceAccessForCourseAdmins) {
3202
        if (api_is_course_admin() || api_is_coach()) {
3203
            return true;
3204
        }
3205
    }
3206
3207
    return userIsSubscribedToWork($userId, $workId, $courseId);
3208
}
3209
3210
/**
3211
 * @param int   $workId
3212
 * @param array $courseInfo
3213
 * @param int   $documentId
3214
 *
3215
 * @return array
3216
 */
3217
function getDocumentTemplateFromWork($workId, $courseInfo, $documentId)
3218
{
3219
    $documents = getAllDocumentToWork($workId, $courseInfo['real_id']);
3220
    if (!empty($documents)) {
3221
        foreach ($documents as $doc) {
3222
            if ($documentId != $doc['document_id']) {
3223
                continue;
3224
            }
3225
            $docData = DocumentManager::get_document_data_by_id($doc['document_id'], $courseInfo['code']);
3226
            $fileInfo = pathinfo($docData['path']);
3227
            if ('html' == $fileInfo['extension']) {
3228
                if (file_exists($docData['absolute_path']) && is_file($docData['absolute_path'])) {
3229
                    $docData['file_content'] = file_get_contents($docData['absolute_path']);
3230
3231
                    return $docData;
3232
                }
3233
            }
3234
        }
3235
    }
3236
3237
    return [];
3238
}
3239
3240
/**
3241
 * @param int   $workId
3242
 * @param array $courseInfo
3243
 *
3244
 * @return string
3245
 */
3246
function getAllDocumentsFromWorkToString($workId, $courseInfo)
3247
{
3248
    $documents = getAllDocumentToWork($workId, $courseInfo['real_id']);
3249
    $content = null;
3250
    if (!empty($documents)) {
3251
        $content .= '<ul class="nav nav-list well">';
3252
        $content .= '<li class="nav-header">'.get_lang('Documents').'</li>';
3253
        foreach ($documents as $doc) {
3254
            $docData = DocumentManager::get_document_data_by_id($doc['document_id'], $courseInfo['code']);
3255
            if ($docData) {
3256
                $content .= '<li><a class="link_to_download" target="_blank" href="'.$docData['url'].'">'.$docData['title'].'</a></li>';
3257
            }
3258
        }
3259
        $content .= '</ul><br />';
3260
    }
3261
3262
    return $content;
3263
}
3264
3265
/**
3266
 * Returns fck editor toolbar.
3267
 *
3268
 * @return array
3269
 */
3270
function getWorkDescriptionToolbar()
3271
{
3272
    return [
3273
        'ToolbarStartExpanded' => 'true',
3274
        'ToolbarSet' => 'Work',
3275
        'Width' => '100%',
3276
        'Height' => '400',
3277
    ];
3278
}
3279
3280
/**
3281
 * @param array $work
3282
 *
3283
 * @return array
3284
 */
3285
function getWorkComments($work)
3286
{
3287
    $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
3288
    $userTable = Database::get_main_table(TABLE_MAIN_USER);
3289
3290
    $courseId = (int) $work['c_id'];
3291
    $workId = (int) $work['id'];
3292
3293
    if (empty($courseId) || empty($workId)) {
3294
        return [];
3295
    }
3296
3297
    $sql = "SELECT
3298
                c.id,
3299
                c.user_id
3300
            FROM $commentTable c
3301
            INNER JOIN $userTable u
3302
            ON (u.id = c.user_id)
3303
            WHERE c_id = $courseId AND work_id = $workId
3304
            ORDER BY sent_at
3305
            ";
3306
    $result = Database::query($sql);
3307
    $comments = Database::store_result($result, 'ASSOC');
3308
    if (!empty($comments)) {
3309
        foreach ($comments as &$comment) {
3310
            $userInfo = api_get_user_info($comment['user_id']);
3311
            $comment['picture'] = $userInfo['avatar'];
3312
            $comment['complete_name'] = $userInfo['complete_name_with_username'];
3313
            $commentInfo = getWorkComment($comment['id']);
3314
            if (!empty($commentInfo)) {
3315
                $comment = array_merge($comment, $commentInfo);
3316
            }
3317
        }
3318
    }
3319
3320
    return $comments;
3321
}
3322
3323
/**
3324
 * Get total score from a work list.
3325
 *
3326
 * @param $workList
3327
 *
3328
 * @return int|null
3329
 */
3330
function getTotalWorkScore($workList)
3331
{
3332
    $count = 0;
3333
    foreach ($workList as $data) {
3334
        $count += $data['qualification_score'];
3335
    }
3336
3337
    return $count;
3338
}
3339
3340
/**
3341
 * Get comment count from a work list (docs sent by students).
3342
 *
3343
 * @param array $workList
3344
 * @param array $courseInfo
3345
 *
3346
 * @return int|null
3347
 */
3348
function getTotalWorkComment($workList, $courseInfo = [])
3349
{
3350
    if (empty($courseInfo)) {
3351
        $courseInfo = api_get_course_info();
3352
    }
3353
3354
    $count = 0;
3355
    foreach ($workList as $data) {
3356
        $count += getWorkCommentCount($data['id'], $courseInfo);
3357
    }
3358
3359
    return $count;
3360
}
3361
3362
/**
3363
 * Get comment count for a specific work sent by a student.
3364
 *
3365
 * @param int   $id
3366
 * @param array $courseInfo
3367
 *
3368
 * @return int
3369
 */
3370
function getWorkCommentCount($id, $courseInfo = [])
3371
{
3372
    if (empty($courseInfo)) {
3373
        $courseInfo = api_get_course_info();
3374
    }
3375
3376
    $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
3377
    $id = (int) $id;
3378
3379
    $sql = "SELECT count(*) as count
3380
            FROM $commentTable
3381
            WHERE work_id = $id AND c_id = ".$courseInfo['real_id'];
3382
3383
    $result = Database::query($sql);
3384
    if (Database::num_rows($result)) {
3385
        $comment = Database::fetch_array($result);
3386
3387
        return $comment['count'];
3388
    }
3389
3390
    return 0;
3391
}
3392
3393
/**
3394
 * Get comment count for a specific parent.
3395
 *
3396
 * @param int   $parentId
3397
 * @param array $courseInfo
3398
 * @param int   $sessionId
3399
 *
3400
 * @return int
3401
 */
3402
function getWorkCommentCountFromParent(
3403
    $parentId,
3404
    $courseInfo = [],
3405
    $sessionId = 0
3406
) {
3407
    if (empty($courseInfo)) {
3408
        $courseInfo = api_get_course_info();
3409
    }
3410
3411
    if (empty($sessionId)) {
3412
        $sessionId = api_get_session_id();
3413
    } else {
3414
        $sessionId = (int) $sessionId;
3415
    }
3416
3417
    $work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
3418
    $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
3419
    $parentId = (int) $parentId;
3420
    $sessionCondition = api_get_session_condition($sessionId, false, false, 'w.session_id');
3421
3422
    $sql = "SELECT count(*) as count
3423
            FROM $commentTable c INNER JOIN $work w
3424
            ON c.c_id = w.c_id AND w.id = c.work_id
3425
            WHERE
3426
                $sessionCondition AND
3427
                parent_id = $parentId AND
3428
                w.c_id = ".$courseInfo['real_id'];
3429
3430
    $result = Database::query($sql);
3431
    if (Database::num_rows($result)) {
3432
        $comment = Database::fetch_array($result);
3433
3434
        return $comment['count'];
3435
    }
3436
3437
    return 0;
3438
}
3439
3440
/**
3441
 * Get last work information from parent.
3442
 *
3443
 * @param int   $parentId
3444
 * @param array $courseInfo
3445
 * @param int   $sessionId
3446
 *
3447
 * @return int
3448
 */
3449
function getLastWorkStudentFromParent(
3450
    $parentId,
3451
    $courseInfo = [],
3452
    $sessionId = 0
3453
) {
3454
    if (empty($courseInfo)) {
3455
        $courseInfo = api_get_course_info();
3456
    }
3457
3458
    if (empty($sessionId)) {
3459
        $sessionId = api_get_session_id();
3460
    } else {
3461
        $sessionId = (int) $sessionId;
3462
    }
3463
3464
    $work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
3465
    $sessionCondition = api_get_session_condition($sessionId, false);
3466
    $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
3467
    $parentId = (int) $parentId;
3468
3469
    $sql = "SELECT w.*
3470
            FROM $commentTable c INNER JOIN $work w
3471
            ON c.c_id = w.c_id AND w.id = c.work_id
3472
            WHERE
3473
                $sessionCondition AND
3474
                parent_id = $parentId AND
3475
                w.c_id = ".$courseInfo['real_id'].'
3476
            ORDER BY w.sent_date
3477
            LIMIT 1
3478
            ';
3479
3480
    $result = Database::query($sql);
3481
    if (Database::num_rows($result)) {
3482
        return Database::fetch_array($result, 'ASSOC');
3483
    }
3484
3485
    return [];
3486
}
3487
3488
/**
3489
 * Get last work information from parent.
3490
 *
3491
 * @param int   $userId
3492
 * @param array $parentInfo
3493
 * @param array $courseInfo
3494
 * @param int   $sessionId
3495
 *
3496
 * @return int
3497
 */
3498
function getLastWorkStudentFromParentByUser(
3499
    $userId,
3500
    $parentInfo,
3501
    $courseInfo = [],
3502
    $sessionId = 0
3503
) {
3504
    if (empty($courseInfo)) {
3505
        $courseInfo = api_get_course_info();
3506
    }
3507
3508
    if (empty($sessionId)) {
3509
        $sessionId = api_get_session_id();
3510
    } else {
3511
        $sessionId = (int) $sessionId;
3512
    }
3513
3514
    $userId = (int) $userId;
3515
    $work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
3516
    if (empty($parentInfo)) {
3517
        return false;
3518
    }
3519
    $parentId = $parentInfo['id'];
3520
3521
    $sessionCondition = api_get_session_condition($sessionId);
3522
3523
    $sql = "SELECT *
3524
            FROM $work
3525
            WHERE
3526
                user_id = $userId
3527
                $sessionCondition AND
3528
                parent_id = $parentId AND
3529
                c_id = ".$courseInfo['real_id'].'
3530
            ORDER BY sent_date DESC
3531
            LIMIT 1
3532
            ';
3533
    $result = Database::query($sql);
3534
    if (Database::num_rows($result)) {
3535
        $work = Database::fetch_array($result, 'ASSOC');
3536
        $work['qualification_rounded'] = formatWorkScore($work['qualification'], $parentInfo['qualification']);
3537
3538
        return $work;
3539
    }
3540
3541
    return [];
3542
}
3543
3544
/**
3545
 * @param float $score
3546
 * @param int   $weight
3547
 *
3548
 * @return string
3549
 */
3550
function formatWorkScore($score, $weight)
3551
{
3552
    $label = 'info';
3553
    $weight = (int) $weight;
3554
    $relativeScore = 0;
3555
    if (!empty($weight)) {
3556
        $relativeScore = $score / $weight;
3557
    }
3558
3559
    if ($relativeScore < 0.5) {
3560
        $label = 'important';
3561
    } elseif ($relativeScore < 0.75) {
3562
        $label = 'warning';
3563
    }
3564
3565
    $scoreBasedInModel = ExerciseLib::convertScoreToModel($relativeScore * 100);
3566
    if (empty($scoreBasedInModel)) {
3567
        $finalScore = api_number_format($score, 1).' / '.$weight;
3568
3569
        return Display::label(
3570
            $finalScore,
3571
            $label
3572
        );
3573
    } else {
3574
        return $scoreBasedInModel;
3575
    }
3576
}
3577
3578
/**
3579
 * @param int   $id         comment id
3580
 * @param array $courseInfo
3581
 *
3582
 * @return string
3583
 */
3584
function getWorkComment($id, $courseInfo = [])
3585
{
3586
    if (empty($courseInfo)) {
3587
        $courseInfo = api_get_course_info();
3588
    }
3589
3590
    if (empty($courseInfo['real_id'])) {
3591
        return [];
3592
    }
3593
3594
    $repo = Container::getStudentPublicationCommentRepository();
3595
    $criteria = [
3596
        'id' => $id,
3597
        'cId' => $courseInfo['real_id'],
3598
    ];
3599
3600
    /** @var CStudentPublicationComment $commentEntity */
3601
    $commentEntity = $repo->findOneBy($criteria);
3602
3603
    $comment = [];
3604
    if ($commentEntity) {
3605
        $filePath = null;
3606
        $fileUrl = null;
3607
        $deleteUrl = null;
3608
        $fileName = null;
3609
        if ($commentEntity->getResourceNode()->hasResourceFile()) {
3610
            $fileUrl = $repo->getResourceFileDownloadUrl($commentEntity);
3611
            $workId = $commentEntity->getWorkId();
3612
            $filePath = '';
3613
            $deleteUrl = api_get_path(WEB_CODE_PATH).'work/view.php?'.api_get_cidreq().'&id='.$workId.'&action=delete_attachment&comment_id='.$id;
3614
            $fileName = $commentEntity->getResourceNode()->getResourceFile()->getName();
3615
        }
3616
        $comment['comment'] = $commentEntity->getComment();
3617
        $comment['delete_file_url'] = $deleteUrl;
3618
        $comment['file_path'] = $filePath;
3619
        $comment['file_url'] = $fileUrl;
3620
        $comment['file_name_to_show'] = $fileName;
3621
        $comment['sent_at_with_label'] = Display::dateToStringAgoAndLongDate($commentEntity->getSentAt());
3622
    }
3623
3624
    return $comment;
3625
}
3626
3627
/**
3628
 * @param int   $id
3629
 * @param array $courseInfo
3630
 */
3631
function deleteCommentFile($id, $courseInfo = [])
3632
{
3633
    $repo = Container::getStudentPublicationCommentRepository();
3634
    $criteria = [
3635
        'id' => $id,
3636
        'cId' => $courseInfo['real_id'],
3637
    ];
3638
3639
    /** @var CStudentPublicationComment $commentEntity */
3640
    $commentEntity = $repo->findOneBy($criteria);
3641
3642
    if ($commentEntity->getResourceNode()->hasResourceFile()) {
3643
        $file = $commentEntity->getResourceNode()->getResourceFile();
3644
3645
        $commentEntity->getResourceNode()->setResourceFile(null);
3646
        $repo->getEntityManager()->remove($file);
3647
        $repo->getEntityManager()->flush();
3648
    }
3649
3650
    /*
3651
    if (isset($workComment['file']) && !empty($workComment['file'])) {
3652
        if (file_exists($workComment['file_path'])) {
3653
            $result = my_delete($workComment['file_path']);
3654
            if ($result) {
3655
                $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
3656
                $params = ['file' => ''];
3657
                Database::update(
3658
                    $commentTable,
3659
                    $params,
3660
                    ['id = ? AND c_id = ? ' => [$workComment['id'], $workComment['c_id']]]
3661
                );
3662
            }
3663
        }
3664
    }*/
3665
}
3666
3667
/**
3668
 * Adds a comments to the work document.
3669
 *
3670
 * @param array $courseInfo
3671
 * @param int   $userId
3672
 * @param array $parentWork
3673
 * @param array $work
3674
 * @param array $data
3675
 *
3676
 * @return int
3677
 */
3678
function addWorkComment($courseInfo, $userId, $parentWork, $work, $data)
3679
{
3680
    $fileData = isset($data['attachment']) ? $data['attachment'] : null;
3681
    // If no attachment and no comment then don't save comment
3682
    if (empty($fileData['name']) && empty($data['comment'])) {
3683
        return false;
3684
    }
3685
    $courseId = $courseInfo['real_id'];
3686
    $courseEntity = api_get_course_entity($courseId);
3687
3688
    /** @var CStudentPublication $work */
3689
    $studentPublication = Container::getStudentPublicationRepository()->find($work['id']);
3690
3691
    $request = Container::getRequest();
3692
    $fileObject = $request->files->get('attachment');
3693
    if (is_array($fileObject)) {
3694
        $fileObject = $fileObject[0];
3695
    }
3696
3697
    $comment = new CStudentPublicationComment();
3698
    $comment
3699
        ->setCId($courseId)
3700
        ->setComment($data['comment'])
3701
        ->setUserId($userId)
3702
        ->setWorkId($work['id'])
3703
    ;
3704
3705
    $userEntity = api_get_user_entity(api_get_user_id());
3706
    $repo = Container::getStudentPublicationCommentRepository();
3707
    $em = $repo->getEntityManager();
3708
    $em->persist($comment);
3709
3710
    $resourceNode = $repo->addResourceNode($comment, $userEntity, $studentPublication);
3711
    $repo->addResourceNodeToCourse(
3712
        $resourceNode,
3713
        ResourceLink::VISIBILITY_PUBLISHED,
3714
        $courseEntity,
3715
        api_get_session_entity(),
3716
        api_get_group_entity()
3717
    );
3718
    $em->flush();
3719
3720
    $comment->setId($comment->getIid());
3721
    $em->persist($comment);
3722
    $em->flush();
3723
3724
    if ($fileObject) {
3725
        $repo->addFile($comment, $fileObject);
3726
        $em->flush();
3727
    }
3728
3729
    $userIdListToSend = [];
3730
    if (api_is_allowed_to_edit()) {
3731
        if (isset($data['send_email']) && $data['send_email']) {
3732
            // Teacher sends a feedback
3733
            $userIdListToSend = [$work['user_id']];
3734
        }
3735
    } else {
3736
        $sessionId = api_get_session_id();
3737
        if (empty($sessionId)) {
3738
            $teachers = CourseManager::get_teacher_list_from_course_code(
3739
                $courseInfo['code']
3740
            );
3741
            if (!empty($teachers)) {
3742
                $userIdListToSend = array_keys($teachers);
3743
            }
3744
        } else {
3745
            $teachers = SessionManager::getCoachesByCourseSession(
3746
                $sessionId,
3747
                $courseInfo['real_id']
3748
            );
3749
3750
            if (!empty($teachers)) {
3751
                $userIdListToSend = array_values($teachers);
3752
            }
3753
        }
3754
3755
        $sendNotification = api_get_course_setting('email_to_teachers_on_new_work_feedback');
3756
        if (1 != $sendNotification) {
3757
            $userIdListToSend = [];
3758
        }
3759
    }
3760
3761
    $url = api_get_path(WEB_CODE_PATH).'work/view.php?'.api_get_cidreq().'&id='.$work['id'];
3762
    $subject = sprintf(get_lang('There\'s a new feedback in work: %s'), $parentWork['title']);
3763
    $content = sprintf(get_lang('There\'s a new feedback in work: %sInWorkXHere'), $work['title'], $url);
3764
3765
    if (!empty($data['comment'])) {
3766
        $content .= '<br /><b>'.get_lang('Comment').':</b><br />'.$data['comment'];
3767
    }
3768
3769
    if (!empty($userIdListToSend)) {
3770
        foreach ($userIdListToSend as $userIdToSend) {
3771
            MessageManager::send_message_simple(
3772
                $userIdToSend,
3773
                $subject,
3774
                $content
3775
            );
3776
        }
3777
    }
3778
3779
    /*if (!empty($commentId) && !empty($fileData)) {
3780
        $workParent = get_work_data_by_id($work['parent_id']);
3781
        if (!empty($workParent)) {
3782
            //$newFileName = 'comment_'.$commentId.'_'.php2phps(api_replace_dangerous_char($fileData['name']));
3783
            //$newFilePath = $uploadDir.'/'.$newFileName;
3784
            $result = move_uploaded_file($fileData['tmp_name'], $newFilePath);
3785
            if ($result) {
3786
                $params = ['file' => $newFileName];
3787
                Database::update(
3788
                    $commentTable,
3789
                    $params,
3790
                    ['id = ? AND c_id = ? ' => [$commentId, $work['c_id']]]
3791
                );
3792
            }
3793
        }
3794
    }*/
3795
}
3796
3797
/**
3798
 * @param array $work
3799
 * @param array $workParent
3800
 *
3801
 * @return string
3802
 */
3803
function getWorkCommentForm($work, $workParent)
3804
{
3805
    $url = api_get_path(WEB_CODE_PATH).'work/view.php?id='.$work['id'].'&action=send_comment&'.api_get_cidreq();
3806
    $form = new FormValidator(
3807
        'work_comment',
3808
        'post',
3809
        $url,
3810
        '',
3811
        ['enctype' => 'multipart/form-data']
3812
    );
3813
3814
    $qualification = $workParent['qualification'];
3815
3816
    $isCourseManager = api_is_platform_admin() || api_is_coach() || api_is_allowed_to_edit(false, false, true);
3817
    $allowEdition = false;
3818
    if ($isCourseManager) {
3819
        $allowEdition = true;
3820
        if (!empty($work['qualification']) && api_get_configuration_value('block_student_publication_score_edition')) {
3821
            $allowEdition = false;
3822
        }
3823
    }
3824
3825
    if (api_is_platform_admin()) {
3826
        $allowEdition = true;
3827
    }
3828
3829
    if ($allowEdition) {
3830
        if (!empty($qualification) && intval($qualification) > 0) {
3831
            $model = ExerciseLib::getCourseScoreModel();
3832
            if (empty($model)) {
3833
                $form->addFloat(
3834
                    'qualification',
3835
                    [get_lang('Score'), ' / '.$qualification],
3836
                    false,
3837
                    [],
3838
                    false,
3839
                    0,
3840
                    $qualification
3841
                );
3842
            } else {
3843
                ExerciseLib::addScoreModelInput(
3844
                    $form,
3845
                    'qualification',
3846
                    $qualification,
3847
                    $work['qualification']
3848
                );
3849
            }
3850
            $form->addFile('file', get_lang('Correction'));
3851
            $form->setDefaults(['qualification' => $work['qualification']]);
3852
        }
3853
    }
3854
3855
    Skill::addSkillsToUserForm($form, ITEM_TYPE_STUDENT_PUBLICATION, $workParent['id'], $work['user_id'], $work['id']);
3856
    $form->addHtmlEditor('comment', get_lang('Comment'), false);
3857
    $form->addFile('attachment', get_lang('Attachment'));
3858
    $form->addElement('hidden', 'id', $work['id']);
3859
3860
    if (api_is_allowed_to_edit()) {
3861
        $form->addCheckBox(
3862
            'send_email',
3863
            null,
3864
            get_lang('Send message mail to student')
3865
        );
3866
    }
3867
3868
    $form->addButtonSend(get_lang('Send'), 'button');
3869
3870
    return $form->returnForm();
3871
}
3872
3873
/**
3874
 * @param array $homework result of get_work_assignment_by_id()
3875
 *
3876
 * @return array
3877
 */
3878
function getWorkDateValidationStatus($homework)
3879
{
3880
    $message = null;
3881
    $has_expired = false;
3882
    $has_ended = false;
3883
3884
    if (!empty($homework)) {
3885
        if (!empty($homework['expires_on']) || !empty($homework['ends_on'])) {
3886
            $time_now = time();
3887
3888
            if (!empty($homework['expires_on'])) {
3889
                $time_expires = api_strtotime($homework['expires_on'], 'UTC');
3890
                $difference = $time_expires - $time_now;
3891
                if ($difference < 0) {
3892
                    $has_expired = true;
3893
                }
3894
            }
3895
3896
            if (empty($homework['expires_on'])) {
3897
                $has_expired = false;
3898
            }
3899
3900
            if (!empty($homework['ends_on'])) {
3901
                $time_ends = api_strtotime($homework['ends_on'], 'UTC');
3902
                $difference2 = $time_ends - $time_now;
3903
                if ($difference2 < 0) {
3904
                    $has_ended = true;
3905
                }
3906
            }
3907
3908
            $ends_on = api_convert_and_format_date($homework['ends_on']);
3909
            $expires_on = api_convert_and_format_date($homework['expires_on']);
3910
        }
3911
3912
        if ($has_ended) {
3913
            $message = Display::return_message(get_lang('End date already passed').' '.$ends_on, 'error');
3914
        } elseif ($has_expired) {
3915
            $message = Display::return_message(get_lang('Expiry date already passed').' '.$expires_on, 'warning');
3916
        } else {
3917
            if ($has_expired) {
3918
                $message = Display::return_message(get_lang('ExpiryDateToSend messageWorkIs').' '.$expires_on);
3919
            }
3920
        }
3921
    }
3922
3923
    return [
3924
        'message' => $message,
3925
        'has_ended' => $has_ended,
3926
        'has_expired' => $has_expired,
3927
    ];
3928
}
3929
3930
/**
3931
 * @param FormValidator $form
3932
 * @param int           $uploadFormType
3933
 */
3934
function setWorkUploadForm($form, $uploadFormType = 0)
3935
{
3936
    $form->addHeader(get_lang('Upload a document'));
3937
    $form->addHidden('contains_file', 0, ['id' => 'contains_file_id']);
3938
    $form->addHidden('active', 1);
3939
    $form->addHidden('accepted', 1);
3940
    $form->addElement('text', 'title', get_lang('Title'), ['id' => 'file_upload']);
3941
    $form->addElement(
3942
        'text',
3943
        'extension',
3944
        get_lang('File extension'),
3945
        ['id' => 'file_extension', 'readonly' => 'readonly']
3946
    );
3947
    $form->addRule('title', get_lang('Required field'), 'required');
3948
3949
    switch ($uploadFormType) {
3950
        case 0:
3951
            // File and text.
3952
            $form->addElement(
3953
                'file',
3954
                'file',
3955
                get_lang('Upload a document'),
3956
                'size="40" onchange="updateDocumentTitle(this.value)"'
3957
            );
3958
            $form->addProgress();
3959
            $form->addHtmlEditor('description', get_lang('Description'), false, false, getWorkDescriptionToolbar());
3960
3961
            break;
3962
        case 1:
3963
            // Only text.
3964
            $form->addHtmlEditor('description', get_lang('Description'), false, false, getWorkDescriptionToolbar());
3965
            $form->addRule('description', get_lang('Required field'), 'required');
3966
3967
            break;
3968
        case 2:
3969
            // Only file.
3970
            $form->addElement(
3971
                'file',
3972
                'file',
3973
                get_lang('Upload a document'),
3974
                'size="40" onchange="updateDocumentTitle(this.value)"'
3975
            );
3976
            $form->addProgress();
3977
            $form->addRule('file', get_lang('Required field'), 'required');
3978
3979
            break;
3980
    }
3981
3982
    $form->addButtonUpload(get_lang('Upload'), 'submitWork');
3983
}
3984
3985
/**
3986
 * @param array $my_folder_data
3987
 * @param array $_course
3988
 * @param bool  $isCorrection
3989
 * @param array $workInfo
3990
 * @param array $file
3991
 *
3992
 * @return array
3993
 */
3994
function uploadWork($my_folder_data, $_course, $isCorrection = false, $workInfo = [], $file = [])
3995
{
3996
    if (isset($_FILES['file']) && !empty($_FILES['file'])) {
3997
        $file = $_FILES['file'];
3998
    }
3999
4000
    if (empty($file['size'])) {
4001
        return [
4002
            'error' => Display:: return_message(
4003
                get_lang('There was a problem uploading your document: the received file had a 0 bytes size on the server. Please, review your local file for any corruption or damage, then try again.'),
4004
                'error'
4005
            ),
4006
        ];
4007
    }
4008
    //$updir = api_get_path(SYS_COURSE_PATH).$_course['path'].'/work/'; //directory path to upload
4009
4010
    // Try to add an extension to the file if it has'nt one
4011
    $filename = add_ext_on_mime(stripslashes($file['name']), $file['type']);
4012
4013
    // Replace dangerous characters
4014
    $filename = api_replace_dangerous_char($filename);
4015
    //$filename = api_replace_dangerous_char($filename);
4016
4017
    $filename = php2phps($filename);
4018
    $filesize = filesize($file['tmp_name']);
4019
4020
    if (empty($filesize)) {
4021
        return [
4022
            'error' => Display::return_message(
4023
                get_lang('There was a problem uploading your document: the received file had a 0 bytes size on the server. Please, review your local file for any corruption or damage, then try again.'),
4024
                'error'
4025
            ),
4026
        ];
4027
    } elseif (!filter_extension($new_file_name)) {
4028
        return [
4029
            'error' => Display::return_message(
4030
                get_lang('File upload failed: this file extension or file type is prohibited'),
4031
                'error'
4032
            ),
4033
        ];
4034
    }
4035
4036
    $repo = Container::getDocumentRepository();
4037
    $totalSpace = $repo->getTotalSpace($_course['real_id']);
4038
    $course_max_space = DocumentManager::get_course_quota($_course['code']);
4039
    $total_size = $filesize + $totalSpace;
4040
4041
    if ($total_size > $course_max_space) {
4042
        return [
4043
            'error' => Display::return_message(get_lang('The upload has failed. Either you have exceeded your maximum quota, or there is not enough disk space.'), 'error'),
4044
        ];
4045
    }
4046
4047
    // Compose a unique file name to avoid any conflict
4048
    $new_file_name = api_get_unique_id();
4049
4050
    if ($isCorrection) {
4051
        if (!empty($workInfo['url'])) {
4052
            $new_file_name = basename($workInfo['url']).'_correction';
4053
        } else {
4054
            $new_file_name .= '_correction';
4055
        }
4056
    }
4057
4058
    //$curdirpath = basename($my_folder_data['url']);
4059
    // If we come from the group tools the groupid will be saved in $work_table
4060
    /*if (is_dir($updir.$curdirpath) || empty($curdirpath)) {
4061
        $result = move_uploaded_file(
4062
            $file['tmp_name'],
4063
            $updir.$curdirpath.'/'.$new_file_name
4064
        );
4065
    } else {
4066
        return [
4067
            'error' => Display :: return_message(
4068
                get_lang('Target folder doesn\'t exist on the server.'),
4069
                'error'
4070
            ),
4071
        ];
4072
    }*/
4073
4074
    /*if ($result) {
4075
        //$url = 'work/'.$curdirpath.'/'.$new_file_name;
4076
    } else {
4077
        return false;
4078
    }*/
4079
4080
    return [
4081
        //'url' => $url,
4082
        'filename' => $filename,
4083
        'filesize' => $filesize,
4084
        'error' => '',
4085
        'file' => $file,
4086
    ];
4087
}
4088
4089
/**
4090
 * Send an e-mail to users related to this work.
4091
 *
4092
 * @param array $workInfo
4093
 * @param int   $workId
4094
 * @param array $courseInfo
4095
 * @param int   $sessionId
4096
 */
4097
function sendAlertToUsers($workInfo, $workId, $courseInfo, $sessionId = 0)
4098
{
4099
    $sessionId = (int) $sessionId;
4100
4101
    if (empty($workInfo) || empty($courseInfo) || empty($workId)) {
4102
        return false;
4103
    }
4104
4105
    $courseCode = $courseInfo['code'];
4106
4107
    $workData = get_work_data_by_id($workId, $courseInfo['real_id'], $sessionId);
4108
    // last value is to check this is not "just" an edit
4109
    // YW Tis part serve to send a e-mail to the tutors when a new file is sent
4110
    $send = api_get_course_setting('email_alert_manager_on_new_doc');
4111
4112
    $userList = [];
4113
    if (SEND_EMAIL_EVERYONE == $send || SEND_EMAIL_TEACHERS == $send) {
4114
        // Lets predefine some variables. Be sure to change the from address!
4115
        if (empty($sessionId)) {
4116
            // Teachers
4117
            $userList = CourseManager::get_user_list_from_course_code(
4118
                $courseCode,
4119
                null,
4120
                null,
4121
                null,
4122
                COURSEMANAGER
4123
            );
4124
        } else {
4125
            // Coaches
4126
            $userList = CourseManager::get_user_list_from_course_code(
4127
                $courseCode,
4128
                $sessionId,
4129
                null,
4130
                null,
4131
                2
4132
            );
4133
        }
4134
    }
4135
4136
    if ($send == SEND_EMAIL_EVERYONE || $send == SEND_EMAIL_STUDENTS) {
4137
        // Send mail only to sender
4138
        $studentList = [[
4139
           'user_id' => api_get_user_id(),
4140
        ]];
4141
        $userList = array_merge($userList, $studentList);
4142
    }
4143
4144
    if ($send) {
4145
        $folderUrl = api_get_path(WEB_CODE_PATH)."work/work_list_all.php?cidReq=".$courseInfo['code']."&id_session=".$sessionId."&id=".$workInfo['id'];
4146
        $fileUrl = api_get_path(WEB_CODE_PATH)."work/view.php?cidReq=".$courseInfo['code']."&id_session=".$sessionId."&id=".$workData['id'];
4147
4148
        foreach ($userList as $userData) {
4149
            $userId = $userData['user_id'];
4150
            $userInfo = api_get_user_info($userId);
4151
            if (empty($userInfo)) {
4152
                continue;
4153
            }
4154
4155
            $userPostedADocument = sprintf(
4156
                get_lang('UserXPostedADocumentInCourseX'),
4157
                $userInfo['complete_name'],
4158
                $courseInfo['name']
4159
            );
4160
4161
            $subject = "[".api_get_setting('siteName')."] ".$userPostedADocument;
4162
            $message = $userPostedADocument."<br />";
4163
            $message .= get_lang('DateSent')." : ".api_format_date(api_get_local_time())."<br />";
4164
            $message .= get_lang('AssignmentName')." : ".Display::url($workInfo['title'], $folderUrl)."<br />";
4165
            $message .= get_lang('Filename')." : ".$workData['title']."<br />";
4166
            $message .= '<a href="'.$fileUrl.'">'.get_lang('DownloadLink')."</a><br />";
4167
4168
            MessageManager::send_message_simple(
4169
                $userId,
4170
                $subject,
4171
                $message,
4172
                0,
4173
                false,
4174
                false,
4175
                [],
4176
                false
4177
            );
4178
        }
4179
    }
4180
}
4181
4182
/**
4183
 * Check if the current uploaded work filename already exists in the current assement.
4184
 *
4185
 * @param string $filename
4186
 * @param int    $workId
4187
 *
4188
 * @return array
4189
 */
4190
function checkExistingWorkFileName($filename, $workId)
4191
{
4192
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
4193
    $filename = Database::escape_string($filename);
4194
    $workId = (int) $workId;
4195
4196
    $sql = "SELECT title FROM $table
4197
            WHERE parent_id = $workId AND title = '$filename' AND active = 1";
4198
    $result = Database::query($sql);
4199
4200
    return Database::fetch_assoc($result);
4201
}
4202
4203
/**
4204
 * @param array $workInfo
4205
 * @param array $values
4206
 * @param array $courseInfo
4207
 * @param int   $sessionId
4208
 * @param int   $groupId
4209
 * @param int   $userId
4210
 * @param array $file
4211
 * @param bool  $checkDuplicated
4212
 * @param bool  $showFlashMessage
4213
 *
4214
 * @return string|null
4215
 */
4216
function processWorkForm(
4217
    $workInfo,
4218
    $values,
4219
    $courseInfo,
4220
    $sessionId,
4221
    $groupId,
4222
    $userId,
4223
    $file = [],
4224
    $checkDuplicated = false,
4225
    $showFlashMessage = true
4226
) {
4227
    $courseId = $courseInfo['real_id'];
4228
    $groupId = (int) $groupId;
4229
    $sessionId = (int) $sessionId;
4230
    $userId = (int) $userId;
4231
4232
    $extension = '';
4233
    if (isset($values['extension'])) {
4234
        $extension = $values['extension'];
4235
    } else {
4236
        $fileInfo = pathinfo($values['title']);
4237
        if (isset($fileInfo['extension']) && !empty($fileInfo['extension'])) {
4238
            $extension = '.'.$fileInfo['extension'];
4239
            $values['title'] = $fileInfo['filename'];
4240
        }
4241
    }
4242
4243
    $title = $values['title'].$extension;
4244
    $description = isset($values['description']) ? $values['description'] : '';
4245
    $containsFile = isset($values['contains_file']) && !empty($values['contains_file']) ? (int) $values['contains_file'] : 0;
4246
4247
    $saveWork = true;
4248
    $filename = null;
4249
    $url = null;
4250
    $filesize = null;
4251
    $workData = [];
4252
    $message = null;
4253
4254
    if ($containsFile) {
4255
        $saveWork = false;
4256
        if ($checkDuplicated) {
4257
            if (checkExistingWorkFileName($file['name'], $workInfo['id'])) {
4258
                $saveWork = false;
4259
                $result['error'] = get_lang('You have already sent this file or another file with the same name. Please make sure you only upload each file once.');
4260
                $workData['error'] = get_lang(' already exists.');
4261
            } else {
4262
                $result = uploadWork($workInfo, $courseInfo, false, [], $file);
4263
            }
4264
        } else {
4265
            $result = uploadWork($workInfo, $courseInfo, false, [], $file);
4266
        }
4267
4268
        if (isset($result['error'])) {
4269
            $saveWork = false;
4270
            if ($showFlashMessage) {
4271
                $message = $result['error'];
4272
            }
4273
            if (empty($result['error'])) {
4274
                $saveWork = true;
4275
            }
4276
        }
4277
    }
4278
4279
    if ($saveWork) {
4280
        $filename = isset($result['filename']) ? $result['filename'] : null;
4281
        if (empty($title)) {
4282
            $title = isset($result['title']) && !empty($result['title']) ? $result['title'] : get_lang('Untitled');
4283
        }
4284
        $filesize = isset($result['filesize']) ? $result['filesize'] : null;
4285
        $url = isset($result['url']) ? $result['url'] : null;
4286
    }
4287
4288
    if (empty($title)) {
4289
        $title = get_lang('Untitled');
4290
    }
4291
4292
    $groupIid = 0;
4293
    $groupInfo = [];
4294
    if ($groupId) {
4295
        $groupInfo = GroupManager::get_group_properties($groupId);
4296
        $groupIid = $groupInfo['iid'];
4297
    }
4298
4299
    if ($saveWork) {
4300
        $documentId = isset($values['document_id']) ? (int) $values['document_id'] : 0;
4301
4302
        $request = Container::getRequest();
4303
        $content = $request->files->get('file');
4304
        if (is_array($content)) {
4305
            $content = $content[0];
4306
        }
4307
4308
        if (empty($content)) {
4309
            $content = $request->files->get('files');
4310
            if (is_array($content)) {
4311
                $content = $content[0];
4312
            }
4313
        }
4314
4315
        $session = api_get_session_entity($sessionId);
4316
        $courseEntity = api_get_course_entity($courseId);
4317
4318
        $repo = Container::getStudentPublicationRepository();
4319
        $parentResource = $repo->find($workInfo['id']);
4320
4321
        $studentPublication = new CStudentPublication();
4322
        $studentPublication
4323
            ->setCId($courseId)
4324
            //->setUrl($url)
4325
            ->setFiletype('file')
4326
            ->setTitle($title)
4327
            ->setDescription($description)
4328
            ->setContainsFile($containsFile)
4329
            ->setActive(1)
4330
            ->setAccepted(1)
4331
            ->setQualificatorId(0)
4332
            ->setWeight(0)
4333
            ->setAllowTextAssignment(0)
4334
            ->setPostGroupId($groupIid)
4335
            ->setParentId($workInfo['id'])
4336
            ->setSession(api_get_session_entity($sessionId))
4337
            ->setFilesize($filesize)
4338
            ->setUserId($userId)
4339
            ->setDocumentId($documentId)
4340
            ->setParent($parentResource)
4341
            ->addCourseLink($courseEntity, $session, api_get_group_entity())
4342
        ;
4343
4344
        $em = $repo->getEntityManager();
4345
        $em->persist($studentPublication);
4346
        $repo->addFile($studentPublication, $content);
4347
        $em->flush();
4348
4349
        $workId = $studentPublication->getIid();
4350
4351
        if ($workId) {
4352
            $studentPublication->setId($studentPublication->getIid());
4353
4354
            /*if (array_key_exists('filename', $workInfo) && !empty($filename)) {
4355
                $filename = Database::escape_string($filename);
4356
                $sql = "UPDATE $work_table SET
4357
                            filename = '$filename'
4358
                        WHERE iid = $workId";
4359
                Database::query($sql);
4360
            }*/
4361
4362
            sendAlertToUsers($workInfo, $workId, $courseInfo, $sessionId);
4363
            Event::event_upload($workId);
4364
4365
            // The following feature requires the creation of a work-type
4366
            // extra_field and the following setting in the configuration file
4367
            // (until moved to the database). It allows te teacher to set a
4368
            // "considered work time", meaning the time we assume a student
4369
            // would have spent, approximately, to prepare the task before
4370
            // handing it in Chamilo, adding this time to the student total
4371
            // course use time, as a register of time spent *before* his
4372
            // connection to the platform to hand the work in.
4373
            $consideredWorkingTime = api_get_configuration_value('considered_working_time');
4374
4375
            if (!empty($consideredWorkingTime)) {
4376
                // Get the "considered work time" defined for this work
4377
                $fieldValue = new ExtraFieldValue('work');
4378
                $resultExtra = $fieldValue->getAllValuesForAnItem(
4379
                    $workInfo['iid'], //the ID of the work *folder*, not the document uploaded by the student
4380
                    true
4381
                );
4382
4383
                $workingTime = null;
4384
                foreach ($resultExtra as $field) {
4385
                    $field = $field['value'];
4386
                    if ($consideredWorkingTime == $field->getField()->getVariable()) {
4387
                        $workingTime = $field->getValue();
4388
                    }
4389
                }
4390
4391
                // If no time was defined, or a time of "0" was set, do nothing
4392
                if (!empty($workingTime)) {
4393
                    // If some time is set, get the list of docs handed in by
4394
                    // this student (to make sure we count the time only once)
4395
                    $userWorks = get_work_user_list(
4396
                        0,
4397
                        100,
4398
                        null,
4399
                        null,
4400
                        $workInfo['id'],
4401
                        null,
4402
                        $userId,
4403
                        false,
4404
                        $courseId,
4405
                        $sessionId
4406
                    );
4407
4408
                    if (1 == count($userWorks)) {
4409
                        // The student only uploaded one doc so far, so add the
4410
                        // considered work time to his course connection time
4411
                        Event::eventAddVirtualCourseTime(
4412
                            $courseId,
4413
                            $userId,
4414
                            $sessionId,
4415
                            $workingTime,
4416
                            $workInfo['iid']
4417
                        );
4418
                    }
4419
                }
4420
            }
4421
            $workData = get_work_data_by_id($workId);
4422
            if ($workData && $showFlashMessage) {
4423
                Display::addFlash(Display::return_message(get_lang('The file has been added to the list of publications.')));
4424
            }
4425
        }
4426
    } else {
4427
        if ($showFlashMessage) {
4428
            Display::addFlash(
4429
                Display::return_message(
4430
                    $message ?: get_lang('Impossible to save the document'),
4431
                    'error'
4432
                )
4433
            );
4434
        }
4435
    }
4436
4437
    return $workData;
4438
}
4439
4440
/**
4441
 * Creates a new task (directory) in the assignment tool.
4442
 *
4443
 * @param array $formValues
4444
 * @param int   $user_id
4445
 * @param array $courseInfo
4446
 * @param int   $groupId
4447
 * @param int   $sessionId
4448
 *
4449
 * @return bool|int
4450
 * @note $params can have the following elements, but should at least have the 2 first ones: (
4451
 *       'new_dir' => 'some-name',
4452
 *       'description' => 'some-desc',
4453
 *       'qualification' => 20 (e.g. 20),
4454
 *       'weight' => 50 (percentage) to add to gradebook (e.g. 50),
4455
 *       'allow_text_assignment' => 0/1/2,
4456
 *
4457
 * @todo Rename createAssignment or createWork, or something like that
4458
 */
4459
function addDir($formValues, $user_id, $courseInfo, $groupId, $sessionId = 0)
4460
{
4461
    $user_id = (int) $user_id;
4462
    $groupId = (int) $groupId;
4463
    $sessionId = (int) $sessionId;
4464
4465
    $groupIid = 0;
4466
    $groupInfo = [];
4467
    if (!empty($groupId)) {
4468
        $groupInfo = GroupManager::get_group_properties($groupId);
4469
        $groupIid = $groupInfo['iid'];
4470
    }
4471
    $session = api_get_session_entity($sessionId);
4472
    $course_id = $courseInfo['real_id'];
4473
4474
    $enableEndDate = isset($formValues['enableEndDate']) ? true : false;
4475
    $enableExpiryDate = isset($formValues['enableExpiryDate']) ? true : false;
4476
4477
    if ($enableEndDate && $enableExpiryDate) {
4478
        if ($formValues['expires_on'] > $formValues['ends_on']) {
4479
            Display::addFlash(
4480
                Display::return_message(
4481
                    get_lang('The date of effective blocking of sending the work can not be before the displayed posting deadline.'),
4482
                    'warning'
4483
                )
4484
            );
4485
4486
            return false;
4487
        }
4488
    }
4489
4490
    $today = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
4491
    $title = isset($formValues['work_title']) ? $formValues['work_title'] : $formValues['new_dir'];
4492
    $courseEntity = api_get_course_entity($course_id);
4493
4494
    $studentPublication = new CStudentPublication();
4495
    $studentPublication
4496
        ->setCId($course_id)
4497
        ->setTitle($title)
4498
        ->setDescription($formValues['description'])
4499
        ->setActive(true)
4500
        ->setAccepted(true)
4501
        ->setFiletype('folder')
4502
        ->setPostGroupId($groupIid)
4503
        ->setSentDate($today)
4504
        ->setQualification('' != $formValues['qualification'] ? $formValues['qualification'] : 0)
4505
        ->setWeight(!empty($formValues['weight']) ? $formValues['weight'] : 0)
4506
        ->setSession($session)
4507
        ->setAllowTextAssignment($formValues['allow_text_assignment'])
4508
        ->setUserId($user_id)
4509
        ->setParent($courseEntity)
4510
        ->addCourseLink(
4511
            $courseEntity,
4512
            api_get_session_entity(),
4513
            api_get_group_entity()
4514
        )
4515
    ;
4516
4517
    $repo = Container::getStudentPublicationRepository();
4518
    $em = $repo->getEntityManager();
4519
    $em->persist($studentPublication);
4520
    $em->flush();
4521
4522
    $studentPublication->setId($studentPublication->getIid());
4523
    $em->persist($studentPublication);
4524
    $em->flush();
4525
4526
    // Folder created
4527
    /*api_item_property_update(
4528
        $courseInfo,
4529
        'work',
4530
        $studentPublication->getIid(),
4531
        'DirectoryCreated',
4532
        $user_id,
4533
        $groupInfo
4534
    );
4535
4536
    updatePublicationAssignment(
4537
        $studentPublication->getIid(),
4538
        $formValues,
4539
        $courseInfo,
4540
        $groupIid
4541
    );*/
4542
4543
    // Added the new Work ID to the extra field values
4544
    $formValues['item_id'] = $studentPublication->getIid();
4545
4546
    $workFieldValue = new ExtraFieldValue('work');
4547
    $workFieldValue->saveFieldValues($formValues);
4548
4549
    $sendEmailAlert = api_get_course_setting('email_alert_students_on_new_homework');
4550
4551
    switch ($sendEmailAlert) {
4552
        case 1:
4553
            sendEmailToStudentsOnHomeworkCreation(
4554
                $studentPublication->getIid(),
4555
                $course_id,
4556
                $sessionId
4557
            );
4558
            //no break
4559
        case 2:
4560
            sendEmailToDrhOnHomeworkCreation(
4561
                $studentPublication->getIid(),
4562
                $course_id,
4563
                $sessionId
4564
            );
4565
4566
            break;
4567
    }
4568
4569
    return $studentPublication->getIid();
4570
}
4571
4572
/**
4573
 * @param int   $workId
4574
 * @param array $courseInfo
4575
 *
4576
 * @return int
4577
 */
4578
function agendaExistsForWork($workId, $courseInfo)
4579
{
4580
    $workTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
4581
    $courseId = $courseInfo['real_id'];
4582
    $workId = (int) $workId;
4583
4584
    $sql = "SELECT add_to_calendar FROM $workTable
4585
            WHERE c_id = $courseId AND publication_id = ".$workId;
4586
    $res = Database::query($sql);
4587
    if (Database::num_rows($res)) {
4588
        $row = Database::fetch_array($res, 'ASSOC');
4589
        if (!empty($row['add_to_calendar'])) {
4590
            return $row['add_to_calendar'];
4591
        }
4592
    }
4593
4594
    return 0;
4595
}
4596
4597
/**
4598
 * Update work description, qualification, weight, allow_text_assignment.
4599
 *
4600
 * @param int   $workId     (iid)
4601
 * @param array $params
4602
 * @param array $courseInfo
4603
 * @param int   $sessionId
4604
 */
4605
function updateWork($workId, $params, $courseInfo, $sessionId = 0)
4606
{
4607
    $workTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
4608
    $filteredParams = [
4609
        'description' => $params['description'],
4610
        'qualification' => $params['qualification'],
4611
        'weight' => (float) $params['weight'],
4612
        'allow_text_assignment' => $params['allow_text_assignment'],
4613
    ];
4614
4615
    Database::update(
4616
        $workTable,
4617
        $filteredParams,
4618
        [
4619
            'iid = ? AND c_id = ?' => [
4620
                $workId,
4621
                $courseInfo['real_id'],
4622
            ],
4623
        ]
4624
    );
4625
4626
    $workFieldValue = new ExtraFieldValue('work');
4627
    $workFieldValue->saveFieldValues($params);
4628
}
4629
4630
/**
4631
 * @param int   $workId
4632
 * @param array $params
4633
 * @param array $courseInfo
4634
 * @param int   $groupId
4635
 */
4636
function updatePublicationAssignment($workId, $params, $courseInfo, $groupId)
4637
{
4638
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
4639
    $workTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
4640
    $workId = (int) $workId;
4641
    $now = api_get_utc_datetime();
4642
    $course_id = $courseInfo['real_id'];
4643
4644
    // Insert into agenda
4645
    $agendaId = 0;
4646
    if (isset($params['add_to_calendar']) && 1 == $params['add_to_calendar']) {
4647
        // Setting today date
4648
        $date = $end_date = $now;
4649
4650
        if (isset($params['enableExpiryDate'])) {
4651
            $end_date = $params['expires_on'];
4652
            $date = $end_date;
4653
        }
4654
4655
        $title = sprintf(get_lang('Handing over of task %s'), $params['new_dir']);
4656
        $description = isset($params['description']) ? $params['description'] : '';
4657
        $content = '<a href="'.api_get_path(WEB_CODE_PATH).'work/work_list.php?'.api_get_cidreq().'&id='.$workId.'">'
4658
            .$params['new_dir'].'</a>'.$description;
4659
4660
        $agendaId = agendaExistsForWork($workId, $courseInfo);
4661
4662
        // Add/edit agenda
4663
        $agenda = new Agenda('course');
4664
        $agenda->set_course($courseInfo);
4665
4666
        if (!empty($agendaId)) {
4667
            // add_to_calendar is set but it doesnt exists then invalidate
4668
            $eventInfo = $agenda->get_event($agendaId);
4669
            if (empty($eventInfo)) {
4670
                $agendaId = 0;
4671
            }
4672
        }
4673
4674
        $eventColor = $agenda->eventStudentPublicationColor;
4675
4676
        if (empty($agendaId)) {
4677
            $agendaId = $agenda->addEvent(
4678
                $date,
4679
                $end_date,
4680
                'false',
4681
                $title,
4682
                $content,
4683
                ['GROUP:'.$groupId],
4684
                false,
4685
                null,
4686
                [],
4687
                [],
4688
                null,
4689
                $eventColor
4690
            );
4691
        } else {
4692
            $agenda->editEvent(
4693
                $agendaId,
4694
                $end_date,
4695
                $end_date,
4696
                'false',
4697
                $title,
4698
                $content,
4699
                [],
4700
                [],
4701
                [],
4702
                null,
4703
                $eventColor
4704
            );
4705
        }
4706
    }
4707
4708
    $qualification = isset($params['qualification']) && !empty($params['qualification']) ? 1 : 0;
4709
    $expiryDate = isset($params['enableExpiryDate']) && 1 == (int) $params['enableExpiryDate'] ? api_get_utc_datetime($params['expires_on']) : '';
4710
    $endDate = isset($params['enableEndDate']) && 1 == (int) $params['enableEndDate'] ? api_get_utc_datetime($params['ends_on']) : '';
4711
    $data = get_work_assignment_by_id($workId, $course_id);
4712
    if (!empty($expiryDate)) {
4713
        $expiryDateCondition = "expires_on = '".Database::escape_string($expiryDate)."', ";
4714
    } else {
4715
        $expiryDateCondition = 'expires_on = null, ';
4716
    }
4717
4718
    if (!empty($endDate)) {
4719
        $endOnCondition = "ends_on = '".Database::escape_string($endDate)."', ";
4720
    } else {
4721
        $endOnCondition = 'ends_on = null, ';
4722
    }
4723
4724
    if (empty($data)) {
4725
        $sql = "INSERT INTO $table SET
4726
                c_id = $course_id ,
4727
                $expiryDateCondition
4728
                $endOnCondition
4729
                add_to_calendar = $agendaId,
4730
                enable_qualification = '$qualification',
4731
                publication_id = '$workId'";
4732
        Database::query($sql);
4733
        $my_last_id = Database::insert_id();
4734
4735
        if ($my_last_id) {
4736
            $sql = "UPDATE $table SET
4737
                        id = iid
4738
                    WHERE iid = $my_last_id";
4739
            Database::query($sql);
4740
4741
            $sql = "UPDATE $workTable SET
4742
                        has_properties  = $my_last_id,
4743
                        view_properties = 1
4744
                    WHERE c_id = $course_id AND id = $workId";
4745
            Database::query($sql);
4746
        }
4747
    } else {
4748
        $sql = "UPDATE $table SET
4749
                    $expiryDateCondition
4750
                    $endOnCondition
4751
                    add_to_calendar  = $agendaId,
4752
                    enable_qualification = '".$qualification."'
4753
                WHERE
4754
                    publication_id = $workId AND
4755
                    c_id = $course_id AND
4756
                    iid = ".$data['iid'];
4757
        Database::query($sql);
4758
    }
4759
4760
    if (!empty($params['category_id'])) {
4761
        $link_info = GradebookUtils::isResourceInCourseGradebook(
4762
            $courseInfo['code'],
4763
            LINK_STUDENTPUBLICATION,
4764
            $workId,
4765
            api_get_session_id()
4766
        );
4767
4768
        $linkId = null;
4769
        if (!empty($link_info)) {
4770
            $linkId = $link_info['id'];
4771
        }
4772
4773
        if (isset($params['make_calification']) &&
4774
            1 == $params['make_calification']
4775
        ) {
4776
            if (empty($linkId)) {
4777
                GradebookUtils::add_resource_to_course_gradebook(
4778
                    $params['category_id'],
4779
                    $courseInfo['code'],
4780
                    LINK_STUDENTPUBLICATION,
4781
                    $workId,
4782
                    $params['new_dir'],
4783
                    api_float_val($params['weight']),
4784
                    api_float_val($params['qualification']),
4785
                    $params['description'],
4786
                    1,
4787
                    api_get_session_id()
4788
                );
4789
            } else {
4790
                GradebookUtils::updateResourceFromCourseGradebook(
4791
                    $linkId,
4792
                    $courseInfo['code'],
4793
                    $params['weight']
4794
                );
4795
            }
4796
        } else {
4797
            // Delete everything of the gradebook for this $linkId
4798
            GradebookUtils::remove_resource_from_course_gradebook($linkId);
4799
        }
4800
    }
4801
}
4802
4803
/**
4804
 * Delete all work by student.
4805
 *
4806
 * @param int   $userId
4807
 * @param array $courseInfo
4808
 *
4809
 * @return array return deleted items
4810
 */
4811
function deleteAllWorkPerUser($userId, $courseInfo)
4812
{
4813
    $deletedItems = [];
4814
    $workPerUser = getWorkPerUser($userId);
4815
    if (!empty($workPerUser)) {
4816
        foreach ($workPerUser as $work) {
4817
            $work = $work['work'];
4818
            foreach ($work->user_results as $userResult) {
4819
                $result = deleteWorkItem($userResult['id'], $courseInfo);
4820
                if ($result) {
4821
                    $deletedItems[] = $userResult;
4822
                }
4823
            }
4824
        }
4825
    }
4826
4827
    return $deletedItems;
4828
}
4829
4830
/**
4831
 * @param int   $item_id
4832
 * @param array $courseInfo course info
4833
 *
4834
 * @return bool
4835
 */
4836
function deleteWorkItem($item_id, $courseInfo)
4837
{
4838
    $item_id = (int) $item_id;
4839
4840
    if (empty($item_id) || empty($courseInfo)) {
4841
        return false;
4842
    }
4843
4844
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
4845
    $is_allowed_to_edit = api_is_allowed_to_edit();
4846
    $file_deleted = false;
4847
    $is_author = user_is_author($item_id);
4848
    $work_data = get_work_data_by_id($item_id);
4849
    $locked = api_resource_is_locked_by_gradebook($work_data['parent_id'], LINK_STUDENTPUBLICATION);
4850
    $course_id = $courseInfo['real_id'];
4851
4852
    if (($is_allowed_to_edit && false == $locked) ||
4853
        (
4854
            false == $locked &&
4855
            $is_author &&
4856
            1 == api_get_course_setting('student_delete_own_publication') &&
4857
            0 == $work_data['qualificator_id']
4858
        )
4859
    ) {
4860
        // We found the current user is the author
4861
        $sql = "SELECT url, contains_file, user_id, session_id, parent_id
4862
                FROM $work_table
4863
                WHERE c_id = $course_id AND id = $item_id";
4864
        $result = Database::query($sql);
4865
        $row = Database::fetch_array($result);
4866
        $count = Database::num_rows($result);
4867
4868
        if ($count > 0) {
4869
            // If the "considered_working_time" option is enabled, check
4870
            // whether some time should be removed from track_e_course_access
4871
            $consideredWorkingTime = api_get_configuration_value('considered_working_time');
4872
            if ($consideredWorkingTime) {
4873
                $userWorks = get_work_user_list(
4874
                    0,
4875
                    100,
4876
                    null,
4877
                    null,
4878
                    $row['parent_id'],
4879
                    null,
4880
                    $row['user_id'],
4881
                    false,
4882
                    $course_id,
4883
                    $row['session_id']
4884
                );
4885
                // We're only interested in deleting the time if this is the latest work sent
4886
                if (1 == count($userWorks)) {
4887
                    // Get the "considered work time" defined for this work
4888
                    $fieldValue = new ExtraFieldValue('work');
4889
                    $resultExtra = $fieldValue->getAllValuesForAnItem(
4890
                        $row['parent_id'],
4891
                        true
4892
                    );
4893
4894
                    $workingTime = null;
4895
                    foreach ($resultExtra as $field) {
4896
                        $field = $field['value'];
4897
4898
                        if ($consideredWorkingTime == $field->getField()->getVariable()) {
4899
                            $workingTime = $field->getValue();
4900
                        }
4901
                    }
4902
                    // If no time was defined, or a time of "0" was set, do nothing
4903
                    if (!empty($workingTime)) {
4904
                        $sessionId = empty($row['session_id']) ? 0 : $row['session_id'];
4905
                        // Getting false from the following call would mean the
4906
                        // time record
4907
                        Event::eventRemoveVirtualCourseTime(
4908
                            $course_id,
4909
                            $row['user_id'],
4910
                            $sessionId,
4911
                            $workingTime
4912
                        );
4913
                    }
4914
                }
4915
            } // end of considered_working_time check section
4916
4917
            $repo = Container::getStudentPublicationRepository();
4918
            /** @var CStudentPublication $work */
4919
            $work = $repo->find($item_id);
4920
            $work->setActive(2);
4921
            $repo->getEntityManager()->persist($work);
4922
4923
            $repo = Container::getStudentPublicationAssignmentRepository();
4924
            $params = ['cId' => $course_id, 'publicationId' => $item_id];
4925
4926
            $items = $repo->getRepository()->findBy($params);
4927
            foreach ($items as $item) {
4928
                $repo->remove($item);
4929
            }
4930
4931
            $repo->getEntityManager()->flush();
4932
4933
            /*$sql = "DELETE FROM $TSTDPUBASG
4934
                    WHERE c_id = $course_id AND publication_id = $item_id";
4935
            Database::query($sql);*/
4936
4937
            Compilatio::plagiarismDeleteDoc($course_id, $item_id);
4938
4939
            /*api_item_property_update(
4940
                $courseInfo,
4941
                'work',
4942
                $item_id,
4943
                'DocumentDeleted',
4944
                api_get_user_id()
4945
            );*/
4946
4947
            Event::addEvent(
4948
                LOG_WORK_FILE_DELETE,
4949
                LOG_WORK_DATA,
4950
                [
4951
                    'id' => $work_data['id'],
4952
                    'url' => $work_data['url'],
4953
                    'title' => $work_data['title'],
4954
                ],
4955
                null,
4956
                api_get_user_id(),
4957
                api_get_course_int_id(),
4958
                api_get_session_id()
4959
            );
4960
            $file_deleted = true;
4961
4962
            if (1 == $row['contains_file']) {
4963
                /*if (!empty($work)) {
4964
                    if (api_get_setting('permanently_remove_deleted_files') === 'true') {
4965
                        my_delete($currentCourseRepositorySys.'/'.$work);
4966
                        $file_deleted = true;
4967
                    } else {
4968
                        $extension = pathinfo($work, PATHINFO_EXTENSION);
4969
                        $new_dir = $work.'_DELETED_'.$item_id.'.'.$extension;
4970
4971
                        if (file_exists($currentCourseRepositorySys.'/'.$work)) {
4972
                            rename($currentCourseRepositorySys.'/'.$work, $currentCourseRepositorySys.'/'.$new_dir);
4973
                            $file_deleted = true;
4974
                        }
4975
                    }
4976
                }*/
4977
            } else {
4978
                $file_deleted = true;
4979
            }
4980
        }
4981
    }
4982
4983
    return $file_deleted;
4984
}
4985
4986
/**
4987
 * @param FormValidator $form
4988
 * @param array         $defaults
4989
 * @param int           $workId
4990
 *
4991
 * @return FormValidator
4992
 */
4993
function getFormWork($form, $defaults = [], $workId = 0)
4994
{
4995
    $sessionId = api_get_session_id();
4996
    if (!empty($defaults)) {
4997
        if (isset($defaults['submit'])) {
4998
            unset($defaults['submit']);
4999
        }
5000
    }
5001
5002
    // Create the form that asks for the directory name
5003
    $form->addText('new_dir', get_lang('Assignment name'));
5004
    $form->addHtmlEditor(
5005
        'description',
5006
        get_lang('Description'),
5007
        false,
5008
        false,
5009
        getWorkDescriptionToolbar()
5010
    );
5011
    $form->addButtonAdvancedSettings('advanced_params', get_lang('Advanced settings'));
5012
5013
    if (!empty($defaults) && (isset($defaults['enableEndDate']) || isset($defaults['enableExpiryDate']))) {
5014
        $form->addHtml('<div id="advanced_params_options" style="display:block">');
5015
    } else {
5016
        $form->addHtml('<div id="advanced_params_options" style="display:none">');
5017
    }
5018
5019
    // ScoreOfAssignment
5020
    $form->addElement('text', 'qualification', get_lang('ScoreNumeric'));
5021
5022
    if (0 != $sessionId && Gradebook::is_active() || 0 == $sessionId) {
5023
        $form->addElement(
5024
            'checkbox',
5025
            'make_calification',
5026
            null,
5027
            get_lang('Add to gradebook'),
5028
            [
5029
                'id' => 'make_calification_id',
5030
                'onclick' => "javascript: if(this.checked) { document.getElementById('option1').style.display='block';}else{document.getElementById('option1').style.display='none';}",
5031
            ]
5032
        );
5033
    } else {
5034
        // QualificationOfAssignment
5035
        $form->addElement('hidden', 'make_calification', false);
5036
    }
5037
5038
    if (!empty($defaults) && isset($defaults['category_id'])) {
5039
        $form->addHtml('<div id=\'option1\' style="display:block">');
5040
    } else {
5041
        $form->addHtml('<div id=\'option1\' style="display:none">');
5042
    }
5043
5044
    // Loading Gradebook select
5045
    GradebookUtils::load_gradebook_select_in_tool($form);
5046
5047
    $form->addElement('text', 'weight', get_lang('Weight inside assessment'));
5048
    $form->addHtml('</div>');
5049
5050
    $form->addElement('checkbox', 'enableExpiryDate', null, get_lang('Enable handing over deadline (visible to learners)'), 'id="expiry_date"');
5051
    if (isset($defaults['enableExpiryDate']) && $defaults['enableExpiryDate']) {
5052
        $form->addHtml('<div id="option2" style="display: block;">');
5053
    } else {
5054
        $form->addHtml('<div id="option2" style="display: none;">');
5055
    }
5056
5057
    $timeNextWeek = time() + 86400 * 7;
5058
    $nextWeek = substr(api_get_local_time($timeNextWeek), 0, 10);
5059
    if (!isset($defaults['expires_on'])) {
5060
        $date = substr($nextWeek, 0, 10);
5061
        $defaults['expires_on'] = $date.' 23:59';
5062
    }
5063
5064
    $form->addElement('date_time_picker', 'expires_on', get_lang('Posted sending deadline'));
5065
    $form->addHtml('</div>');
5066
    $form->addElement('checkbox', 'enableEndDate', null, get_lang('Enable final acceptance date (invisible to learners)'), 'id="end_date"');
5067
5068
    if (!isset($defaults['ends_on'])) {
5069
        $nextDay = substr(api_get_local_time($timeNextWeek + 86400), 0, 10);
5070
        $date = substr($nextDay, 0, 10);
5071
        $defaults['ends_on'] = $date.' 23:59';
5072
    }
5073
    if (isset($defaults['enableEndDate']) && $defaults['enableEndDate']) {
5074
        $form->addHtml('<div id="option3" style="display: block;">');
5075
    } else {
5076
        $form->addHtml('<div id="option3" style="display: none;">');
5077
    }
5078
5079
    $form->addElement('date_time_picker', 'ends_on', get_lang('Ends at (completely closed)'));
5080
    $form->addHtml('</div>');
5081
5082
    $form->addElement('checkbox', 'add_to_calendar', null, get_lang('Add to calendar'));
5083
    $form->addElement('select', 'allow_text_assignment', get_lang('Document type'), getUploadDocumentType());
5084
5085
    // Extra fields
5086
    $extraField = new ExtraField('work');
5087
    $extra = $extraField->addElements($form, $workId);
5088
5089
    $htmlHeadXtra[] = '
5090
        <script>
5091
        $(function() {
5092
            '.$extra['jquery_ready_content'].'
5093
        });
5094
        </script>';
5095
5096
    $form->addHtml('</div>');
5097
5098
    $skillList = Skill::addSkillsToForm($form, ITEM_TYPE_STUDENT_PUBLICATION, $workId);
5099
5100
    if (!empty($defaults)) {
5101
        $defaults['skills'] = array_keys($skillList);
5102
        $form->setDefaults($defaults);
5103
    }
5104
5105
    return $form;
5106
}
5107
5108
/**
5109
 * @return array
5110
 */
5111
function getUploadDocumentType()
5112
{
5113
    return [
5114
        0 => get_lang('Allow files or online text'),
5115
        1 => get_lang('Allow only text'),
5116
        2 => get_lang('Allow only files'),
5117
    ];
5118
}
5119
5120
/**
5121
 * @param int   $itemId
5122
 * @param array $course_info
5123
 *
5124
 * @return bool
5125
 */
5126
function makeVisible($itemId, $course_info)
5127
{
5128
    $itemId = (int) $itemId;
5129
    if (empty($course_info) || empty($itemId)) {
5130
        return false;
5131
    }
5132
5133
    $itemId = (int) $itemId;
5134
    if (empty($course_info) || empty($itemId)) {
5135
        return false;
5136
    }
5137
5138
    $repo = Container::getStudentPublicationRepository();
5139
    /** @var CStudentPublication $studentPublication */
5140
    $studentPublication = $repo->find($itemId);
5141
    if ($studentPublication) {
5142
        $studentPublication->setAccepted(1);
5143
        $repo->getEntityManager()->persist($studentPublication);
5144
        $repo->getEntityManager()->flush();
5145
    }
5146
    /*
5147
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
5148
    $course_id = $course_info['real_id'];
5149
5150
    $sql = "UPDATE $work_table SET accepted = 1
5151
            WHERE c_id = $course_id AND id = $itemId";
5152
    Database::query($sql);
5153
    api_item_property_update($course_info, 'work', $itemId, 'visible', api_get_user_id());
5154
    */
5155
    return true;
5156
}
5157
5158
/**
5159
 * @param int   $itemId
5160
 * @param array $course_info
5161
 *
5162
 * @return int
5163
 */
5164
function makeInvisible($itemId, $course_info)
5165
{
5166
    $itemId = (int) $itemId;
5167
    if (empty($course_info) || empty($itemId)) {
5168
        return false;
5169
    }
5170
5171
    $repo = Container::getStudentPublicationRepository();
5172
    /** @var CStudentPublication $studentPublication */
5173
    $studentPublication = $repo->find($itemId);
5174
    if ($studentPublication) {
5175
        $studentPublication->setAccepted(0);
5176
        $repo->getEntityManager()->persist($studentPublication);
5177
        $repo->getEntityManager()->flush();
5178
    }
5179
5180
    /*api_item_property_update(
5181
        $course_info,
5182
        'work',
5183
        $itemId,
5184
        'invisible',
5185
        api_get_user_id()
5186
    );*/
5187
5188
    return true;
5189
}
5190
5191
/**
5192
 * @param int    $item_id
5193
 * @param string $path
5194
 * @param array  $courseInfo
5195
 * @param int    $groupId    iid
5196
 * @param int    $sessionId
5197
 *
5198
 * @return string
5199
 */
5200
function generateMoveForm($item_id, $path, $courseInfo, $groupId, $sessionId)
5201
{
5202
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
5203
    $courseId = $courseInfo['real_id'];
5204
    $folders = [];
5205
    $session_id = (int) $sessionId;
5206
    $groupId = (int) $groupId;
5207
    $sessionCondition = empty($sessionId) ? ' AND (session_id = 0 OR session_id IS NULL) ' : " AND session_id='".$session_id."'";
5208
5209
    $groupIid = 0;
5210
    if ($groupId) {
5211
        $groupInfo = GroupManager::get_group_properties($groupId);
5212
        $groupIid = $groupInfo['iid'];
5213
    }
5214
5215
    $sql = "SELECT id, url, title
5216
            FROM $work_table
5217
            WHERE
5218
                c_id = $courseId AND
5219
                active IN (0, 1) AND
5220
                parent_id = 0 AND
5221
                post_group_id = $groupIid
5222
                $sessionCondition";
5223
    $res = Database::query($sql);
5224
    while ($folder = Database::fetch_array($res)) {
5225
        $title = empty($folder['title']) ? basename($folder['url']) : $folder['title'];
5226
        $folders[$folder['id']] = $title;
5227
    }
5228
5229
    return build_work_move_to_selector($folders, $path, $item_id);
5230
}
5231
5232
/**
5233
 * @param int $workId
5234
 *
5235
 * @return string
5236
 */
5237
function showStudentList($workId)
5238
{
5239
    $columnModel = [
5240
        [
5241
            'name' => 'student',
5242
            'index' => 'student',
5243
            'width' => '350px',
5244
            'align' => 'left',
5245
            'sortable' => 'false',
5246
        ],
5247
        [
5248
            'name' => 'works',
5249
            'index' => 'works',
5250
            'align' => 'center',
5251
            'sortable' => 'false',
5252
        ],
5253
    ];
5254
    $token = null;
5255
    $url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_work_student_list_overview&work_id='.$workId.'&'.api_get_cidreq();
5256
5257
    $columns = [
5258
        get_lang('Learners'),
5259
        get_lang('Assignments'),
5260
    ];
5261
5262
    $order = api_is_western_name_order() ? 'firstname' : 'lastname';
5263
    $params = [
5264
        'autowidth' => 'true',
5265
        'height' => 'auto',
5266
        'rowNum' => 5,
5267
        'sortname' => $order,
5268
        'sortorder' => 'asc',
5269
    ];
5270
5271
    $html = '<script>
5272
    $(function() {
5273
        '.Display::grid_js('studentList', $url, $columns, $columnModel, $params, [], null, true).'
5274
        $("#workList").jqGrid(
5275
            "navGrid",
5276
            "#studentList_pager",
5277
            { edit: false, add: false, del: false },
5278
            { height:280, reloadAfterSubmit:false }, // edit options
5279
            { height:280, reloadAfterSubmit:false }, // add options
5280
            { width:500 } // search options
5281
        );
5282
    });
5283
    </script>';
5284
    $html .= Display::grid_html('studentList');
5285
5286
    return $html;
5287
}
5288
5289
/**
5290
 * @param string $courseCode
5291
 * @param int    $sessionId
5292
 * @param int    $groupId
5293
 * @param int    $start
5294
 * @param int    $limit
5295
 * @param string $sidx
5296
 * @param string $sord
5297
 * @param $getCount
5298
 *
5299
 * @return array|int
5300
 */
5301
function getWorkUserList($courseCode, $sessionId, $groupId, $start, $limit, $sidx, $sord, $getCount = false)
5302
{
5303
    if (!empty($groupId)) {
5304
        $userList = GroupManager::get_users(
5305
            $groupId,
5306
            false,
5307
            $start,
5308
            $limit,
5309
            $getCount,
5310
            null,
5311
            $sidx,
5312
            $sord
5313
        );
5314
    } else {
5315
        $limitString = null;
5316
        if (!empty($start) && !empty($limit)) {
5317
            $start = (int) $start;
5318
            $limit = (int) $limit;
5319
            $limitString = " LIMIT $start, $limit";
5320
        }
5321
5322
        $orderBy = null;
5323
5324
        if (!empty($sidx) && !empty($sord)) {
5325
            if (in_array($sidx, ['firstname', 'lastname'])) {
5326
                $orderBy = "ORDER BY $sidx $sord";
5327
            }
5328
        }
5329
5330
        if (empty($sessionId)) {
5331
            $userList = CourseManager::get_user_list_from_course_code(
5332
                $courseCode,
5333
                $sessionId,
5334
                $limitString,
5335
                $orderBy,
5336
                STUDENT,
5337
                $getCount
5338
            );
5339
        } else {
5340
            $userList = CourseManager::get_user_list_from_course_code(
5341
                $courseCode,
5342
                $sessionId,
5343
                $limitString,
5344
                $orderBy,
5345
                0,
5346
                $getCount
5347
            );
5348
        }
5349
5350
        if (false == $getCount) {
5351
            $userList = array_keys($userList);
5352
        }
5353
    }
5354
5355
    return $userList;
5356
}
5357
5358
/**
5359
 * @param int    $workId
5360
 * @param string $courseCode
5361
 * @param int    $sessionId
5362
 * @param int    $groupId
5363
 * @param int    $start
5364
 * @param int    $limit
5365
 * @param int    $sidx
5366
 * @param string $sord
5367
 * @param bool   $getCount
5368
 *
5369
 * @return array|int
5370
 */
5371
function getWorkUserListData(
5372
    $workId,
5373
    $courseCode,
5374
    $sessionId,
5375
    $groupId,
5376
    $start,
5377
    $limit,
5378
    $sidx,
5379
    $sord,
5380
    $getCount = false
5381
) {
5382
    $my_folder_data = get_work_data_by_id($workId);
5383
    $workParents = [];
5384
    if (empty($my_folder_data)) {
5385
        $workParents = getWorkList($workId, $my_folder_data, null);
5386
    }
5387
5388
    $workIdList = [];
5389
    if (!empty($workParents)) {
5390
        foreach ($workParents as $work) {
5391
            $workIdList[] = $work->id;
5392
        }
5393
    }
5394
5395
    $courseInfo = api_get_course_info($courseCode);
5396
5397
    $userList = getWorkUserList(
5398
        $courseCode,
5399
        $sessionId,
5400
        $groupId,
5401
        $start,
5402
        $limit,
5403
        $sidx,
5404
        $sord,
5405
        $getCount
5406
    );
5407
5408
    if ($getCount) {
5409
        return $userList;
5410
    }
5411
    $results = [];
5412
    if (!empty($userList)) {
5413
        foreach ($userList as $userId) {
5414
            $user = api_get_user_info($userId);
5415
            $link = api_get_path(WEB_CODE_PATH).'work/student_work.php?'.api_get_cidreq().'&studentId='.$user['user_id'];
5416
            $url = Display::url(api_get_person_name($user['firstname'], $user['lastname']), $link);
5417
            $userWorks = 0;
5418
            if (!empty($workIdList)) {
5419
                $userWorks = getUniqueStudentAttempts(
5420
                    $workIdList,
5421
                    $groupId,
5422
                    $courseInfo['real_id'],
5423
                    $sessionId,
5424
                    $user['user_id']
5425
                );
5426
            }
5427
            $works = $userWorks.' / '.count($workParents);
5428
            $results[] = [
5429
                'student' => $url,
5430
                'works' => Display::url($works, $link),
5431
            ];
5432
        }
5433
    }
5434
5435
    return $results;
5436
}
5437
5438
/**
5439
 * @param int   $id
5440
 * @param array $course_info
5441
 * @param bool  $isCorrection
5442
 *
5443
 * @return bool
5444
 */
5445
function downloadFile($id, $course_info, $isCorrection)
5446
{
5447
    return getFile($id, $course_info, true, $isCorrection, true);
5448
}
5449
5450
/**
5451
 * @param int   $id
5452
 * @param array $course_info
5453
 * @param bool  $download
5454
 * @param bool  $isCorrection
5455
 * @param bool  $forceAccessForCourseAdmins
5456
 *
5457
 * @return bool
5458
 */
5459
function getFile($id, $course_info, $download = true, $isCorrection = false, $forceAccessForCourseAdmins = false)
5460
{
5461
    $file = getFileContents($id, $course_info, 0, $isCorrection, $forceAccessForCourseAdmins);
5462
    var_dump($file);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($file) looks like debug code. Are you sure you do not want to remove it?
Loading history...
5463
    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
5464
    if (!empty($file) && isset($file['entity'])) {
0 ignored issues
show
Unused Code introduced by
IfNode 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...
5465
        /** @var CStudentPublication $studentPublication */
5466
        $studentPublication = $file['entity'];
5467
    }
5468
5469
    return false;
5470
}
5471
5472
/**
5473
 * Get the file contents for an assigment.
5474
 *
5475
 * @param int   $id
5476
 * @param array $courseInfo
5477
 * @param int   $sessionId
5478
 * @param bool  $correction
5479
 * @param bool  $forceAccessForCourseAdmins
5480
 *
5481
 * @return array|bool
5482
 */
5483
function getFileContents($id, $courseInfo, $sessionId = 0, $correction = false, $forceAccessForCourseAdmins = false)
5484
{
5485
    $id = (int) $id;
5486
5487
    if (empty($courseInfo) || empty($id)) {
5488
        return false;
5489
    }
5490
    if (empty($sessionId)) {
5491
        $sessionId = api_get_session_id();
5492
    }
5493
5494
    $courseEntity = api_get_course_entity($courseInfo['real_id']);
5495
    $sessionEntity = api_get_session_entity($sessionId);
5496
5497
    $repo = Container::getStudentPublicationRepository();
5498
    /** @var CStudentPublication $studentPublication */
5499
    $studentPublication = $repo->find($id);
5500
5501
    if (empty($studentPublication)) {
5502
        return false;
5503
    }
5504
5505
    if ($correction) {
5506
        //$row['url'] = $row['url_correction'];
5507
    }
5508
    $hasFile = $studentPublication->getResourceNode()->hasResourceFile();
5509
    if (!$hasFile) {
5510
        return false;
5511
    }
5512
5513
    /*
5514
    $item_info = api_get_item_property_info(
5515
        api_get_course_int_id(),
5516
        'work',
5517
        $row['id'],
5518
        $sessionId
5519
    );
5520
5521
    if (empty($item_info)) {
5522
        return false;
5523
    }*/
5524
5525
    $isAllow = allowOnlySubscribedUser(
5526
        api_get_user_id(),
5527
        $studentPublication->getParentId(),
5528
        $courseInfo['real_id'],
5529
        $forceAccessForCourseAdmins
5530
    );
5531
5532
    if (empty($isAllow)) {
5533
        return false;
5534
    }
5535
5536
    /*
5537
    field show_score in table course :
5538
        0 =>    New documents are visible for all users
5539
        1 =>    New documents are only visible for the teacher(s)
5540
    field visibility in table item_property :
5541
        0 => eye closed, invisible for all students
5542
        1 => eye open
5543
    field accepted in table c_student_publication :
5544
        0 => eye closed, invisible for all students
5545
        1 => eye open
5546
    ( We should have visibility == accepted, otherwise there is an
5547
    inconsistency in the Database)
5548
    field value in table c_course_setting :
5549
        0 => Allow learners to delete their own publications = NO
5550
        1 => Allow learners to delete their own publications = YES
5551
5552
    +------------------+-------------------------+------------------------+
5553
    |Can download work?| doc visible for all = 0 | doc visible for all = 1|
5554
    +------------------+-------------------------+------------------------+
5555
    |  visibility = 0  | editor only             | editor only            |
5556
    |                  |                         |                        |
5557
    +------------------+-------------------------+------------------------+
5558
    |  visibility = 1  | editor                  | editor                 |
5559
    |                  | + owner of the work     | + any student          |
5560
    +------------------+-------------------------+------------------------+
5561
    (editor = teacher + admin + anybody with right api_is_allowed_to_edit)
5562
    */
5563
5564
    $work_is_visible = $studentPublication->isVisible($courseEntity, $sessionEntity) && $studentPublication->getAccepted();
5565
    $doc_visible_for_all = 0 === (int) $courseInfo['show_score'];
5566
5567
    $is_editor = api_is_allowed_to_edit(true, true, true);
5568
    $student_is_owner_of_work = user_is_author($studentPublication->getIid(), api_get_user_id());
5569
5570
    if (($forceAccessForCourseAdmins && $isAllow) ||
5571
        $is_editor ||
5572
        $student_is_owner_of_work ||
5573
        ($doc_visible_for_all && $work_is_visible)
5574
    ) {
5575
        $title = $studentPublication->getTitle();
5576
        if ($correction) {
5577
            $title = $studentPublication->getTitleCorrection();
5578
        }
5579
        if ($hasFile) {
5580
            $title = $studentPublication->getResourceNode()->getResourceFile()->getName();
5581
        }
5582
5583
        $title = str_replace(' ', '_', $title);
5584
5585
        if (false == $correction) {
5586
            $userInfo = api_get_user_info($studentPublication->getUserId());
5587
            if ($userInfo) {
5588
                $date = api_get_local_time($studentPublication->getSentDate()->format('Y-m-d H:i:s'));
5589
                $date = str_replace([':', '-', ' '], '_', $date);
5590
                $title = $date.'_'.$userInfo['username'].'_'.$title;
5591
            }
5592
        }
5593
5594
        return [
5595
            //'path' => $full_file_name,
5596
            'title' => $title,
5597
            'title_correction' => $studentPublication->getTitleCorrection(),
5598
            'entity' => $studentPublication,
5599
        ];
5600
    }
5601
5602
    return false;
5603
}
5604
5605
/**
5606
 * @param int    $userId
5607
 * @param array  $courseInfo
5608
 * @param string $format
5609
 *
5610
 * @return bool
5611
 */
5612
function exportAllWork($userId, $courseInfo, $format = 'pdf')
5613
{
5614
    $userInfo = api_get_user_info($userId);
5615
    if (empty($userInfo) || empty($courseInfo)) {
5616
        return false;
5617
    }
5618
5619
    $workPerUser = getWorkPerUser($userId);
5620
5621
    switch ($format) {
5622
        case 'pdf':
5623
            if (!empty($workPerUser)) {
5624
                $pdf = new PDF();
5625
5626
                $content = null;
5627
                foreach ($workPerUser as $work) {
5628
                    $work = $work['work'];
5629
                    foreach ($work->user_results as $userResult) {
5630
                        $content .= $userResult['title'];
5631
                        // No need to use api_get_local_time()
5632
                        $content .= $userResult['sent_date'];
5633
                        $content .= $userResult['qualification'];
5634
                        $content .= $userResult['description'];
5635
                    }
5636
                }
5637
5638
                if (!empty($content)) {
5639
                    $pdf->content_to_pdf(
5640
                        $content,
5641
                        null,
5642
                        api_replace_dangerous_char($userInfo['complete_name']),
5643
                        $courseInfo['code']
5644
                    );
5645
                }
5646
            }
5647
5648
            break;
5649
    }
5650
}
5651
5652
/**
5653
 * @param int    $workId
5654
 * @param array  $courseInfo
5655
 * @param int    $sessionId
5656
 * @param string $format
5657
 *
5658
 * @return bool
5659
 */
5660
function exportAllStudentWorkFromPublication(
5661
    $workId,
5662
    $courseInfo,
5663
    $sessionId,
5664
    $format = 'pdf'
5665
) {
5666
    if (empty($courseInfo)) {
5667
        return false;
5668
    }
5669
5670
    $workData = get_work_data_by_id($workId);
5671
    if (empty($workData)) {
5672
        return false;
5673
    }
5674
5675
    $assignment = get_work_assignment_by_id($workId);
5676
5677
    $courseCode = $courseInfo['code'];
5678
    $header = get_lang('Course').': '.$courseInfo['title'];
5679
    $teachers = CourseManager::getTeacherListFromCourseCodeToString(
5680
        $courseCode
5681
    );
5682
5683
    if (!empty($sessionId)) {
5684
        $sessionInfo = api_get_session_info($sessionId);
5685
        if (!empty($sessionInfo)) {
5686
            $header .= ' - '.$sessionInfo['name'];
5687
            $header .= '<br />'.$sessionInfo['description'];
5688
            $teachers = SessionManager::getCoachesByCourseSessionToString(
5689
                $sessionId,
5690
                $courseInfo['real_id']
5691
            );
5692
        }
5693
    }
5694
5695
    $header .= '<br />'.get_lang('Trainers').': '.$teachers.'<br />';
5696
    $header .= '<br />'.get_lang('Date').': '.api_get_local_time().'<br />';
5697
    $header .= '<br />'.get_lang('Assignment name').': '.$workData['title'].'<br />';
5698
5699
    $content = null;
5700
    $expiresOn = null;
5701
5702
    if (!empty($assignment) && isset($assignment['expires_on'])) {
5703
        $content .= '<br /><strong>'.get_lang('Posted deadline for sending the work (Visible to the learner)').'</strong>: '.api_get_local_time($assignment['expires_on']);
5704
        $expiresOn = api_get_local_time($assignment['expires_on']);
5705
    }
5706
5707
    if (!empty($workData['description'])) {
5708
        $content .= '<br /><strong>'.get_lang('Description').'</strong>: '.$workData['description'];
5709
    }
5710
5711
    $workList = get_work_user_list(null, null, null, null, $workId);
5712
5713
    switch ($format) {
5714
        case 'pdf':
5715
            if (!empty($workList)) {
5716
                $table = new HTML_Table(['class' => 'data_table']);
5717
                $headers = [
5718
                    get_lang('Name'),
5719
                    get_lang('User'),
5720
                    get_lang('Deadline'),
5721
                    get_lang('Sent date'),
5722
                    get_lang('Filename'),
5723
                    get_lang('Score'),
5724
                    get_lang('Feedback'),
5725
                ];
5726
5727
                $column = 0;
5728
                foreach ($headers as $header) {
5729
                    $table->setHeaderContents(0, $column, $header);
5730
                    $column++;
5731
                }
5732
5733
                $row = 1;
5734
5735
                //$pdf->set_custom_header($header);
5736
                foreach ($workList as $work) {
5737
                    $content .= '<hr />';
5738
                    // getWorkComments need c_id
5739
                    $work['c_id'] = $courseInfo['real_id'];
5740
5741
                    //$content .= get_lang('Date').': '.api_get_local_time($work['sent_date_from_db']).'<br />';
5742
                    $score = null;
5743
                    if (!empty($work['qualification_only'])) {
5744
                        $score = $work['qualification_only'];
5745
                    }
5746
5747
                    $comments = getWorkComments($work);
5748
5749
                    $feedback = null;
5750
                    if (!empty($comments)) {
5751
                        $content .= '<h4>'.get_lang('Feedback').': </h4>';
5752
                        foreach ($comments as $comment) {
5753
                            $feedback .= get_lang('User').': '.$comment['complete_name'].
5754
                                '<br />';
5755
                            $feedback .= $comment['comment'].'<br />';
5756
                        }
5757
                    }
5758
                    $table->setCellContents($row, 0, strip_tags($workData['title']));
5759
                    $table->setCellContents($row, 1, strip_tags($work['fullname']));
5760
                    $table->setCellContents($row, 2, $expiresOn);
5761
                    $table->setCellContents($row, 3, api_get_local_time($work['sent_date_from_db']));
5762
                    $table->setCellContents($row, 4, strip_tags($work['title']));
5763
                    $table->setCellContents($row, 5, $score);
5764
                    $table->setCellContents($row, 6, $feedback);
5765
5766
                    $row++;
5767
                }
5768
5769
                $content = $table->toHtml();
5770
5771
                if (!empty($content)) {
5772
                    $params = [
5773
                        'filename' => $workData['title'].'_'.api_get_local_time(),
5774
                        'pdf_title' => api_replace_dangerous_char($workData['title']),
5775
                        'course_code' => $courseInfo['code'],
5776
                    ];
5777
                    $pdf = new PDF('A4', null, $params);
5778
                    $pdf->html_to_pdf_with_template($content);
5779
                }
5780
                exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
5781
            }
5782
5783
            break;
5784
    }
5785
}
5786
5787
/**
5788
 * Downloads all user files per user.
5789
 *
5790
 * @param int   $userId
5791
 * @param array $courseInfo
5792
 *
5793
 * @return bool
5794
 */
5795
function downloadAllFilesPerUser($userId, $courseInfo)
5796
{
5797
    $userInfo = api_get_user_info($userId);
5798
5799
    if (empty($userInfo) || empty($courseInfo)) {
5800
        return false;
5801
    }
5802
5803
    $tempZipFile = api_get_path(SYS_ARCHIVE_PATH).api_get_unique_id().'.zip';
5804
    $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/work/';
5805
    $zip = new PclZip($tempZipFile);
5806
    $workPerUser = getWorkPerUser($userId);
5807
5808
    if (!empty($workPerUser)) {
5809
        $files = [];
5810
        foreach ($workPerUser as $work) {
5811
            $work = $work['work'];
5812
            foreach ($work->user_results as $userResult) {
5813
                if (empty($userResult['url']) || empty($userResult['contains_file'])) {
5814
                    continue;
5815
                }
5816
                $data = getFileContents($userResult['id'], $courseInfo);
5817
                if (!empty($data) && isset($data['path'])) {
5818
                    $files[basename($data['path'])] = [
5819
                        'title' => $data['title'],
5820
                        'path' => $data['path'],
5821
                    ];
5822
                }
5823
            }
5824
        }
5825
5826
        if (!empty($files)) {
5827
            Session::write('files', $files);
5828
            foreach ($files as $data) {
5829
                $zip->add(
5830
                    $data['path'],
5831
                    PCLZIP_OPT_REMOVE_PATH,
5832
                    $coursePath,
5833
                    PCLZIP_CB_PRE_ADD,
5834
                    'preAddAllWorkStudentCallback'
5835
                );
5836
            }
5837
        }
5838
5839
        // Start download of created file
5840
        $name = basename(api_replace_dangerous_char($userInfo['complete_name'])).'.zip';
5841
        Event::event_download($name.'.zip (folder)');
5842
        if (Security::check_abs_path($tempZipFile, api_get_path(SYS_ARCHIVE_PATH))) {
5843
            DocumentManager::file_send_for_download($tempZipFile, true, $name);
5844
            @unlink($tempZipFile);
5845
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
5846
        }
5847
    }
5848
    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
5849
}
5850
5851
/**
5852
 * @param $p_event
5853
 * @param array $p_header
5854
 *
5855
 * @return int
5856
 */
5857
function preAddAllWorkStudentCallback($p_event, &$p_header)
5858
{
5859
    $files = Session::read('files');
5860
    if (isset($files[basename($p_header['stored_filename'])])) {
5861
        $p_header['stored_filename'] = $files[basename($p_header['stored_filename'])]['title'];
5862
5863
        return 1;
5864
    }
5865
5866
    return 0;
5867
}
5868
5869
/**
5870
 * Get all work created by a user.
5871
 *
5872
 * @param int $user_id
5873
 * @param int $courseId
5874
 * @param int $sessionId
5875
 *
5876
 * @return array
5877
 */
5878
function getWorkCreatedByUser($user_id, $courseId, $sessionId)
5879
{
5880
    $items = api_get_item_property_list_by_tool_by_user(
5881
        $user_id,
5882
        'work',
5883
        $courseId,
5884
        $sessionId
5885
    );
5886
5887
    $list = [];
5888
    if (!empty($items)) {
5889
        foreach ($items as $work) {
5890
            $item = get_work_data_by_id(
5891
                $work['ref'],
5892
                $courseId,
5893
                $sessionId
5894
            );
5895
            if (!empty($item)) {
5896
                $list[] = [
5897
                    $item['title'],
5898
                    api_get_local_time($work['insert_date']),
5899
                    api_get_local_time($work['lastedit_date']),
5900
                ];
5901
            }
5902
        }
5903
    }
5904
5905
    return $list;
5906
}
5907
5908
/**
5909
 * @param array $courseInfo
5910
 * @param int   $workId
5911
 *
5912
 * @return bool
5913
 */
5914
function protectWork($courseInfo, $workId)
5915
{
5916
    $userId = api_get_user_id();
5917
    $groupId = api_get_group_id();
5918
    $sessionId = api_get_session_id();
5919
    $workData = get_work_data_by_id($workId);
5920
5921
    if (empty($workData) || empty($courseInfo)) {
5922
        api_not_allowed(true);
5923
    }
5924
5925
    if (api_is_platform_admin() || api_is_allowed_to_edit()) {
5926
        return true;
5927
    }
5928
5929
    $workId = $workData['id'];
5930
5931
    if (1 != $workData['active']) {
5932
        api_not_allowed(true);
5933
    }
5934
5935
    /*$visibility = api_get_item_visibility($courseInfo, 'work', $workId, $sessionId);
5936
    if ($visibility != 1) {
5937
        api_not_allowed(true);
5938
    }*/
5939
5940
    $isAllow = allowOnlySubscribedUser($userId, $workId, $courseInfo['real_id']);
5941
    if (empty($isAllow)) {
5942
        api_not_allowed(true);
5943
    }
5944
5945
    $groupInfo = GroupManager::get_group_properties($groupId);
5946
5947
    if (!empty($groupId)) {
5948
        $showWork = GroupManager::user_has_access(
5949
            $userId,
5950
            $groupInfo['iid'],
5951
            GroupManager::GROUP_TOOL_WORK
5952
        );
5953
        if (!$showWork) {
5954
            api_not_allowed(true);
5955
        }
5956
    }
5957
}
5958
5959
/**
5960
 * @param array $courseInfo
5961
 * @param array $work
5962
 */
5963
function deleteCorrection($courseInfo, $work)
5964
{
5965
    if (isset($work['url_correction']) && !empty($work['url_correction']) && isset($work['iid'])) {
5966
        $id = $work['iid'];
5967
        $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
5968
        $sql = "UPDATE $table SET
5969
                    url_correction = '',
5970
                    title_correction = ''
5971
                WHERE iid = $id";
5972
        Database::query($sql);
5973
        $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/';
5974
        if (file_exists($coursePath.$work['url_correction'])) {
5975
            if (Security::check_abs_path($coursePath.$work['url_correction'], $coursePath)) {
5976
                unlink($coursePath.$work['url_correction']);
5977
            }
5978
        }
5979
    }
5980
}
5981
5982
/**
5983
 * @param int $workId
5984
 *
5985
 * @return string
5986
 */
5987
function workGetExtraFieldData($workId)
5988
{
5989
    $sessionField = new ExtraField('work');
5990
    $extraFieldData = $sessionField->getDataAndFormattedValues($workId);
5991
    $result = '';
5992
    if (!empty($extraFieldData)) {
5993
        $result .= '<div class="well">';
5994
        foreach ($extraFieldData as $data) {
5995
            $result .= $data['text'].': <b>'.$data['value'].'</b>';
5996
        }
5997
        $result .= '</div>';
5998
    }
5999
6000
    return $result;
6001
}
6002