getWorkListTeacher()   C
last analyzed

Complexity

Conditions 14
Paths 128

Size

Total Lines 129
Code Lines 73

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 73
c 0
b 0
f 0
dl 0
loc 129
rs 5.4157
cc 14
nc 128
nop 7

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