Passed
Push — 1.11.x ( bce6cd...c146d9 )
by Angel Fernando Quiroz
12:25
created

getWorkListTeacher()   C

Complexity

Conditions 14
Paths 128

Size

Total Lines 129
Code Lines 73

Duplication

Lines 0
Ratio 0 %

Importance

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

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 ($start != 0 && $limit != 0) {
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('Visible');
1743
                $action = 'invisible';
1744
                $class = '';
1745
            } else {
1746
                $icon = 'invisible.png';
1747
                $text = get_lang('Invisible');
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
) {
2096
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
2097
    $user_table = Database::get_main_table(TABLE_MAIN_USER);
2098
2099
    $session_id = $sessionId ? (int) $sessionId : api_get_session_id();
2100
    $group_id = api_get_group_id();
2101
    $course_info = api_get_course_info();
2102
    $course_info = empty($course_info) ? api_get_course_info_by_id($courseId) : $course_info;
2103
    $course_id = isset($course_info['real_id']) ? $course_info['real_id'] : $courseId;
2104
2105
    $work_id = (int) $work_id;
2106
    $start = (int) $start;
2107
    $limit = (int) $limit;
2108
2109
    $column = !empty($column) ? Database::escape_string($column) : 'sent_date';
2110
    $compilation = null;
2111
    if (api_get_configuration_value('allow_compilatio_tool')) {
2112
        $compilation = new Compilatio();
2113
    }
2114
2115
    if (!in_array($direction, ['asc', 'desc'])) {
2116
        $direction = 'desc';
2117
    }
2118
2119
    $work_data = get_work_data_by_id($work_id, $courseId, $sessionId);
2120
    $is_allowed_to_edit = api_is_allowed_to_edit() || api_is_coach();
2121
    $condition_session = api_get_session_condition(
2122
        $session_id,
2123
        true,
2124
        false,
2125
        'work.session_id'
2126
    );
2127
2128
    $locked = api_resource_is_locked_by_gradebook(
2129
        $work_id,
2130
        LINK_STUDENTPUBLICATION,
2131
        $course_info['code']
2132
    );
2133
2134
    $isDrhOfCourse = CourseManager::isUserSubscribedInCourseAsDrh(
2135
        api_get_user_id(),
2136
        $course_info
2137
    );
2138
2139
    $isDrhOfSession = !empty(SessionManager::getSessionFollowedByDrh(api_get_user_id(), $session_id));
2140
2141
    $groupIid = 0;
2142
    if ($group_id) {
2143
        $groupInfo = GroupManager::get_group_properties($group_id);
2144
        if ($groupInfo) {
2145
            $groupIid = $groupInfo['iid'];
2146
        }
2147
    }
2148
2149
    if (!empty($work_data)) {
2150
        if (!empty($group_id)) {
2151
            // set to select only messages posted by the user's group
2152
            $extra_conditions = " work.post_group_id = '".$groupIid."' ";
2153
        } else {
2154
            $extra_conditions = " (work.post_group_id = '0' OR work.post_group_id is NULL) ";
2155
        }
2156
2157
        if ($is_allowed_to_edit || $isDrhOfCourse || $isDrhOfSession) {
2158
            $extra_conditions .= ' AND work.active IN (0, 1) ';
2159
        } else {
2160
            if (isset($course_info['show_score']) &&
2161
                1 == $course_info['show_score']
2162
            ) {
2163
                $extra_conditions .= ' AND (u.user_id = '.api_get_user_id().' AND work.active IN (0, 1)) ';
2164
            } else {
2165
                $extra_conditions .= ' AND work.active IN (0, 1) ';
2166
            }
2167
        }
2168
2169
        $extra_conditions .= " AND parent_id  = $work_id ";
2170
2171
        $select = 'SELECT DISTINCT
2172
                        u.user_id,
2173
                        work.id as id,
2174
                        title as title,
2175
                        description,
2176
                        url,
2177
                        sent_date,
2178
                        contains_file,
2179
                        has_properties,
2180
                        view_properties,
2181
                        qualification,
2182
                        weight,
2183
                        allow_text_assignment,
2184
                        u.firstname,
2185
                        u.lastname,
2186
                        u.username,
2187
                        parent_id,
2188
                        accepted,
2189
                        qualificator_id,
2190
                        url_correction,
2191
                        title_correction
2192
                        ';
2193
        if ($getCount) {
2194
            $select = 'SELECT DISTINCT count(u.user_id) as count ';
2195
        }
2196
2197
        $work_assignment = get_work_assignment_by_id($work_id, $courseId);
2198
2199
        if (!empty($studentId)) {
2200
            $studentId = (int) $studentId;
2201
            $whereCondition .= " AND u.user_id = $studentId ";
2202
        }
2203
2204
        $sql = " $select
2205
                FROM $work_table work
2206
                INNER JOIN $user_table u
2207
                ON (work.user_id = u.user_id)
2208
                WHERE
2209
                    work.c_id = $course_id AND
2210
                    $extra_conditions
2211
                    $whereCondition
2212
                    $condition_session
2213
                    AND u.status != ".INVITEE."
2214
                ORDER BY `$column` $direction";
2215
2216
        if (!empty($start) && !empty($limit)) {
2217
            $sql .= " LIMIT $start, $limit";
2218
        }
2219
        $result = Database::query($sql);
2220
        $works = [];
2221
2222
        if ($getCount) {
2223
            $work = Database::fetch_array($result, 'ASSOC');
2224
            if ($work) {
2225
                return (int) $work['count'];
2226
            }
2227
2228
            return 0;
2229
        }
2230
2231
        $url = api_get_path(WEB_CODE_PATH).'work/';
2232
        $unoconv = api_get_configuration_value('unoconv.binaries');
2233
        $loadingText = addslashes(get_lang('Loading'));
2234
        $uploadedText = addslashes(get_lang('Uploaded'));
2235
        $failsUploadText = addslashes(get_lang('UplNoFileUploaded'));
2236
        $failsUploadIcon = Display::return_icon(
2237
            'closed-circle.png',
2238
            '',
2239
            [],
2240
            ICON_SIZE_TINY
2241
        );
2242
        $saveIcon = Display::return_icon(
2243
            'save.png',
2244
            get_lang('Save'),
2245
            [],
2246
            ICON_SIZE_SMALL
2247
        );
2248
2249
        $correctionIcon = Display::return_icon(
2250
            'check-circle.png',
2251
            get_lang('Correction'),
2252
            null,
2253
            ICON_SIZE_SMALL
2254
        );
2255
2256
        $correctionIconSmall = Display::return_icon(
2257
            'check-circle.png',
2258
            get_lang('Correction'),
2259
            null,
2260
            ICON_SIZE_TINY
2261
        );
2262
2263
        $rateIcon = Display::return_icon(
2264
            'rate_work.png',
2265
            get_lang('CorrectAndRate'),
2266
            [],
2267
            ICON_SIZE_SMALL
2268
        );
2269
2270
        $blockEdition = api_get_configuration_value('block_student_publication_edition');
2271
        $blockScoreEdition = api_get_configuration_value('block_student_publication_score_edition');
2272
        $loading = Display::returnFontAwesomeIcon('spinner', null, true, 'fa-spin');
2273
        $cidReq = api_get_cidreq();
2274
2275
        $qualification_exists = false;
2276
        if (!empty($work_data['qualification']) &&
2277
            intval($work_data['qualification']) > 0
2278
        ) {
2279
            $qualification_exists = true;
2280
        }
2281
2282
        while ($work = Database::fetch_array($result, 'ASSOC')) {
2283
            $item_id = $work['id'];
2284
            $dbTitle = $work['title'];
2285
            // Get the author ID for that document from the item_property table
2286
            $is_author = false;
2287
            $can_read = false;
2288
            $owner_id = $work['user_id'];
2289
2290
            /* Because a bug found when saving items using the api_item_property_update()
2291
               the field $item_property_data['insert_user_id'] is not reliable. */
2292
            if (!$is_allowed_to_edit && $owner_id == api_get_user_id()) {
2293
                $is_author = true;
2294
            }
2295
2296
            if ($course_info['show_score'] == 0) {
2297
                $can_read = true;
2298
            }
2299
2300
            $qualification_string = '';
2301
            if ($qualification_exists) {
2302
                if ($work['qualification'] == '') {
2303
                    $qualification_string = Display::label('-');
2304
                } else {
2305
                    $qualification_string = formatWorkScore($work['qualification'], $work_data['qualification']);
2306
                }
2307
            }
2308
2309
            $work['qualification_score'] = $work['qualification'];
2310
            $add_string = '';
2311
            $time_expires = '';
2312
            if (!empty($work_assignment['expires_on'])) {
2313
                $time_expires = api_strtotime(
2314
                    $work_assignment['expires_on'],
2315
                    'UTC'
2316
                );
2317
            }
2318
2319
            if (!empty($work_assignment['expires_on']) &&
2320
                !empty($time_expires) && ($time_expires < api_strtotime($work['sent_date'], 'UTC'))) {
2321
                $add_string = Display::label(get_lang('Expired'), 'important').' - ';
2322
            }
2323
2324
            if (($can_read && $work['accepted'] == '1') ||
2325
                ($is_author && in_array($work['accepted'], ['1', '0'])) ||
2326
                ($is_allowed_to_edit || api_is_drh())
2327
            ) {
2328
                // Firstname, lastname, username
2329
                $work['fullname'] = Display::div(
2330
                    api_get_person_name($work['firstname'], $work['lastname']),
2331
                    ['class' => 'work-name']
2332
                );
2333
                // Title
2334
                $work['title_clean'] = $work['title'];
2335
                $work['title'] = Security::remove_XSS($work['title']);
2336
                if (strlen($work['title']) > 30) {
2337
                    $short_title = substr($work['title'], 0, 27).'...';
2338
                    $work['title'] = Display::span($short_title, ['class' => 'work-title', 'title' => $work['title']]);
2339
                } else {
2340
                    $work['title'] = Display::div($work['title'], ['class' => 'work-title']);
2341
                }
2342
2343
                // Type.
2344
                $work['type'] = DocumentManager::build_document_icon_tag('file', $work['url']);
2345
2346
                // File name.
2347
                $linkToDownload = '';
2348
                // If URL is present then there's a file to download keep BC.
2349
                if ($work['contains_file'] || !empty($work['url'])) {
2350
                    $linkToDownload = '<a href="'.$url.'download.php?id='.$item_id.'&'.$cidReq.'">'.$saveIcon.'</a> ';
2351
                }
2352
2353
                $feedback = '';
2354
                $count = getWorkCommentCount($item_id, $course_info);
2355
                if (!is_null($count) && !empty($count)) {
2356
                    if ($qualification_exists) {
2357
                        $feedback .= ' ';
2358
                    }
2359
                    $feedback .= Display::url(
2360
                        $count.' '.Display::returnFontAwesomeIcon('comments-o'),
2361
                        $url.'view.php?'.api_get_cidreq().'&id='.$item_id
2362
                    );
2363
                }
2364
2365
                $correction = '';
2366
                $hasCorrection = '';
2367
                if (!empty($work['url_correction'])) {
2368
                    $hasCorrection = Display::url(
2369
                        $correctionIcon,
2370
                        api_get_path(WEB_CODE_PATH).'work/download.php?id='.$item_id.'&'.$cidReq.'&correction=1'
2371
                    );
2372
                }
2373
2374
                if ($qualification_exists) {
2375
                    $work['qualification'] = $qualification_string.$feedback;
2376
                } else {
2377
                    $work['qualification'] = $qualification_string.$feedback.$hasCorrection;
2378
                }
2379
2380
                $work['qualification_only'] = $qualification_string;
2381
2382
                // Date.
2383
                $work_date = api_get_local_time($work['sent_date']);
2384
                $date = date_to_str_ago($work['sent_date']).' '.$work_date;
2385
                $work['formatted_date'] = $work_date.' '.$add_string;
2386
                $work['expiry_note'] = $add_string;
2387
                $work['sent_date_from_db'] = $work['sent_date'];
2388
                $work['sent_date'] = '<div class="work-date" title="'.$date.'">'.
2389
                    $add_string.' '.Display::dateToStringAgoAndLongDate($work['sent_date']).'</div>';
2390
                $work['status'] = $hasCorrection;
2391
                $work['has_correction'] = $hasCorrection;
2392
2393
                // Actions.
2394
                $action = '';
2395
                if (api_is_allowed_to_edit()) {
2396
                    if ($blockScoreEdition && !api_is_platform_admin() && !empty($work['qualification_score'])) {
2397
                        $rateLink = '';
2398
                    } else {
2399
                        $rateLink = '<a href="'.$url.'view.php?'.$cidReq.'&id='.$item_id.'" title="'.get_lang('View').'">'.
2400
                            $rateIcon.'</a> ';
2401
                    }
2402
                    $action .= $rateLink;
2403
2404
                    if ($unoconv && empty($work['contains_file'])) {
2405
                        $action .= '<a
2406
                            href="'.$url.'work_list_all.php?'.$cidReq.'&id='.$work_id.'&action=export_to_doc&item_id='.$item_id.'"
2407
                            title="'.get_lang('ExportToDoc').'" >'.
2408
                            Display::return_icon('export_doc.png', get_lang('ExportToDoc'), [], ICON_SIZE_SMALL).'</a> ';
2409
                    }
2410
2411
                    $alreadyUploaded = '';
2412
                    if (!empty($work['url_correction'])) {
2413
                        $alreadyUploaded = '<br />'.$work['title_correction'].' '.$correctionIconSmall;
2414
                    }
2415
2416
                    $correction = '
2417
                        <form
2418
                        id="file_upload_'.$item_id.'"
2419
                        class="work_correction_file_upload file_upload_small fileinput-button"
2420
                        action="'.api_get_path(WEB_AJAX_PATH).'work.ajax.php?'.$cidReq.'&a=upload_correction_file&item_id='.$item_id.'"
2421
                        method="POST"
2422
                        enctype="multipart/form-data"
2423
                        >
2424
                        <div id="progress_'.$item_id.'" class="text-center button-load">
2425
                            '.addslashes(get_lang('ClickOrDropOneFileHere')).'
2426
                            '.Display::return_icon('upload_file.png', get_lang('Correction'), [], ICON_SIZE_TINY).'
2427
                            '.$alreadyUploaded.'
2428
                        </div>
2429
                        <input id="file_'.$item_id.'" type="file" name="file" class="" multiple>
2430
                        </form>
2431
                    ';
2432
2433
                    $correction .= "<script>
2434
                    $(function() {
2435
                        $('.work_correction_file_upload').each(function () {
2436
                            $(this).fileupload({
2437
                                dropZone: $(this)
2438
                            });
2439
                        });
2440
2441
                        $('#file_upload_".$item_id."').fileupload({
2442
                            add: function (e, data) {
2443
                                $('#progress_$item_id').html();
2444
                                data.context = $('#progress_$item_id').html('$loadingText <br /> <em class=\"fa fa-spinner fa-pulse fa-fw\"></em>');
2445
                                data.submit();
2446
                                $(this).removeClass('hover');
2447
                            },
2448
                            dragover: function (e, data) {
2449
                                $(this).addClass('hover');
2450
                            },
2451
                            done: function (e, data) {
2452
                                if (data._response.result.name) {
2453
                                    $('#progress_$item_id').html('$uploadedText '+data._response.result.result+'<br />'+data._response.result.name);
2454
                                } else {
2455
                                    $('#progress_$item_id').html('$failsUploadText $failsUploadIcon');
2456
                                }
2457
                                $(this).removeClass('hover');
2458
                            }
2459
                        });
2460
                        $('#file_upload_".$item_id."').on('dragleave', function (e) {
2461
                            // dragleave callback implementation
2462
                            $(this).removeClass('hover');
2463
                        });
2464
                    });
2465
                    </script>";
2466
2467
                    if ($locked) {
2468
                        if ($qualification_exists) {
2469
                            $action .= Display::return_icon(
2470
                                'edit_na.png',
2471
                                get_lang('CorrectAndRate'),
2472
                                [],
2473
                                ICON_SIZE_SMALL
2474
                            );
2475
                        } else {
2476
                            $action .= Display::return_icon('edit_na.png', get_lang('Comment'), [], ICON_SIZE_SMALL);
2477
                        }
2478
                    } else {
2479
                        if ($blockEdition && !api_is_platform_admin()) {
2480
                            $editLink = '';
2481
                        } else {
2482
                            if ($qualification_exists) {
2483
                                $editLink = '<a href="'.$url.'edit.php?'.api_get_cidreq(
2484
                                    ).'&item_id='.$item_id.'&id='.$work['parent_id'].'" title="'.get_lang(
2485
                                        'Edit'
2486
                                    ).'"  >'.
2487
                                    Display::return_icon('edit.png', get_lang('Edit'), [], ICON_SIZE_SMALL).'</a>';
2488
                            } else {
2489
                                $editLink = '<a href="'.$url.'edit.php?'.api_get_cidreq(
2490
                                    ).'&item_id='.$item_id.'&id='.$work['parent_id'].'" title="'.get_lang(
2491
                                        'Modify'
2492
                                    ).'">'.
2493
                                    Display::return_icon('edit.png', get_lang('Edit'), [], ICON_SIZE_SMALL).'</a>';
2494
                            }
2495
                        }
2496
                        $action .= $editLink;
2497
                    }
2498
2499
                    if ($work['contains_file']) {
2500
                        if ($locked) {
2501
                            $action .= Display::return_icon(
2502
                                'move_na.png',
2503
                                get_lang('Move'),
2504
                                [],
2505
                                ICON_SIZE_SMALL
2506
                            );
2507
                        } else {
2508
                            $action .= '<a href="'.$url.'work.php?'.api_get_cidreq().'&action=move&item_id='.$item_id.'&id='.$work['parent_id'].'" title="'.get_lang('Move').'">'.
2509
                                Display::return_icon('move.png', get_lang('Move'), [], ICON_SIZE_SMALL).'</a>';
2510
                        }
2511
                    }
2512
2513
                    if ($work['accepted'] == '1') {
2514
                        $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').'" >'.
2515
                            Display::return_icon('visible.png', get_lang('Invisible'), [], ICON_SIZE_SMALL).'</a>';
2516
                    } else {
2517
                        $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').'" >'.
2518
                            Display::return_icon('invisible.png', get_lang('Visible'), [], ICON_SIZE_SMALL).'</a> ';
2519
                    }
2520
2521
                    if ($locked) {
2522
                        $action .= Display::return_icon('delete_na.png', get_lang('Delete'), '', ICON_SIZE_SMALL);
2523
                    } else {
2524
                        $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').'" >'.
2525
                            Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL).'</a>';
2526
                    }
2527
                } elseif ($is_author && (empty($work['qualificator_id']) || $work['qualificator_id'] == 0)) {
2528
                    $action .= '<a href="'.$url.'view.php?'.api_get_cidreq().'&id='.$item_id.'" title="'.get_lang('View').'">'.
2529
                        Display::return_icon('default.png', get_lang('View'), [], ICON_SIZE_SMALL).'</a>';
2530
2531
                    if (api_get_course_setting('student_delete_own_publication') == 1) {
2532
                        if (api_is_allowed_to_session_edit(false, true)) {
2533
                            $action .= '<a href="'.$url.'edit.php?'.api_get_cidreq().'&item_id='.$item_id.'&id='.$work['parent_id'].'" title="'.get_lang('Modify').'">'.
2534
                                Display::return_icon('edit.png', get_lang('Comment'), [], ICON_SIZE_SMALL).'</a>';
2535
                        }
2536
                        $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').'"  >'.
2537
                            Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL).'</a>';
2538
                    }
2539
                } else {
2540
                    $action .= '<a href="'.$url.'view.php?'.api_get_cidreq().'&id='.$item_id.'" title="'.get_lang('View').'">'.
2541
                        Display::return_icon('default.png', get_lang('View'), [], ICON_SIZE_SMALL).'</a>';
2542
                }
2543
2544
                // Status.
2545
                if (empty($work['qualificator_id'])) {
2546
                    $qualificator_id = Display::label(get_lang('NotRevised'), 'warning');
2547
                } else {
2548
                    $qualificator_id = Display::label(get_lang('Revised'), 'success');
2549
                }
2550
                $work['qualificator_id'] = $qualificator_id.' '.$hasCorrection;
2551
                $work['actions'] = '<div class="work-action">'.$linkToDownload.$action.'</div>';
2552
                $work['correction'] = $correction;
2553
2554
                if (!empty($compilation) && $is_allowed_to_edit) {
2555
                    $compilationId = $compilation->getCompilatioId($item_id, $course_id);
2556
                    if ($compilationId) {
2557
                        $actionCompilatio = "<div id='id_avancement".$item_id."' class='compilation_block'>
2558
                            ".$loading.'&nbsp;'.get_lang('CompilatioConnectionWithServer').'</div>';
2559
                    } else {
2560
                        $workDirectory = api_get_path(SYS_COURSE_PATH).$course_info['directory'];
2561
                        if (!Compilatio::verifiFileType($dbTitle)) {
2562
                            $actionCompilatio = get_lang('FileFormatNotSupported');
2563
                        } elseif (filesize($workDirectory.'/'.$work['url']) > $compilation->getMaxFileSize()) {
2564
                            $sizeFile = round(filesize($workDirectory.'/'.$work['url']) / 1000000);
2565
                            $actionCompilatio = get_lang('UplFileTooBig').': '.format_file_size($sizeFile).'<br />';
2566
                        } else {
2567
                            $actionCompilatio = "<div id='id_avancement".$item_id."' class='compilation_block'>";
2568
                            $actionCompilatio .= Display::url(
2569
                                get_lang('CompilatioAnalysis'),
2570
                                'javascript:void(0)',
2571
                                [
2572
                                    'class' => 'getSingleCompilatio btn btn-primary btn-xs',
2573
                                    'onclick' => "getSingleCompilatio($item_id);",
2574
                                ]
2575
                            );
2576
                            $actionCompilatio .= get_lang('CompilatioWithCompilatio');
2577
                        }
2578
                    }
2579
                    $work['compilatio'] = $actionCompilatio;
2580
                }
2581
                $works[] = $work;
2582
            }
2583
        }
2584
2585
        return $works;
2586
    }
2587
}
2588
2589
function getAllWork(
2590
    $start,
2591
    $limit,
2592
    $column,
2593
    $direction,
2594
    $whereCondition = '',
2595
    $getCount = false,
2596
    $courseId = 0,
2597
    $status = 0
2598
) {
2599
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
2600
    $user_table = Database::get_main_table(TABLE_MAIN_USER);
2601
    $userId = api_get_user_id();
2602
    if (empty($userId)) {
2603
        return [];
2604
    }
2605
2606
    $allowWorkFromAllSessions = api_get_configuration_value('assignment_base_course_teacher_access_to_all_session');
2607
    $coursesInSession = [];
2608
    $courses = CourseManager::get_courses_list_by_user_id($userId, false, false, false);
2609
    if ($allowWorkFromAllSessions) {
2610
        if (empty($courses)) {
2611
            return [];
2612
        }
2613
    } else {
2614
        $coursesInSession = SessionManager::getCoursesForCourseSessionCoach($userId);
2615
2616
        if (empty($courses) && empty($coursesInSession)) {
2617
            return [];
2618
        }
2619
    }
2620
2621
    if (!empty($whereCondition)) {
2622
        $whereCondition = ' AND '.$whereCondition;
2623
    }
2624
    $whereCondition = Database::escape_string($whereCondition);
2625
2626
    if (!in_array($direction, ['asc', 'desc'])) {
2627
        $direction = 'desc';
2628
    }
2629
2630
    $column = !empty($column) ? Database::escape_string($column) : 'sent_date';
2631
    $start = (int) $start;
2632
    $limit = (int) $limit;
2633
    $courseQuery = [];
2634
    $courseList = [];
2635
    $withResults = 0;
2636
    foreach ($courses as $course) {
2637
        $courseIdItem = $course['real_id'];
2638
        if (!empty($courseId) && $courseIdItem != $courseId) {
2639
            continue;
2640
        }
2641
        $courseInfo = api_get_course_info_by_id($courseIdItem);
2642
        // Only teachers or platform admins.
2643
        $isAllow = api_is_platform_admin() || CourseManager::is_course_teacher($userId, $courseInfo['code']);
2644
        if (false === $isAllow) {
2645
            continue;
2646
        }
2647
2648
        //$session_id = isset($course['session_id']) ? $course['session_id'] : 0;
2649
        //$conditionSession = api_get_session_condition($session_id, true, false, 'w.session_id');
2650
        $conditionSession = ' AND (work.session_id = 0 OR work.session_id IS NULL)';
2651
        if ($allowWorkFromAllSessions) {
2652
            $conditionSession = '';
2653
        }
2654
        $parentCondition = '';
2655
        if ($withResults) {
2656
            $parentCondition = 'AND ww.parent_id is NOT NULL';
2657
        }
2658
        $courseQuery[] = " (work.c_id = $courseIdItem $conditionSession $parentCondition ) ";
2659
        $courseList[$courseIdItem] = $courseInfo;
2660
    }
2661
2662
    if (false === $allowWorkFromAllSessions) {
2663
        foreach ($coursesInSession as $courseIdInSession => $sessionList) {
2664
            if (!empty($sessionList)) {
2665
                if (!isset($courseList[$courseIdInSession])) {
2666
                    $courseList[$courseIdInSession] = api_get_course_info_by_id($courseIdInSession);
2667
                }
2668
2669
                foreach ($sessionList as $sessionId) {
2670
                    $conditionSession = " AND (work.session_id = $sessionId)";
2671
                    $parentCondition = '';
2672
                    $courseQuery[] = " (work.c_id = $courseIdInSession $conditionSession $parentCondition ) ";
2673
                }
2674
            }
2675
        }
2676
    }
2677
2678
    if (empty($courseQuery)) {
2679
        return [];
2680
    }
2681
2682
    $courseQueryToString = implode(' OR ', $courseQuery);
2683
    $compilation = null;
2684
    /*if (api_get_configuration_value('allow_compilatio_tool')) {
2685
        $compilation = new Compilatio();
2686
    }*/
2687
2688
    if ($getCount) {
2689
        if (empty($courseQuery)) {
2690
            return 0;
2691
        }
2692
        $select = 'SELECT DISTINCT count(u.id) as count ';
2693
    } else {
2694
        $select = 'SELECT DISTINCT
2695
                    u.id as user_id,
2696
                    work.id as id,
2697
                    title as title,
2698
                    description,
2699
                    url,
2700
                    sent_date,
2701
                    contains_file,
2702
                    has_properties,
2703
                    view_properties,
2704
                    qualification,
2705
                    weight,
2706
                    allow_text_assignment,
2707
                    u.firstname,
2708
                    u.lastname,
2709
                    u.username,
2710
                    parent_id,
2711
                    accepted,
2712
                    qualificator_id,
2713
                    url_correction,
2714
                    title_correction,
2715
                    work.c_id,
2716
                    work.session_id ';
2717
    }
2718
2719
    $statusCondition = '';
2720
    if (!empty($status)) {
2721
        switch ($status) {
2722
            case 2:
2723
                $statusCondition = ' AND (qualificator_id IS NULL OR qualificator_id = 0) ';
2724
                break;
2725
            case 3:
2726
                $statusCondition = ' AND (qualificator_id <> 0 AND qualificator_id IS NOT NULL) ';
2727
                break;
2728
        }
2729
    }
2730
2731
    $sql = " $select
2732
            FROM $work_table work
2733
            INNER JOIN $user_table u
2734
            ON (work.user_id = u.id)
2735
            WHERE
2736
                work.parent_id <> 0 AND
2737
                work.active IN (1, 0)
2738
                $whereCondition AND
2739
                ($courseQueryToString)
2740
                $statusCondition
2741
                AND u.status != ".INVITEE;
2742
2743
    $sql .= " ORDER BY `$column` $direction ";
2744
2745
    if (!empty($start) && !empty($limit)) {
2746
        $sql .= " LIMIT $start, $limit";
2747
    }
2748
2749
    $result = Database::query($sql);
2750
    $works = [];
2751
    if ($getCount) {
2752
        $work = Database::fetch_array($result, 'ASSOC');
2753
        if ($work) {
2754
            return (int) $work['count'];
2755
        }
2756
2757
        return 0;
2758
    }
2759
2760
    $url = api_get_path(WEB_CODE_PATH).'work/';
2761
    $unoconv = api_get_configuration_value('unoconv.binaries');
2762
    $loadingText = addslashes(get_lang('Loading'));
2763
    $uploadedText = addslashes(get_lang('Uploaded'));
2764
    $failsUploadText = addslashes(get_lang('UplNoFileUploaded'));
2765
    $failsUploadIcon = Display::return_icon(
2766
        'closed-circle.png',
2767
        '',
2768
        [],
2769
        ICON_SIZE_TINY
2770
    );
2771
    $saveIcon = Display::return_icon(
2772
        'save.png',
2773
        get_lang('Save'),
2774
        [],
2775
        ICON_SIZE_SMALL
2776
    );
2777
2778
    $correctionIcon = Display::return_icon(
2779
        'check-circle.png',
2780
        get_lang('Correction'),
2781
        null,
2782
        ICON_SIZE_SMALL
2783
    );
2784
2785
    $correctionIconSmall = Display::return_icon(
2786
        'check-circle.png',
2787
        get_lang('Correction'),
2788
        null,
2789
        ICON_SIZE_TINY
2790
    );
2791
2792
    $rateIcon = Display::return_icon(
2793
        'rate_work.png',
2794
        get_lang('CorrectAndRate'),
2795
        [],
2796
        ICON_SIZE_SMALL
2797
    );
2798
    $parentList = [];
2799
    $blockEdition = api_get_configuration_value('block_student_publication_edition');
2800
    $blockScoreEdition = api_get_configuration_value('block_student_publication_score_edition');
2801
    $loading = Display::returnFontAwesomeIcon('spinner', null, true, 'fa-spin');
2802
    $qualification_exists = true;
2803
    while ($work = Database::fetch_array($result, 'ASSOC')) {
2804
        $courseId = $work['c_id'];
2805
        $courseInfo = $courseList[$work['c_id']];
2806
        $sessionId = $work['session_id'];
2807
        $cidReq = 'cidReq='.$courseInfo['code'].'&id_session='.$sessionId;
2808
2809
        $item_id = $work_id = $work['id'];
2810
        $dbTitle = $work['title'];
2811
        // Get the author ID for that document from the item_property table
2812
        $is_author = false;
2813
        $can_read = false;
2814
        $owner_id = $work['user_id'];
2815
        $visibility = api_get_item_visibility($courseInfo, 'work', $work['id'], $sessionId);
2816
        if ($visibility != 1) {
2817
            continue;
2818
        }
2819
        /*$locked = api_resource_is_locked_by_gradebook(
2820
            $item_id,
2821
            LINK_STUDENTPUBLICATION,
2822
            $courseInfo['code']
2823
        );*/
2824
        $locked = false;
2825
2826
        /* Because a bug found when saving items using the api_item_property_update()
2827
           the field $item_property_data['insert_user_id'] is not reliable. */
2828
        /*if (!$is_allowed_to_edit && $owner_id == api_get_user_id()) {
2829
            $is_author = true;
2830
        }*/
2831
        // Teacher can be treated as an author.
2832
        $is_author = true;
2833
2834
        /*if ($course_info['show_score'] == 0) {
2835
            $can_read = true;
2836
        }*/
2837
2838
        $qualification_string = '';
2839
        if ($qualification_exists) {
2840
            if ($work['qualification'] == '') {
2841
                $qualification_string = Display::label('-');
2842
            } else {
2843
                $qualification_string = formatWorkScore($work['qualification'], $work['qualification']);
2844
            }
2845
        }
2846
2847
        $work['qualification_score'] = $work['qualification'];
2848
        $add_string = '';
2849
        $time_expires = '';
2850
        if (!empty($work_assignment['expires_on'])) {
2851
            $time_expires = api_strtotime(
2852
                $work_assignment['expires_on'],
2853
                'UTC'
2854
            );
2855
        }
2856
2857
        if (!empty($work_assignment['expires_on']) &&
2858
            !empty($time_expires) && ($time_expires < api_strtotime($work['sent_date'], 'UTC'))) {
2859
            $add_string = Display::label(get_lang('Expired'), 'important').' - ';
2860
        }
2861
2862
        if (($can_read && $work['accepted'] == '1') ||
2863
            ($is_author && in_array($work['accepted'], ['1', '0']))
2864
        ) {
2865
            // Firstname, lastname, username
2866
            $work['fullname'] = Display::div(
2867
                api_get_person_name($work['firstname'], $work['lastname']),
2868
                ['class' => 'work-name']
2869
            );
2870
            // Title
2871
            $work['title_clean'] = $work['title'];
2872
            $work['title'] = Security::remove_XSS($work['title']);
2873
            if (strlen($work['title']) > 30) {
2874
                $short_title = substr($work['title'], 0, 27).'...';
2875
                $work['title'] = Display::span($short_title, ['class' => 'work-title', 'title' => $work['title']]);
2876
            } else {
2877
                $work['title'] = Display::div($work['title'], ['class' => 'work-title']);
2878
            }
2879
2880
            // Type.
2881
            $work['type'] = DocumentManager::build_document_icon_tag('file', $work['url']);
2882
2883
            // File name.
2884
            $linkToDownload = '';
2885
            // If URL is present then there's a file to download keep BC.
2886
            if ($work['contains_file'] || !empty($work['url'])) {
2887
                $linkToDownload = '<a href="'.$url.'download.php?id='.$item_id.'&'.$cidReq.'">'.$saveIcon.'</a> ';
2888
            }
2889
2890
            $feedback = '';
2891
            $count = getWorkCommentCount($item_id, $courseInfo);
2892
            if (!is_null($count) && !empty($count)) {
2893
                if ($qualification_exists) {
2894
                    $feedback .= ' ';
2895
                }
2896
                $feedback .= Display::url(
2897
                    $count.' '.Display::returnFontAwesomeIcon('comments-o'),
2898
                    $url.'view.php?'.$cidReq.'&id='.$item_id
2899
                );
2900
            }
2901
2902
            $correction = '';
2903
            $hasCorrection = '';
2904
            if (!empty($work['url_correction'])) {
2905
                $hasCorrection = Display::url(
2906
                    $correctionIcon,
2907
                    api_get_path(WEB_CODE_PATH).'work/download.php?id='.$item_id.'&'.$cidReq.'&correction=1'
2908
                );
2909
            }
2910
2911
            if ($qualification_exists) {
2912
                $work['qualification'] = $qualification_string.$feedback;
2913
            } else {
2914
                $work['qualification'] = $qualification_string.$feedback.$hasCorrection;
2915
            }
2916
2917
            $work['qualification_only'] = $qualification_string;
2918
2919
            // Date.
2920
            $work_date = api_get_local_time($work['sent_date']);
2921
            $date = date_to_str_ago($work['sent_date']).' '.$work_date;
2922
            $work['formatted_date'] = $work_date.' '.$add_string;
2923
            $work['expiry_note'] = $add_string;
2924
            $work['sent_date_from_db'] = $work['sent_date'];
2925
            $work['sent_date'] = '<div class="work-date" title="'.$date.'">'.
2926
                $add_string.' '.Display::dateToStringAgoAndLongDate($work['sent_date']).'</div>';
2927
            $work['status'] = $hasCorrection;
2928
            $work['has_correction'] = $hasCorrection;
2929
            $work['course'] = $courseInfo['title'];
2930
2931
            if (isset($parentList[$work['parent_id']])) {
2932
                $parent = $parentList[$work['parent_id']];
2933
            } else {
2934
                $parent = get_work_data_by_id($work['parent_id'], $courseId);
2935
            }
2936
            $work['work_name'] = $parent['title'];
2937
2938
            // Actions.
2939
            $action = '';
2940
            if ($blockScoreEdition && !api_is_platform_admin() && !empty($work['qualification_score'])) {
2941
                $rateLink = '';
2942
            } else {
2943
                $rateLink = '<a href="'.$url.'view.php?'.$cidReq.'&id='.$item_id.'" title="'.get_lang('View').'">'.
2944
                    $rateIcon.'</a> ';
2945
            }
2946
            $action .= $rateLink;
2947
            if ($unoconv && empty($work['contains_file'])) {
2948
                $action .= '<a
2949
                    href="'.$url.'work_list_all.php?'.$cidReq.'&id='.$work_id.'&action=export_to_doc&item_id='.$item_id.'"
2950
                    title="'.get_lang('ExportToDoc').'" >'.
2951
                    Display::return_icon('export_doc.png', get_lang('ExportToDoc'), [], ICON_SIZE_SMALL).'</a> ';
2952
            }
2953
2954
            $alreadyUploaded = '';
2955
            if (!empty($work['url_correction'])) {
2956
                $alreadyUploaded = '<br />'.$work['title_correction'].' '.$correctionIconSmall;
2957
            }
2958
2959
            $correction = '
2960
                <form
2961
                id="file_upload_'.$item_id.'"
2962
                class="work_correction_file_upload file_upload_small fileinput-button"
2963
                action="'.api_get_path(WEB_AJAX_PATH).'work.ajax.php?'.$cidReq.'&a=upload_correction_file&item_id='.$item_id.'"
2964
                method="POST"
2965
                enctype="multipart/form-data"
2966
                >
2967
                <div id="progress_'.$item_id.'" class="text-center button-load">
2968
                    '.addslashes(get_lang('ClickOrDropOneFileHere')).'
2969
                    '.Display::return_icon('upload_file.png', get_lang('Correction'), [], ICON_SIZE_TINY).'
2970
                    '.$alreadyUploaded.'
2971
                </div>
2972
                <input id="file_'.$item_id.'" type="file" name="file" class="" multiple>
2973
                </form>
2974
            ';
2975
2976
            $correction .= "<script>
2977
            $(function() {
2978
                $('.work_correction_file_upload').each(function () {
2979
                    $(this).fileupload({
2980
                        dropZone: $(this)
2981
                    });
2982
                });
2983
                $('#file_upload_".$item_id."').fileupload({
2984
                    add: function (e, data) {
2985
                        $('#progress_$item_id').html();
2986
                        data.context = $('#progress_$item_id').html('$loadingText <br /> <em class=\"fa fa-spinner fa-pulse fa-fw\"></em>');
2987
                        data.submit();
2988
                        $(this).removeClass('hover');
2989
                    },
2990
                    dragover: function (e, data) {
2991
                        $(this).addClass('hover');
2992
                    },
2993
                    done: function (e, data) {
2994
                        if (data._response.result.name) {
2995
                            $('#progress_$item_id').html('$uploadedText '+data._response.result.result+'<br />'+data._response.result.name);
2996
                        } else {
2997
                            $('#progress_$item_id').html('$failsUploadText $failsUploadIcon');
2998
                        }
2999
                        $(this).removeClass('hover');
3000
                    }
3001
                });
3002
                $('#file_upload_".$item_id."').on('dragleave', function (e) {
3003
                    // dragleave callback implementation
3004
                    $(this).removeClass('hover');
3005
                });
3006
            });
3007
            </script>";
3008
3009
            if ($locked) {
3010
                if ($qualification_exists) {
3011
                    $action .= Display::return_icon(
3012
                        'edit_na.png',
3013
                        get_lang('CorrectAndRate'),
3014
                        [],
3015
                        ICON_SIZE_SMALL
3016
                    );
3017
                } else {
3018
                    $action .= Display::return_icon('edit_na.png', get_lang('Comment'), [], ICON_SIZE_SMALL);
3019
                }
3020
            } else {
3021
                if ($blockEdition && !api_is_platform_admin()) {
3022
                    $editLink = '';
3023
                } else {
3024
                    $editIcon = Display::return_icon('edit.png', get_lang('Edit'), [], ICON_SIZE_SMALL);
3025
                    if ($qualification_exists) {
3026
                        $editLink = '<a
3027
                            href="'.$url.'edit.php?'.$cidReq.'&item_id='.$item_id.'&id='.$work['parent_id'].'"
3028
                            title="'.get_lang('Edit').'"  >'.
3029
                            $editIcon.
3030
                        '</a>';
3031
                    } else {
3032
                        $editLink = '<a
3033
                            href="'.$url.'edit.php?'.$cidReq.'&item_id='.$item_id.'&id='.$work['parent_id'].'"
3034
                            title="'.get_lang('Modify').'">'.
3035
                            $editIcon.'</a>';
3036
                    }
3037
                }
3038
                $action .= $editLink;
3039
            }
3040
3041
            /*if ($work['contains_file']) {
3042
                if ($locked) {
3043
                    $action .= Display::return_icon(
3044
                        'move_na.png',
3045
                        get_lang('Move'),
3046
                        [],
3047
                        ICON_SIZE_SMALL
3048
                    );
3049
                } else {
3050
                    $action .= '<a href="'.$url.'work.php?'.$cidReq.'&action=move&item_id='.$item_id.'&id='.$work['parent_id'].'" title="'.get_lang('Move').'">'.
3051
                        Display::return_icon('move.png', get_lang('Move'), [], ICON_SIZE_SMALL).'</a>';
3052
                }
3053
            }*/
3054
3055
            /*if ($work['accepted'] == '1') {
3056
                $action .= '<a href="'.$url.'work_list_all.php?'.$cidReq.'&id='.$work_id.'&action=make_invisible&item_id='.$item_id.'" title="'.get_lang('Invisible').'" >'.
3057
                    Display::return_icon('visible.png', get_lang('Invisible'), [], ICON_SIZE_SMALL).'</a>';
3058
            } else {
3059
                $action .= '<a href="'.$url.'work_list_all.php?'.$cidReq.'&id='.$work_id.'&action=make_visible&item_id='.$item_id.'" title="'.get_lang('Visible').'" >'.
3060
                    Display::return_icon('invisible.png', get_lang('Visible'), [], ICON_SIZE_SMALL).'</a> ';
3061
            }*/
3062
            /*if ($locked) {
3063
                $action .= Display::return_icon('delete_na.png', get_lang('Delete'), '', ICON_SIZE_SMALL);
3064
            } else {
3065
                $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').'" >'.
3066
                    Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL).'</a>';
3067
            }*/
3068
            // Status.
3069
            if (empty($work['qualificator_id'])) {
3070
                $qualificator_id = Display::label(get_lang('NotRevised'), 'warning');
3071
            } else {
3072
                $qualificator_id = Display::label(get_lang('Revised'), 'success');
3073
            }
3074
            $work['qualificator_id'] = $qualificator_id.' '.$hasCorrection;
3075
            $work['actions'] = '<div class="work-action">'.$linkToDownload.$action.'</div>';
3076
            $work['correction'] = $correction;
3077
3078
            if (!empty($compilation)) {
3079
                $compilationId = $compilation->getCompilatioId($item_id, $courseId);
3080
                if ($compilationId) {
3081
                    $actionCompilatio = "<div id='id_avancement".$item_id."' class='compilation_block'>
3082
                        ".$loading.'&nbsp;'.get_lang('CompilatioConnectionWithServer').'</div>';
3083
                } else {
3084
                    $workDirectory = api_get_path(SYS_COURSE_PATH).$courseInfo['directory'];
3085
                    if (!Compilatio::verifiFileType($dbTitle)) {
3086
                        $actionCompilatio = get_lang('FileFormatNotSupported');
3087
                    } elseif (filesize($workDirectory.'/'.$work['url']) > $compilation->getMaxFileSize()) {
3088
                        $sizeFile = round(filesize($workDirectory.'/'.$work['url']) / 1000000);
3089
                        $actionCompilatio = get_lang('UplFileTooBig').': '.format_file_size($sizeFile).'<br />';
3090
                    } else {
3091
                        $actionCompilatio = "<div id='id_avancement".$item_id."' class='compilation_block'>";
3092
                        $actionCompilatio .= Display::url(
3093
                            get_lang('CompilatioAnalysis'),
3094
                            'javascript:void(0)',
3095
                            [
3096
                                'class' => 'getSingleCompilatio btn btn-primary btn-xs',
3097
                                'onclick' => "getSingleCompilatio($item_id);",
3098
                            ]
3099
                        );
3100
                        $actionCompilatio .= get_lang('CompilatioWithCompilatio');
3101
                    }
3102
                }
3103
                $work['compilatio'] = $actionCompilatio;
3104
            }
3105
            $works[] = $work;
3106
        }
3107
    }
3108
3109
    return $works;
3110
}
3111
3112
/**
3113
 * Send reminder to users who have not given the task.
3114
 *
3115
 * @param int
3116
 *
3117
 * @return array
3118
 *
3119
 * @author cvargas [email protected] cfasanando, [email protected]
3120
 */
3121
function send_reminder_users_without_publication($task_data)
3122
{
3123
    $_course = api_get_course_info();
3124
    $task_id = $task_data['id'];
3125
    $task_title = !empty($task_data['title']) ? $task_data['title'] : basename($task_data['url']);
3126
    $subject = '['.api_get_setting('siteName').'] ';
3127
3128
    // The body can be as long as you wish, and any combination of text and variables
3129
    $content = get_lang('ReminderToSubmitPendingTask')."\n".get_lang('CourseName').' : '.$_course['name']."\n";
3130
    $content .= get_lang('WorkName').' : '.$task_title."\n";
3131
    $list_users = get_list_users_without_publication($task_id);
3132
    $mails_sent_to = [];
3133
    foreach ($list_users as $user) {
3134
        $name_user = api_get_person_name($user[1], $user[0], null, PERSON_NAME_EMAIL_ADDRESS);
3135
        $dear_line = get_lang('Dear')." ".api_get_person_name($user[1], $user[0]).", \n\n";
3136
        $body = $dear_line.$content;
3137
        MessageManager::send_message($user[3], $subject, $body);
3138
        $mails_sent_to[] = $name_user;
3139
    }
3140
3141
    return $mails_sent_to;
3142
}
3143
3144
/**
3145
 * @param int $workId    The work ID
3146
 * @param int $courseId  The course ID
3147
 * @param int $sessionId Optional. The session ID
3148
 */
3149
function sendEmailToDrhOnHomeworkCreation($workId, $courseId, $sessionId = 0)
3150
{
3151
    $courseInfo = api_get_course_info_by_id($courseId);
3152
    $assignment = get_work_assignment_by_id($workId, $courseId);
3153
    $work = get_work_data_by_id($workId, $courseId, $sessionId);
3154
    $workInfo = array_merge($assignment, $work);
3155
3156
    if (empty($sessionId)) {
3157
        $students = CourseManager::get_student_list_from_course_code($courseInfo['code']);
3158
    } else {
3159
        $students = CourseManager::get_student_list_from_course_code($courseInfo['code'], true, $sessionId);
3160
    }
3161
3162
    $bodyView = new Template(null, false, false, false, false, false);
3163
3164
    foreach ($students as $student) {
3165
        $studentInfo = api_get_user_info($student['user_id']);
3166
        if (empty($studentInfo)) {
3167
            continue;
3168
        }
3169
3170
        $hrms = UserManager::getDrhListFromUser($student['id']);
3171
        foreach ($hrms as $hrm) {
3172
            $hrmName = api_get_person_name($hrm['firstname'], $hrm['lastname'], null, PERSON_NAME_EMAIL_ADDRESS);
3173
3174
            $bodyView->assign('hrm_name', $hrmName);
3175
            $bodyView->assign('student', $studentInfo);
3176
            $bodyView->assign('course', $courseInfo);
3177
            $bodyView->assign('course_link', api_get_course_url($courseInfo['code'], $sessionId));
3178
            $bodyView->assign('work', $workInfo);
3179
3180
            $bodyTemplate = $bodyView->get_template('mail/new_work_alert_hrm.tpl');
3181
3182
            MessageManager::send_message(
3183
                $hrm['id'],
3184
                sprintf(
3185
                    get_lang('StudentXHasBeenAssignedNewWorkInCourseY'),
3186
                    $student['firstname'],
3187
                    $courseInfo['title']
3188
                ),
3189
                $bodyView->fetch($bodyTemplate)
3190
            );
3191
        }
3192
    }
3193
}
3194
3195
/**
3196
 * Sends an email to the students of a course when a homework is created.
3197
 *
3198
 * @param int $workId
3199
 * @param int $courseId
3200
 * @param int $sessionId
3201
 *
3202
 * @author Guillaume Viguier <[email protected]>
3203
 * @author Julio Montoya <[email protected]> Adding session support - 2011
3204
 */
3205
function sendEmailToStudentsOnHomeworkCreation($workId, $courseId, $sessionId = 0)
3206
{
3207
    $courseInfo = api_get_course_info_by_id($courseId);
3208
    $courseCode = $courseInfo['code'];
3209
    // Get the students of the course
3210
    if (empty($sessionId)) {
3211
        $students = CourseManager::get_student_list_from_course_code($courseCode);
3212
    } else {
3213
        $students = CourseManager::get_student_list_from_course_code($courseCode, true, $sessionId);
3214
    }
3215
    $emailsubject = '['.api_get_setting('siteName').'] '.get_lang('HomeworkCreated');
3216
    $currentUser = api_get_user_info(api_get_user_id());
3217
    if (!empty($students)) {
3218
        foreach ($students as $student) {
3219
            $user_info = api_get_user_info($student['user_id']);
3220
            if (!empty($user_info)) {
3221
                $link = api_get_path(WEB_CODE_PATH).'work/work_list.php?'.api_get_cidreq().'&id='.$workId;
3222
                $emailbody = get_lang('Dear')." ".$user_info['complete_name'].",\n\n";
3223
                $emailbody .= get_lang('HomeworkHasBeenCreatedForTheCourse')." ".$courseCode.". "."\n\n".
3224
                    '<a href="'.$link.'">'.get_lang('PleaseCheckHomeworkPage').'</a>';
3225
                $emailbody .= "\n\n".$currentUser['complete_name'];
3226
3227
                $additionalParameters = [
3228
                    'smsType' => SmsPlugin::ASSIGNMENT_BEEN_CREATED_COURSE,
3229
                    'userId' => $student['user_id'],
3230
                    'courseTitle' => $courseCode,
3231
                    'link' => $link,
3232
                ];
3233
3234
                MessageManager::send_message_simple(
3235
                    $student['user_id'],
3236
                    $emailsubject,
3237
                    $emailbody,
3238
                    null,
3239
                    false,
3240
                    false,
3241
                    $additionalParameters,
3242
                    false
3243
                );
3244
            }
3245
        }
3246
    }
3247
}
3248
3249
/**
3250
 * @param string $url
3251
 *
3252
 * @return bool
3253
 */
3254
function is_work_exist_by_url($url)
3255
{
3256
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
3257
    $url = Database::escape_string($url);
3258
    $sql = "SELECT id FROM $table WHERE url='$url'";
3259
    $result = Database::query($sql);
3260
    if (Database::num_rows($result) > 0) {
3261
        $row = Database::fetch_row($result);
3262
        if (empty($row)) {
3263
            return false;
3264
        } else {
3265
            return true;
3266
        }
3267
    } else {
3268
        return false;
3269
    }
3270
}
3271
3272
/**
3273
 * Check if a user is the author of a work document.
3274
 *
3275
 * @param int $itemId
3276
 * @param int $userId
3277
 * @param int $courseId
3278
 * @param int $sessionId
3279
 *
3280
 * @return bool
3281
 */
3282
function user_is_author($itemId, $userId = null, $courseId = 0, $sessionId = 0)
3283
{
3284
    $userId = (int) $userId;
3285
3286
    if (empty($itemId)) {
3287
        return false;
3288
    }
3289
3290
    if (empty($userId)) {
3291
        $userId = api_get_user_id();
3292
    }
3293
3294
    $isAuthor = false;
3295
    $is_allowed_to_edit = api_is_allowed_to_edit();
3296
3297
    if ($is_allowed_to_edit) {
3298
        $isAuthor = true;
3299
    } else {
3300
        if (empty($courseId)) {
3301
            $courseId = api_get_course_int_id();
3302
        }
3303
        if (empty($sessionId)) {
3304
            $sessionId = api_get_session_id();
3305
        }
3306
3307
        $data = api_get_item_property_info($courseId, 'work', $itemId, $sessionId);
3308
        if ($data['insert_user_id'] == $userId) {
3309
            $isAuthor = true;
3310
        }
3311
3312
        $workData = get_work_data_by_id($itemId);
3313
        if ($workData['user_id'] == $userId) {
3314
            $isAuthor = true;
3315
        }
3316
    }
3317
3318
    if (!$isAuthor) {
3319
        return false;
3320
    }
3321
3322
    return $isAuthor;
3323
}
3324
3325
/**
3326
 * Get list of users who have not given the task.
3327
 *
3328
 * @param int
3329
 * @param int
3330
 *
3331
 * @return array
3332
 *
3333
 * @author cvargas
3334
 * @author Julio Montoya <[email protected]> Fixing query
3335
 */
3336
function get_list_users_without_publication($task_id, $studentId = 0)
3337
{
3338
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
3339
    $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3340
    $table_user = Database::get_main_table(TABLE_MAIN_USER);
3341
    $session_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3342
3343
    $users = getAllUserToWork($task_id, api_get_course_int_id());
3344
    $users = array_column($users, 'user_id');
3345
3346
    // Condition for the session
3347
    $session_id = api_get_session_id();
3348
    $course_id = api_get_course_int_id();
3349
    $task_id = (int) $task_id;
3350
    $sessionCondition = api_get_session_condition($session_id);
3351
3352
    if (0 == $session_id) {
3353
        $sql = "SELECT user_id as id FROM $work_table
3354
                WHERE
3355
                    c_id = $course_id AND
3356
                    parent_id = '$task_id' AND
3357
                    active IN (0, 1)";
3358
    } else {
3359
        $sql = "SELECT user_id as id FROM $work_table
3360
                WHERE
3361
                    c_id = $course_id AND
3362
                    parent_id = '$task_id' $sessionCondition AND
3363
                    active IN (0, 1)";
3364
    }
3365
3366
    $result = Database::query($sql);
3367
    $users_with_tasks = [];
3368
    while ($row = Database::fetch_array($result)) {
3369
        $users_with_tasks[] = $row['id'];
3370
    }
3371
3372
    if (0 == $session_id) {
3373
        $sql_users = "SELECT cu.user_id, u.lastname, u.firstname, u.email
3374
                      FROM $table_course_user AS cu, $table_user AS u
3375
                      WHERE u.status != 1 and cu.c_id='".$course_id."' AND u.user_id = cu.user_id";
3376
    } else {
3377
        $sql_users = "SELECT cu.user_id, u.lastname, u.firstname, u.email
3378
                      FROM $session_course_rel_user AS cu, $table_user AS u
3379
                      WHERE
3380
                        u.status != 1 AND
3381
                        cu.c_id='".$course_id."' AND
3382
                        u.user_id = cu.user_id AND
3383
                        cu.session_id = '".$session_id."'";
3384
    }
3385
3386
    if (!empty($studentId)) {
3387
        $sql_users .= ' AND u.user_id = '.(int) $studentId;
3388
    }
3389
3390
    $group_id = api_get_group_id();
3391
    $new_group_user_list = [];
3392
3393
    if ($group_id) {
3394
        $groupInfo = GroupManager::get_group_properties($group_id);
3395
        $group_user_list = GroupManager::get_subscribed_users($groupInfo);
3396
        if (!empty($group_user_list)) {
3397
            foreach ($group_user_list as $group_user) {
3398
                $new_group_user_list[] = $group_user['user_id'];
3399
            }
3400
        }
3401
    }
3402
3403
    $result_users = Database::query($sql_users);
3404
    $users_without_tasks = [];
3405
    while ($rowUsers = Database::fetch_array($result_users)) {
3406
        $userId = $rowUsers['user_id'];
3407
        if (in_array($userId, $users_with_tasks)) {
3408
            continue;
3409
        }
3410
3411
        if ($group_id && !in_array($userId, $new_group_user_list)) {
3412
            continue;
3413
        }
3414
3415
        if (!empty($users)) {
3416
            if (!in_array($userId, $users)) {
3417
                continue;
3418
            }
3419
        }
3420
3421
        $row_users = [];
3422
        $row_users[0] = $rowUsers['lastname'];
3423
        $row_users[1] = $rowUsers['firstname'];
3424
        $row_users[2] = Display::encrypted_mailto_link($rowUsers['email']);
3425
        $row_users[3] = $userId;
3426
        $users_without_tasks[] = $row_users;
3427
    }
3428
3429
    return $users_without_tasks;
3430
}
3431
3432
/**
3433
 * Display list of users who have not given the task.
3434
 *
3435
 * @param int task id
3436
 * @param int $studentId
3437
 *
3438
 * @author cvargas [email protected] cfasanando, [email protected]
3439
 * @author Julio Montoya <[email protected]> Fixes
3440
 */
3441
function display_list_users_without_publication($task_id, $studentId = null)
3442
{
3443
    $origin = api_get_origin();
3444
    $table_header[] = [get_lang('LastName'), true];
3445
    $table_header[] = [get_lang('FirstName'), true];
3446
    $table_header[] = [get_lang('Email'), true];
3447
3448
    $data = get_list_users_without_publication($task_id);
3449
3450
    $sorting_options = [];
3451
    $sorting_options['column'] = 1;
3452
    $paging_options = [];
3453
    $my_params = [];
3454
3455
    if (isset($_GET['edit_dir'])) {
3456
        $my_params['edit_dir'] = Security::remove_XSS($_GET['edit_dir']);
3457
    }
3458
    if (isset($_GET['list'])) {
3459
        $my_params['list'] = Security::remove_XSS($_GET['list']);
3460
    }
3461
    $my_params['origin'] = $origin;
3462
    $my_params['id'] = (int) ($_GET['id']);
3463
3464
    //$column_show
3465
    $column_show[] = 1;
3466
    $column_show[] = 1;
3467
    $column_show[] = 1;
3468
    Display::display_sortable_config_table(
3469
        'work',
3470
        $table_header,
3471
        $data,
3472
        $sorting_options,
3473
        $paging_options,
3474
        $my_params,
3475
        $column_show
3476
    );
3477
}
3478
3479
/**
3480
 * @param int $documentId
3481
 * @param int $workId
3482
 * @param int $courseId
3483
 */
3484
function addDocumentToWork($documentId, $workId, $courseId)
3485
{
3486
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
3487
    $params = [
3488
        'document_id' => $documentId,
3489
        'work_id' => $workId,
3490
        'c_id' => $courseId,
3491
    ];
3492
    Database::insert($table, $params);
3493
}
3494
3495
/**
3496
 * @param int $documentId
3497
 * @param int $workId
3498
 * @param int $courseId
3499
 *
3500
 * @return array
3501
 */
3502
function getDocumentToWork($documentId, $workId, $courseId)
3503
{
3504
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
3505
    $params = [
3506
        'document_id = ? and work_id = ? and c_id = ?' => [$documentId, $workId, $courseId],
3507
    ];
3508
3509
    return Database::select('*', $table, ['where' => $params]);
3510
}
3511
3512
/**
3513
 * @param int $documentId
3514
 * @param int $workId
3515
 * @param int $courseId
3516
 * @param int $sessionId
3517
 * @param int $userId
3518
 * @param int $active
3519
 *
3520
 * @return array
3521
 */
3522
function getDocumentToWorkPerUser($documentId, $workId, $courseId, $sessionId, $userId, $active = 1)
3523
{
3524
    $workRel = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
3525
    $work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
3526
3527
    $documentId = (int) $documentId;
3528
    $workId = (int) $workId;
3529
    $courseId = (int) $courseId;
3530
    $userId = (int) $userId;
3531
    $sessionId = (int) $sessionId;
3532
    $active = (int) $active;
3533
    $sessionCondition = api_get_session_condition($sessionId);
3534
3535
    $sql = "SELECT w.* FROM $work w
3536
            INNER JOIN $workRel rel
3537
            ON (w.parent_id = rel.work_id)
3538
            WHERE
3539
                w.document_id = $documentId AND
3540
                w.parent_id = $workId AND
3541
                w.c_id = $courseId
3542
                $sessionCondition AND
3543
                user_id = $userId AND
3544
                active = $active
3545
            ";
3546
3547
    $result = Database::query($sql);
3548
    $workInfo = [];
3549
    if (Database::num_rows($result)) {
3550
        $workInfo = Database::fetch_array($result, 'ASSOC');
3551
    }
3552
3553
    return $workInfo;
3554
}
3555
3556
/**
3557
 * @param int $workId
3558
 * @param int $courseId
3559
 *
3560
 * @return array
3561
 */
3562
function getAllDocumentToWork($workId, $courseId)
3563
{
3564
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
3565
    $params = [
3566
        'work_id = ? and c_id = ?' => [$workId, $courseId],
3567
    ];
3568
3569
    return Database::select('*', $table, ['where' => $params]);
3570
}
3571
3572
/**
3573
 * @param int $documentId
3574
 * @param int $workId
3575
 * @param int $courseId
3576
 */
3577
function deleteDocumentToWork($documentId, $workId, $courseId)
3578
{
3579
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
3580
    $params = [
3581
        'document_id = ? and work_id = ? and c_id = ?' => [$documentId, $workId, $courseId],
3582
    ];
3583
    Database::delete($table, $params);
3584
}
3585
3586
/**
3587
 * @param int $userId
3588
 * @param int $workId
3589
 * @param int $courseId
3590
 */
3591
function addUserToWork($userId, $workId, $courseId)
3592
{
3593
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_USER);
3594
    $params = [
3595
        'user_id' => $userId,
3596
        'work_id' => $workId,
3597
        'c_id' => $courseId,
3598
    ];
3599
    Database::insert($table, $params);
3600
}
3601
3602
/**
3603
 * @param int $userId
3604
 * @param int $workId
3605
 * @param int $courseId
3606
 *
3607
 * @return array
3608
 */
3609
function getUserToWork($userId, $workId, $courseId)
3610
{
3611
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_USER);
3612
    $params = [
3613
        'user_id = ? and work_id = ? and c_id = ?' => [$userId, $workId, $courseId],
3614
    ];
3615
3616
    return Database::select('*', $table, ['where' => $params]);
3617
}
3618
3619
/**
3620
 * @param int  $workId
3621
 * @param int  $courseId
3622
 * @param bool $getCount
3623
 *
3624
 * @return array|int
3625
 */
3626
function getAllUserToWork($workId, $courseId, $getCount = false)
3627
{
3628
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_USER);
3629
    $params = [
3630
        'work_id = ? and c_id = ?' => [$workId, $courseId],
3631
    ];
3632
    if ($getCount) {
3633
        $count = 0;
3634
        $result = Database::select(
3635
            'count(user_id) as count',
3636
            $table,
3637
            ['where' => $params],
3638
            'simple'
3639
        );
3640
        if (!empty($result)) {
3641
            $count = (int) ($result['count']);
3642
        }
3643
3644
        return $count;
3645
    } else {
3646
        return Database::select('*', $table, ['where' => $params]);
3647
    }
3648
}
3649
3650
/**
3651
 * @param int $userId
3652
 * @param int $workId
3653
 * @param int $courseId
3654
 */
3655
function deleteUserToWork($userId, $workId, $courseId)
3656
{
3657
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_USER);
3658
    $params = [
3659
        'user_id = ? and work_id = ? and c_id = ?' => [$userId, $workId, $courseId],
3660
    ];
3661
    Database::delete($table, $params);
3662
}
3663
3664
/**
3665
 * @param int $userId
3666
 * @param int $workId
3667
 * @param int $courseId
3668
 *
3669
 * @return bool
3670
 */
3671
function userIsSubscribedToWork($userId, $workId, $courseId)
3672
{
3673
    $subscribedUsers = getAllUserToWork($workId, $courseId);
3674
3675
    if (empty($subscribedUsers)) {
3676
        return true;
3677
    } else {
3678
        $subscribedUsersList = [];
3679
        foreach ($subscribedUsers as $item) {
3680
            $subscribedUsersList[] = $item['user_id'];
3681
        }
3682
        if (in_array($userId, $subscribedUsersList)) {
3683
            return true;
3684
        }
3685
    }
3686
3687
    return false;
3688
}
3689
3690
/**
3691
 * Get the list of students that have to submit their work.
3692
 *
3693
 * @param int  $workId    The internal ID of the assignment
3694
 * @param int  $courseId  The course ID
3695
 * @param int  $groupId   The group ID, if any
3696
 * @param int  $sessionId The session ID, if any
3697
 * @param bool $getCount  Whether we want just the amount or the full result
3698
 *
3699
 * @return array|int An integer (if we just asked for the count) or an array of users
3700
 */
3701
function getStudentSubscribedToWork(
3702
    $workId,
3703
    $courseId,
3704
    $groupId = null,
3705
    $sessionId = null,
3706
    $getCount = false
3707
) {
3708
    $usersInWork = null;
3709
    $usersInCourse = null;
3710
3711
    if (empty($groupId)) {
3712
        $courseInfo = api_get_course_info_by_id($courseId);
3713
        $status = STUDENT;
3714
        if (!empty($sessionId)) {
3715
            $status = 0;
3716
        }
3717
        $usersInCourse = CourseManager::get_user_list_from_course_code(
3718
            $courseInfo['code'],
3719
            $sessionId,
3720
            null,
3721
            null,
3722
            $status,
3723
            $getCount
3724
        );
3725
    } else {
3726
        $usersInCourse = GroupManager::get_users(
3727
            $groupId,
3728
            false,
3729
            null,
3730
            null,
3731
            $getCount,
3732
            $courseId
3733
        );
3734
    }
3735
3736
    $usersInWork = getAllUserToWork($workId, $courseId, $getCount);
3737
3738
    if (empty($usersInWork)) {
3739
        return $usersInCourse;
3740
    } else {
3741
        return $usersInWork;
3742
    }
3743
}
3744
3745
/**
3746
 * @param int  $userId
3747
 * @param int  $workId
3748
 * @param int  $courseId
3749
 * @param bool $forceAccessForCourseAdmins
3750
 *
3751
 * @return bool
3752
 */
3753
function allowOnlySubscribedUser($userId, $workId, $courseId, $forceAccessForCourseAdmins = false)
3754
{
3755
    if (api_is_platform_admin() || api_is_allowed_to_edit()) {
3756
        return true;
3757
    }
3758
3759
    if ($forceAccessForCourseAdmins) {
3760
        if (api_is_course_admin() || api_is_coach()) {
3761
            return true;
3762
        }
3763
    }
3764
3765
    return userIsSubscribedToWork($userId, $workId, $courseId);
3766
}
3767
3768
/**
3769
 * @param int   $workId
3770
 * @param array $courseInfo
3771
 * @param int   $documentId
3772
 *
3773
 * @return array
3774
 */
3775
function getDocumentTemplateFromWork($workId, $courseInfo, $documentId)
3776
{
3777
    $documents = getAllDocumentToWork($workId, $courseInfo['real_id']);
3778
    if (!empty($documents)) {
3779
        foreach ($documents as $doc) {
3780
            if ($documentId != $doc['document_id']) {
3781
                continue;
3782
            }
3783
            $docData = DocumentManager::get_document_data_by_id($doc['document_id'], $courseInfo['code']);
3784
            $fileInfo = pathinfo($docData['path']);
3785
            if ('html' == $fileInfo['extension']) {
3786
                if (file_exists($docData['absolute_path']) && is_file($docData['absolute_path'])) {
3787
                    $docData['file_content'] = file_get_contents($docData['absolute_path']);
3788
3789
                    return $docData;
3790
                }
3791
            }
3792
        }
3793
    }
3794
3795
    return [];
3796
}
3797
3798
/**
3799
 * @param int   $workId
3800
 * @param array $courseInfo
3801
 *
3802
 * @return string
3803
 */
3804
function getAllDocumentsFromWorkToString($workId, $courseInfo)
3805
{
3806
    $documents = getAllDocumentToWork($workId, $courseInfo['real_id']);
3807
    $content = null;
3808
    if (!empty($documents)) {
3809
        $content .= '<ul class="nav nav-list well">';
3810
        $content .= '<li class="nav-header">'.get_lang('Documents').'</li>';
3811
        foreach ($documents as $doc) {
3812
            $docData = DocumentManager::get_document_data_by_id($doc['document_id'], $courseInfo['code']);
3813
            if ($docData) {
3814
                $content .= '<li><a class="link_to_download" target="_blank" href="'.$docData['url'].'">'.$docData['title'].'</a></li>';
3815
            }
3816
        }
3817
        $content .= '</ul><br />';
3818
    }
3819
3820
    return $content;
3821
}
3822
3823
/**
3824
 * Returns fck editor toolbar.
3825
 *
3826
 * @return array
3827
 */
3828
function getWorkDescriptionToolbar()
3829
{
3830
    return [
3831
        'ToolbarStartExpanded' => 'true',
3832
        'ToolbarSet' => 'Work',
3833
        'Width' => '100%',
3834
        'Height' => '400',
3835
    ];
3836
}
3837
3838
/**
3839
 * @param array $work
3840
 *
3841
 * @return array
3842
 */
3843
function getWorkComments($work)
3844
{
3845
    $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
3846
    $userTable = Database::get_main_table(TABLE_MAIN_USER);
3847
3848
    $courseId = (int) $work['c_id'];
3849
    $workId = (int) $work['id'];
3850
3851
    if (empty($courseId) || empty($workId)) {
3852
        return [];
3853
    }
3854
3855
    $sql = "SELECT
3856
                c.id,
3857
                c.user_id
3858
            FROM $commentTable c
3859
            INNER JOIN $userTable u
3860
            ON (u.id = c.user_id)
3861
            WHERE c_id = $courseId AND work_id = $workId
3862
            ORDER BY sent_at
3863
            ";
3864
    $result = Database::query($sql);
3865
    $comments = Database::store_result($result, 'ASSOC');
3866
    if (!empty($comments)) {
3867
        foreach ($comments as &$comment) {
3868
            $userInfo = api_get_user_info($comment['user_id']);
3869
            $comment['picture'] = $userInfo['avatar'];
3870
            $comment['complete_name'] = $userInfo['complete_name_with_username'];
3871
            $commentInfo = getWorkComment($comment['id']);
3872
            if (!empty($commentInfo)) {
3873
                $comment = array_merge($comment, $commentInfo);
3874
            }
3875
        }
3876
    }
3877
3878
    return $comments;
3879
}
3880
3881
/**
3882
 * Get total score from a work list.
3883
 *
3884
 * @param $workList
3885
 *
3886
 * @return int|null
3887
 */
3888
function getTotalWorkScore($workList)
3889
{
3890
    $count = 0;
3891
    foreach ($workList as $data) {
3892
        $count += $data['qualification_score'];
3893
    }
3894
3895
    return $count;
3896
}
3897
3898
/**
3899
 * Get comment count from a work list (docs sent by students).
3900
 *
3901
 * @param array $workList
3902
 * @param array $courseInfo
3903
 *
3904
 * @return int|null
3905
 */
3906
function getTotalWorkComment($workList, $courseInfo = [])
3907
{
3908
    if (empty($courseInfo)) {
3909
        $courseInfo = api_get_course_info();
3910
    }
3911
3912
    $count = 0;
3913
    foreach ($workList as $data) {
3914
        $count += getWorkCommentCount($data['id'], $courseInfo);
3915
    }
3916
3917
    return $count;
3918
}
3919
3920
/**
3921
 * Get comment count for a specific work sent by a student.
3922
 *
3923
 * @param int   $id
3924
 * @param array $courseInfo
3925
 *
3926
 * @return int
3927
 */
3928
function getWorkCommentCount($id, $courseInfo = [])
3929
{
3930
    if (empty($courseInfo)) {
3931
        $courseInfo = api_get_course_info();
3932
    }
3933
3934
    $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
3935
    $id = (int) $id;
3936
3937
    $sql = "SELECT count(*) as count
3938
            FROM $commentTable
3939
            WHERE work_id = $id AND c_id = ".$courseInfo['real_id'];
3940
3941
    $result = Database::query($sql);
3942
    if (Database::num_rows($result)) {
3943
        $comment = Database::fetch_array($result);
3944
3945
        return $comment['count'];
3946
    }
3947
3948
    return 0;
3949
}
3950
3951
/**
3952
 * Get comment count for a specific parent.
3953
 *
3954
 * @param int   $parentId
3955
 * @param array $courseInfo
3956
 * @param int   $sessionId
3957
 *
3958
 * @return int
3959
 */
3960
function getWorkCommentCountFromParent(
3961
    $parentId,
3962
    $courseInfo = [],
3963
    $sessionId = 0
3964
) {
3965
    if (empty($courseInfo)) {
3966
        $courseInfo = api_get_course_info();
3967
    }
3968
3969
    if (empty($sessionId)) {
3970
        $sessionId = api_get_session_id();
3971
    } else {
3972
        $sessionId = (int) $sessionId;
3973
    }
3974
3975
    $work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
3976
    $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
3977
    $parentId = (int) $parentId;
3978
    $sessionCondition = api_get_session_condition($sessionId, false, false, 'w.session_id');
3979
3980
    $sql = "SELECT count(*) as count
3981
            FROM $commentTable c INNER JOIN $work w
3982
            ON c.c_id = w.c_id AND w.id = c.work_id
3983
            WHERE
3984
                $sessionCondition AND
3985
                parent_id = $parentId AND
3986
                w.c_id = ".$courseInfo['real_id'];
3987
3988
    $result = Database::query($sql);
3989
    if (Database::num_rows($result)) {
3990
        $comment = Database::fetch_array($result);
3991
3992
        return $comment['count'];
3993
    }
3994
3995
    return 0;
3996
}
3997
3998
/**
3999
 * Get last work information from parent.
4000
 *
4001
 * @param int   $parentId
4002
 * @param array $courseInfo
4003
 * @param int   $sessionId
4004
 *
4005
 * @return int
4006
 */
4007
function getLastWorkStudentFromParent(
4008
    $parentId,
4009
    $courseInfo = [],
4010
    $sessionId = 0
4011
) {
4012
    if (empty($courseInfo)) {
4013
        $courseInfo = api_get_course_info();
4014
    }
4015
4016
    if (empty($sessionId)) {
4017
        $sessionId = api_get_session_id();
4018
    } else {
4019
        $sessionId = (int) $sessionId;
4020
    }
4021
4022
    $work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
4023
    $sessionCondition = api_get_session_condition($sessionId, false);
4024
    $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
4025
    $parentId = (int) $parentId;
4026
4027
    $sql = "SELECT w.*
4028
            FROM $commentTable c INNER JOIN $work w
4029
            ON c.c_id = w.c_id AND w.id = c.work_id
4030
            WHERE
4031
                $sessionCondition AND
4032
                parent_id = $parentId AND
4033
                w.c_id = ".$courseInfo['real_id'].'
4034
            ORDER BY w.sent_date
4035
            LIMIT 1
4036
            ';
4037
4038
    $result = Database::query($sql);
4039
    if (Database::num_rows($result)) {
4040
        return Database::fetch_array($result, 'ASSOC');
4041
    }
4042
4043
    return [];
4044
}
4045
4046
/**
4047
 * Get last work information from parent.
4048
 *
4049
 * @param int   $userId
4050
 * @param array $parentInfo
4051
 * @param array $courseInfo
4052
 * @param int   $sessionId
4053
 *
4054
 * @return int
4055
 */
4056
function getLastWorkStudentFromParentByUser(
4057
    $userId,
4058
    $parentInfo,
4059
    $courseInfo = [],
4060
    $sessionId = 0
4061
) {
4062
    if (empty($courseInfo)) {
4063
        $courseInfo = api_get_course_info();
4064
    }
4065
4066
    if (empty($sessionId)) {
4067
        $sessionId = api_get_session_id();
4068
    } else {
4069
        $sessionId = (int) $sessionId;
4070
    }
4071
4072
    $userId = (int) $userId;
4073
    $work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
4074
    if (empty($parentInfo)) {
4075
        return false;
4076
    }
4077
    $parentId = $parentInfo['id'];
4078
4079
    $sessionCondition = api_get_session_condition($sessionId);
4080
4081
    $sql = "SELECT *
4082
            FROM $work
4083
            WHERE
4084
                user_id = $userId
4085
                $sessionCondition AND
4086
                parent_id = $parentId AND
4087
                c_id = ".$courseInfo['real_id']."
4088
            ORDER BY sent_date DESC
4089
            LIMIT 1
4090
            ";
4091
    $result = Database::query($sql);
4092
    if (Database::num_rows($result)) {
4093
        $work = Database::fetch_array($result, 'ASSOC');
4094
        $work['qualification_rounded'] = formatWorkScore($work['qualification'], $parentInfo['qualification']);
4095
4096
        return $work;
4097
    }
4098
4099
    return [];
4100
}
4101
4102
/**
4103
 * @param float $score
4104
 * @param int   $weight
4105
 *
4106
 * @return string
4107
 */
4108
function formatWorkScore($score, $weight)
4109
{
4110
    $label = 'info';
4111
    $weight = (int) $weight;
4112
    $relativeScore = 0;
4113
    if (!empty($weight)) {
4114
        $relativeScore = $score / $weight;
4115
    }
4116
4117
    if ($relativeScore < 0.5) {
4118
        $label = 'important';
4119
    } elseif ($relativeScore < 0.75) {
4120
        $label = 'warning';
4121
    }
4122
4123
    $scoreBasedInModel = ExerciseLib::convertScoreToModel($relativeScore * 100);
4124
    if (empty($scoreBasedInModel)) {
4125
        $finalScore = api_number_format($score, 1).' / '.$weight;
4126
4127
        return Display::label(
4128
            $finalScore,
4129
            $label
4130
        );
4131
    } else {
4132
        return $scoreBasedInModel;
4133
    }
4134
}
4135
4136
/**
4137
 * @param int   $id         comment id
4138
 * @param array $courseInfo
4139
 *
4140
 * @return string
4141
 */
4142
function getWorkComment($id, $courseInfo = [])
4143
{
4144
    if (empty($courseInfo)) {
4145
        $courseInfo = api_get_course_info();
4146
    }
4147
4148
    if (empty($courseInfo['real_id'])) {
4149
        return [];
4150
    }
4151
4152
    $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
4153
    $id = intval($id);
4154
4155
    $sql = "SELECT * FROM $commentTable
4156
            WHERE id = $id AND c_id = ".$courseInfo['real_id'];
4157
    $result = Database::query($sql);
4158
    $comment = [];
4159
    if (Database::num_rows($result)) {
4160
        $comment = Database::fetch_array($result, 'ASSOC');
4161
        $filePath = null;
4162
        $fileUrl = null;
4163
        $deleteUrl = null;
4164
        $fileName = null;
4165
        if (!empty($comment['file'])) {
4166
            $work = get_work_data_by_id($comment['work_id']);
4167
            $workParent = get_work_data_by_id($work['parent_id']);
4168
            $filePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/work/'.$workParent['url'].'/'.$comment['file'];
4169
            $fileUrl = api_get_path(WEB_CODE_PATH).'work/download_comment_file.php?comment_id='.$id.'&'.api_get_cidreq();
4170
            $deleteUrl = api_get_path(WEB_CODE_PATH).'work/view.php?'.api_get_cidreq().'&id='.$comment['work_id'].'&action=delete_attachment&comment_id='.$id;
4171
            $fileParts = explode('_', $comment['file']);
4172
            $fileName = str_replace($fileParts[0].'_'.$fileParts[1].'_', '', $comment['file']);
4173
        }
4174
        $comment['delete_file_url'] = $deleteUrl;
4175
        $comment['file_path'] = $filePath;
4176
        $comment['file_url'] = $fileUrl;
4177
        $comment['file_name_to_show'] = $fileName;
4178
        $comment['sent_at_with_label'] = Display::dateToStringAgoAndLongDate($comment['sent_at']);
4179
    }
4180
4181
    return $comment;
4182
}
4183
4184
/**
4185
 * @param int   $id
4186
 * @param array $courseInfo
4187
 */
4188
function deleteCommentFile($id, $courseInfo = [])
4189
{
4190
    $workComment = getWorkComment($id, $courseInfo);
4191
    if (isset($workComment['file']) && !empty($workComment['file'])) {
4192
        if (file_exists($workComment['file_path'])) {
4193
            $result = my_delete($workComment['file_path']);
4194
            if ($result) {
4195
                $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
4196
                $params = ['file' => ''];
4197
                Database::update(
4198
                    $commentTable,
4199
                    $params,
4200
                    ['id = ? AND c_id = ? ' => [$workComment['id'], $workComment['c_id']]]
4201
                );
4202
            }
4203
        }
4204
    }
4205
}
4206
4207
/**
4208
 * Adds a comments to the work document.
4209
 *
4210
 * @param array $courseInfo
4211
 * @param int   $userId
4212
 * @param array $parentWork
4213
 * @param array $work
4214
 * @param array $data
4215
 *
4216
 * @return int
4217
 */
4218
function addWorkComment($courseInfo, $userId, $parentWork, $work, $data)
4219
{
4220
    $fileData = isset($data['attachment']) ? $data['attachment'] : null;
4221
    $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
4222
4223
    // If no attachment and no comment then don't save comment
4224
    if (empty($fileData['name']) && empty($data['comment'])) {
4225
        return false;
4226
    }
4227
4228
    $params = [
4229
        'work_id' => $work['id'],
4230
        'c_id' => $work['c_id'],
4231
        'user_id' => $userId,
4232
        'comment' => $data['comment'],
4233
        'sent_at' => api_get_utc_datetime(),
4234
    ];
4235
4236
    $commentId = Database::insert($commentTable, $params);
4237
4238
    if ($commentId) {
4239
        Display::addFlash(
4240
            Display::return_message(get_lang('CommentAdded'))
4241
        );
4242
4243
        $sql = "UPDATE $commentTable SET id = iid WHERE iid = $commentId";
4244
        Database::query($sql);
4245
    }
4246
4247
    $userIdListToSend = [];
4248
    if (api_is_allowed_to_edit()) {
4249
        if (isset($data['send_email']) && $data['send_email']) {
4250
            // Teacher sends a feedback
4251
            $userIdListToSend = [$work['user_id']];
4252
        }
4253
    } else {
4254
        $sessionId = api_get_session_id();
4255
        if (empty($sessionId)) {
4256
            $teachers = CourseManager::get_teacher_list_from_course_code(
4257
                $courseInfo['code']
4258
            );
4259
            if (!empty($teachers)) {
4260
                $userIdListToSend = array_keys($teachers);
4261
            }
4262
        } else {
4263
            $teachers = SessionManager::getCoachesByCourseSession(
4264
                $sessionId,
4265
                $courseInfo['real_id']
4266
            );
4267
4268
            if (!empty($teachers)) {
4269
                $userIdListToSend = array_values($teachers);
4270
            }
4271
        }
4272
4273
        $sendNotification = api_get_course_setting('email_to_teachers_on_new_work_feedback');
4274
        if ($sendNotification != 1) {
4275
            $userIdListToSend = [];
4276
        }
4277
    }
4278
4279
    $url = api_get_path(WEB_CODE_PATH).'work/view.php?'.api_get_cidreq().'&id='.$work['id'];
4280
    $subject = sprintf(get_lang('ThereIsANewWorkFeedback'), $parentWork['title']);
4281
    $content = sprintf(get_lang('ThereIsANewWorkFeedbackInWorkXHere'), $work['title'], $url);
4282
4283
    if (!empty($data['comment'])) {
4284
        $content .= '<br /><b>'.get_lang('Comment').':</b><br />'.$data['comment'];
4285
    }
4286
4287
    if (!empty($userIdListToSend)) {
4288
        foreach ($userIdListToSend as $userIdToSend) {
4289
            MessageManager::send_message_simple(
4290
                $userIdToSend,
4291
                $subject,
4292
                $content
4293
            );
4294
        }
4295
    }
4296
4297
    if (!empty($commentId) && !empty($fileData)) {
4298
        $workParent = get_work_data_by_id($work['parent_id']);
4299
        if (!empty($workParent)) {
4300
            $uploadDir = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/work'.$workParent['url'];
4301
            $newFileName = 'comment_'.$commentId.'_'.php2phps(api_replace_dangerous_char($fileData['name']));
4302
            $newFilePath = $uploadDir.'/'.$newFileName;
4303
            $result = move_uploaded_file($fileData['tmp_name'], $newFilePath);
4304
            if ($result) {
4305
                $params = ['file' => $newFileName];
4306
                Database::update(
4307
                    $commentTable,
4308
                    $params,
4309
                    ['id = ? AND c_id = ? ' => [$commentId, $work['c_id']]]
4310
                );
4311
            }
4312
        }
4313
    }
4314
}
4315
4316
/**
4317
 * @param array $work
4318
 * @param array $workParent
4319
 *
4320
 * @return string
4321
 */
4322
function getWorkCommentForm($work, $workParent)
4323
{
4324
    $url = api_get_path(WEB_CODE_PATH).'work/view.php?id='.$work['id'].'&action=send_comment&'.api_get_cidreq();
4325
    $form = new FormValidator(
4326
        'work_comment',
4327
        'post',
4328
        $url,
4329
        '',
4330
        ['enctype' => "multipart/form-data"]
4331
    );
4332
4333
    $qualification = $workParent['qualification'];
4334
4335
    $isCourseManager = api_is_platform_admin() || api_is_coach() || api_is_allowed_to_edit(false, false, true);
4336
    $allowEdition = false;
4337
    if ($isCourseManager) {
4338
        $allowEdition = true;
4339
        if (!empty($work['qualification']) && api_get_configuration_value('block_student_publication_score_edition')) {
4340
            $allowEdition = false;
4341
        }
4342
    }
4343
4344
    if (api_is_platform_admin()) {
4345
        $allowEdition = true;
4346
    }
4347
4348
    if ($allowEdition) {
4349
        if (!empty($qualification) && intval($qualification) > 0) {
4350
            $model = ExerciseLib::getCourseScoreModel();
4351
            if (empty($model)) {
4352
                $form->addFloat(
4353
                    'qualification',
4354
                    [get_lang('Qualification'), " / ".$qualification],
4355
                    false,
4356
                    [],
4357
                    false,
4358
                    0,
4359
                    $qualification
4360
                );
4361
            } else {
4362
                ExerciseLib::addScoreModelInput(
4363
                    $form,
4364
                    'qualification',
4365
                    $qualification,
4366
                    $work['qualification']
4367
                );
4368
            }
4369
            $form->addFile('file', get_lang('Correction'));
4370
            $form->setDefaults(['qualification' => $work['qualification']]);
4371
        }
4372
    }
4373
4374
    Skill::addSkillsToUserForm($form, ITEM_TYPE_STUDENT_PUBLICATION, $workParent['id'], $work['user_id'], $work['id']);
4375
    $form->addHtmlEditor('comment', get_lang('Comment'), false);
4376
    $form->addFile('attachment', get_lang('Attachment'));
4377
    $form->addElement('hidden', 'id', $work['id']);
4378
4379
    if (api_is_allowed_to_edit()) {
4380
        $form->addCheckBox(
4381
            'send_email',
4382
            null,
4383
            get_lang('SendMailToStudent')
4384
        );
4385
    }
4386
4387
    $form->addButtonSend(get_lang('Send'), 'button');
4388
4389
    return $form->returnForm();
4390
}
4391
4392
/**
4393
 * @param array $homework result of get_work_assignment_by_id()
4394
 *
4395
 * @return array
4396
 */
4397
function getWorkDateValidationStatus($homework)
4398
{
4399
    $message = null;
4400
    $has_expired = false;
4401
    $has_ended = false;
4402
4403
    if (!empty($homework)) {
4404
        if (!empty($homework['expires_on']) || !empty($homework['ends_on'])) {
4405
            $time_now = time();
4406
4407
            if (!empty($homework['expires_on'])) {
4408
                $time_expires = api_strtotime($homework['expires_on'], 'UTC');
4409
                $difference = $time_expires - $time_now;
4410
                if ($difference < 0) {
4411
                    $has_expired = true;
4412
                }
4413
            }
4414
4415
            if (empty($homework['expires_on'])) {
4416
                $has_expired = false;
4417
            }
4418
4419
            if (!empty($homework['ends_on'])) {
4420
                $time_ends = api_strtotime($homework['ends_on'], 'UTC');
4421
                $difference2 = $time_ends - $time_now;
4422
                if ($difference2 < 0) {
4423
                    $has_ended = true;
4424
                }
4425
            }
4426
4427
            $ends_on = api_convert_and_format_date($homework['ends_on']);
4428
            $expires_on = api_convert_and_format_date($homework['expires_on']);
4429
        }
4430
4431
        if ($has_ended) {
4432
            $message = Display::return_message(get_lang('EndDateAlreadyPassed').' '.$ends_on, 'error');
4433
        } elseif ($has_expired) {
4434
            $message = Display::return_message(get_lang('ExpiryDateAlreadyPassed').' '.$expires_on, 'warning');
4435
        } else {
4436
            if ($has_expired) {
4437
                $message = Display::return_message(get_lang('ExpiryDateToSendWorkIs').' '.$expires_on);
4438
            }
4439
        }
4440
    }
4441
4442
    return [
4443
        'message' => $message,
4444
        'has_ended' => $has_ended,
4445
        'has_expired' => $has_expired,
4446
    ];
4447
}
4448
4449
/**
4450
 * @param FormValidator $form
4451
 * @param int           $uploadFormType
4452
 */
4453
function setWorkUploadForm($form, $uploadFormType = 0)
4454
{
4455
    $form->addHeader(get_lang('UploadADocument'));
4456
    $form->addHidden('contains_file', 0, ['id' => 'contains_file_id']);
4457
    $form->addHidden('active', 1);
4458
    $form->addHidden('accepted', 1);
4459
    $form->addElement('text', 'title', get_lang('Title'), ['id' => 'file_upload']);
4460
    $form->addElement(
4461
        'text',
4462
        'extension',
4463
        get_lang('FileExtension'),
4464
        ['id' => 'file_extension', 'readonly' => 'readonly']
4465
    );
4466
    $form->addRule('title', get_lang('ThisFieldIsRequired'), 'required');
4467
4468
    switch ($uploadFormType) {
4469
        case 0:
4470
            // File and text.
4471
            $form->addElement(
4472
                'file',
4473
                'file',
4474
                get_lang('UploadADocument'),
4475
                'size="40" onchange="updateDocumentTitle(this.value)"'
4476
            );
4477
            $form->addProgress();
4478
            $form->addHtmlEditor('description', get_lang('Description'), false, false, getWorkDescriptionToolbar());
4479
            break;
4480
        case 1:
4481
            // Only text.
4482
            $form->addHtmlEditor('description', get_lang('Description'), false, false, getWorkDescriptionToolbar());
4483
            $form->addRule('description', get_lang('ThisFieldIsRequired'), 'required');
4484
            break;
4485
        case 2:
4486
            // Only file.
4487
            $form->addElement(
4488
                'file',
4489
                'file',
4490
                get_lang('UploadADocument'),
4491
                'size="40" onchange="updateDocumentTitle(this.value)"'
4492
            );
4493
            $form->addProgress();
4494
            $form->addRule('file', get_lang('ThisFieldIsRequired'), 'required');
4495
            break;
4496
    }
4497
4498
    $form->addButtonUpload(get_lang('Upload'), 'submitWork');
4499
}
4500
4501
/**
4502
 * @param array $my_folder_data
4503
 * @param array $_course
4504
 * @param bool  $isCorrection
4505
 * @param array $workInfo
4506
 * @param array $file
4507
 *
4508
 * @return array
4509
 */
4510
function uploadWork($my_folder_data, $_course, $isCorrection = false, $workInfo = [], $file = [])
4511
{
4512
    if (isset($_FILES['file']) && !empty($_FILES['file'])) {
4513
        $file = $_FILES['file'];
4514
    }
4515
4516
    if (empty($file['size'])) {
4517
        return [
4518
            'error' => Display:: return_message(
4519
                get_lang('UplUploadFailedSizeIsZero'),
4520
                'error'
4521
            ),
4522
        ];
4523
    }
4524
    $updir = api_get_path(SYS_COURSE_PATH).$_course['path'].'/work/'; //directory path to upload
4525
4526
    // Try to add an extension to the file if it has'nt one
4527
    $filename = add_ext_on_mime(stripslashes($file['name']), $file['type']);
4528
4529
    // Replace dangerous characters
4530
    $filename = api_replace_dangerous_char($filename);
4531
4532
    // Transform any .php file in .phps fo security
4533
    $filename = php2phps($filename);
4534
    $filesize = filesize($file['tmp_name']);
4535
4536
    if (empty($filesize)) {
4537
        return [
4538
            'error' => Display::return_message(
4539
                get_lang('UplUploadFailedSizeIsZero'),
4540
                'error'
4541
            ),
4542
        ];
4543
    } elseif (!filter_extension($new_file_name)) {
4544
        return [
4545
            'error' => Display::return_message(
4546
                get_lang('UplUnableToSaveFileFilteredExtension'),
4547
                'error'
4548
            ),
4549
        ];
4550
    }
4551
4552
    $totalSpace = DocumentManager::documents_total_space($_course['real_id']);
4553
    $course_max_space = DocumentManager::get_course_quota($_course['code']);
4554
    $total_size = $filesize + $totalSpace;
4555
4556
    if ($total_size > $course_max_space) {
4557
        return [
4558
            'error' => Display::return_message(get_lang('NoSpace'), 'error'),
4559
        ];
4560
    }
4561
4562
    // Compose a unique file name to avoid any conflict
4563
    $new_file_name = api_get_unique_id();
4564
4565
    if ($isCorrection) {
4566
        if (!empty($workInfo['url'])) {
4567
            $new_file_name = basename($workInfo['url']).'_correction';
4568
        } else {
4569
            $new_file_name = $new_file_name.'_correction';
4570
        }
4571
    }
4572
4573
    $curdirpath = basename($my_folder_data['url']);
4574
4575
    // If we come from the group tools the groupid will be saved in $work_table
4576
    if (is_dir($updir.$curdirpath) || empty($curdirpath)) {
4577
        $result = move_uploaded_file(
4578
            $file['tmp_name'],
4579
            $updir.$curdirpath.'/'.$new_file_name
4580
        );
4581
    } else {
4582
        return [
4583
            'error' => Display :: return_message(
4584
                get_lang('FolderDoesntExistsInFileSystem'),
4585
                'error'
4586
            ),
4587
        ];
4588
    }
4589
4590
    if ($result) {
4591
        $url = 'work/'.$curdirpath.'/'.$new_file_name;
4592
    } else {
4593
        return false;
4594
    }
4595
4596
    return [
4597
        'url' => $url,
4598
        'filename' => $filename,
4599
        'filesize' => $filesize,
4600
        'error' => '',
4601
    ];
4602
}
4603
4604
/**
4605
 * Send an e-mail to users related to this work.
4606
 *
4607
 * @param array $workInfo
4608
 * @param int   $workId
4609
 * @param array $courseInfo
4610
 * @param int   $sessionId
4611
 */
4612
function sendAlertToUsers($workInfo, $workId, $courseInfo, $sessionId = 0)
4613
{
4614
    $sessionId = (int) $sessionId;
4615
4616
    if (empty($workInfo) || empty($courseInfo) || empty($workId)) {
4617
        return false;
4618
    }
4619
4620
    $courseCode = $courseInfo['code'];
4621
4622
    $workData = get_work_data_by_id($workId, $courseInfo['real_id'], $sessionId);
4623
    // last value is to check this is not "just" an edit
4624
    // YW Tis part serve to send a e-mail to the tutors when a new file is sent
4625
    $send = api_get_course_setting('email_alert_manager_on_new_doc');
4626
4627
    $userList = [];
4628
    if ($send == SEND_EMAIL_EVERYONE || $send == SEND_EMAIL_TEACHERS) {
4629
        // Lets predefine some variables. Be sure to change the from address!
4630
        if (empty($sessionId)) {
4631
            // Teachers
4632
            $userList = CourseManager::get_user_list_from_course_code(
4633
                $courseCode,
4634
                null,
4635
                null,
4636
                null,
4637
                COURSEMANAGER
4638
            );
4639
        } else {
4640
            // Coaches
4641
            $userList = CourseManager::get_user_list_from_course_code(
4642
                $courseCode,
4643
                $sessionId,
4644
                null,
4645
                null,
4646
                2
4647
            );
4648
        }
4649
    }
4650
4651
    if ($send == SEND_EMAIL_EVERYONE || $send == SEND_EMAIL_STUDENTS) {
4652
        // Send mail only to sender
4653
        $studentList = [[
4654
           'user_id' => api_get_user_id(),
4655
        ]];
4656
        $userList = array_merge($userList, $studentList);
4657
    }
4658
4659
    if ($send) {
4660
        $folderUrl = api_get_path(WEB_CODE_PATH)."work/work_list_all.php?cidReq=".$courseInfo['code']."&id_session=".$sessionId."&id=".$workInfo['id'];
4661
        $fileUrl = api_get_path(WEB_CODE_PATH)."work/view.php?cidReq=".$courseInfo['code']."&id_session=".$sessionId."&id=".$workData['id'];
4662
4663
        foreach ($userList as $userData) {
4664
            $userId = $userData['user_id'];
4665
            $userInfo = api_get_user_info($userId);
4666
            if (empty($userInfo)) {
4667
                continue;
4668
            }
4669
4670
            $userPostedADocument = sprintf(
4671
                get_lang('UserXPostedADocumentInCourseX'),
4672
                $userInfo['complete_name'],
4673
                $courseInfo['name']
4674
            );
4675
4676
            $subject = "[".api_get_setting('siteName')."] ".$userPostedADocument;
4677
            $message = $userPostedADocument."<br />";
4678
            $message .= get_lang('DateSent')." : ".api_format_date(api_get_local_time())."<br />";
4679
            $message .= get_lang('AssignmentName')." : ".Display::url($workInfo['title'], $folderUrl)."<br />";
4680
            $message .= get_lang('Filename')." : ".$workData['title']."<br />";
4681
            $message .= '<a href="'.$fileUrl.'">'.get_lang('DownloadLink')."</a><br />";
4682
4683
            MessageManager::send_message_simple(
4684
                $userId,
4685
                $subject,
4686
                $message,
4687
                0,
4688
                false,
4689
                false,
4690
                [],
4691
                false
4692
            );
4693
        }
4694
    }
4695
}
4696
4697
/**
4698
 * Check if the current uploaded work filename already exists in the current assement.
4699
 *
4700
 * @param string $filename
4701
 * @param int    $workId
4702
 *
4703
 * @return array
4704
 */
4705
function checkExistingWorkFileName($filename, $workId)
4706
{
4707
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
4708
    $filename = Database::escape_string($filename);
4709
    $workId = (int) $workId;
4710
4711
    $sql = "SELECT title FROM $table
4712
            WHERE parent_id = $workId AND title = '$filename' AND active = 1";
4713
    $result = Database::query($sql);
4714
4715
    return Database::fetch_assoc($result);
4716
}
4717
4718
/**
4719
 * @param array $workInfo
4720
 * @param array $values
4721
 * @param array $courseInfo
4722
 * @param int   $sessionId
4723
 * @param int   $groupId
4724
 * @param int   $userId
4725
 * @param array $file
4726
 * @param bool  $checkDuplicated
4727
 * @param bool  $showFlashMessage
4728
 *
4729
 * @return string|null
4730
 */
4731
function processWorkForm(
4732
    $workInfo,
4733
    $values,
4734
    $courseInfo,
4735
    $sessionId,
4736
    $groupId,
4737
    $userId,
4738
    $file = [],
4739
    $checkDuplicated = false,
4740
    $showFlashMessage = true
4741
) {
4742
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
4743
4744
    $courseId = $courseInfo['real_id'];
4745
    $groupId = (int) $groupId;
4746
    $sessionId = (int) $sessionId;
4747
    $userId = (int) $userId;
4748
4749
    $extension = '';
4750
    if (isset($values['extension'])) {
4751
        $extension = $values['extension'];
4752
    } else {
4753
        $fileInfo = pathinfo($values['title']);
4754
        if (isset($fileInfo['extension']) && !empty($fileInfo['extension'])) {
4755
            $extension = '.'.$fileInfo['extension'];
4756
            $values['title'] = $fileInfo['filename'];
4757
        }
4758
    }
4759
4760
    $title = $values['title'].$extension;
4761
    $description = isset($values['description']) ? $values['description'] : '';
4762
    $containsFile = isset($values['contains_file']) && !empty($values['contains_file']) ? (int) $values['contains_file'] : 0;
4763
4764
    $saveWork = true;
4765
    $filename = null;
4766
    $url = null;
4767
    $filesize = null;
4768
    $workData = [];
4769
    $message = null;
4770
4771
    if ($containsFile) {
4772
        $saveWork = false;
4773
        if ($checkDuplicated) {
4774
            if (checkExistingWorkFileName($file['name'], $workInfo['id'])) {
4775
                $saveWork = false;
4776
                $result['error'] = get_lang('YouAlreadySentThisFile');
4777
                $workData['error'] = get_lang('UplAlreadyExists');
4778
            } else {
4779
                $result = uploadWork($workInfo, $courseInfo, false, [], $file);
4780
            }
4781
        } else {
4782
            $result = uploadWork($workInfo, $courseInfo, false, [], $file);
4783
        }
4784
4785
        if (isset($result['error'])) {
4786
            $saveWork = false;
4787
            if ($showFlashMessage) {
4788
                $message = $result['error'];
4789
            }
4790
            if (empty($result['error']) && isset($result['url']) && !empty($result['url'])) {
4791
                $saveWork = true;
4792
            }
4793
        }
4794
    }
4795
4796
    if ($saveWork) {
4797
        $filename = isset($result['filename']) ? $result['filename'] : null;
4798
        if (empty($title)) {
4799
            $title = isset($result['title']) && !empty($result['title']) ? $result['title'] : get_lang('Untitled');
4800
        }
4801
        $filesize = isset($result['filesize']) ? $result['filesize'] : null;
4802
        $url = isset($result['url']) ? $result['url'] : null;
4803
    }
4804
4805
    if (empty($title)) {
4806
        $title = get_lang('Untitled');
4807
    }
4808
4809
    $groupIid = 0;
4810
    $groupInfo = [];
4811
    if ($groupId) {
4812
        $groupInfo = GroupManager::get_group_properties($groupId);
4813
        $groupIid = $groupInfo['iid'];
4814
    }
4815
4816
    if ($saveWork) {
4817
        $active = '1';
4818
        $params = [
4819
            'c_id' => $courseId,
4820
            'url' => $url,
4821
            'filetype' => 'file',
4822
            'title' => $title,
4823
            'description' => $description,
4824
            'contains_file' => $containsFile,
4825
            'active' => $active,
4826
            'accepted' => '1',
4827
            'qualificator_id' => 0,
4828
            'document_id' => 0,
4829
            'weight' => 0,
4830
            'allow_text_assignment' => 0,
4831
            'post_group_id' => $groupIid,
4832
            'sent_date' => api_get_utc_datetime(),
4833
            'parent_id' => $workInfo['id'],
4834
            'session_id' => $sessionId ? $sessionId : null,
4835
            'user_id' => $userId,
4836
            'has_properties' => 0,
4837
            'qualification' => 0,
4838
            //'filesize' => $filesize
4839
        ];
4840
        $workId = Database::insert($work_table, $params);
4841
4842
        if ($workId) {
4843
            $sql = "UPDATE $work_table SET id = iid WHERE iid = $workId ";
4844
            Database::query($sql);
4845
4846
            if (array_key_exists('filename', $workInfo) && !empty($filename)) {
4847
                $filename = Database::escape_string($filename);
4848
                $sql = "UPDATE $work_table SET
4849
                            filename = '$filename'
4850
                        WHERE iid = $workId";
4851
                Database::query($sql);
4852
            }
4853
4854
            if (array_key_exists('document_id', $workInfo)) {
4855
                $documentId = isset($values['document_id']) ? (int) $values['document_id'] : 0;
4856
                $sql = "UPDATE $work_table SET
4857
                            document_id = '$documentId'
4858
                        WHERE iid = $workId";
4859
                Database::query($sql);
4860
            }
4861
4862
            api_item_property_update(
4863
                $courseInfo,
4864
                'work',
4865
                $workId,
4866
                'DocumentAdded',
4867
                $userId,
4868
                $groupInfo
4869
            );
4870
            sendAlertToUsers($workInfo, $workId, $courseInfo, $sessionId);
4871
            Event::event_upload($workId);
4872
4873
            // The following feature requires the creation of a work-type
4874
            // extra_field and the following setting in the configuration file
4875
            // (until moved to the database). It allows te teacher to set a
4876
            // "considered work time", meaning the time we assume a student
4877
            // would have spent, approximately, to prepare the task before
4878
            // handing it in Chamilo, adding this time to the student total
4879
            // course use time, as a register of time spent *before* his
4880
            // connection to the platform to hand the work in.
4881
            $consideredWorkingTime = api_get_configuration_value('considered_working_time');
4882
4883
            if (!empty($consideredWorkingTime)) {
4884
                // Get the "considered work time" defined for this work
4885
                $fieldValue = new ExtraFieldValue('work');
4886
                $resultExtra = $fieldValue->getAllValuesForAnItem(
4887
                    $workInfo['iid'], //the ID of the work *folder*, not the document uploaded by the student
4888
                    true
4889
                );
4890
4891
                $workingTime = null;
4892
                foreach ($resultExtra as $field) {
4893
                    $field = $field['value'];
4894
                    if ($consideredWorkingTime == $field->getField()->getVariable()) {
4895
                        $workingTime = $field->getValue();
4896
                    }
4897
                }
4898
4899
                // If no time was defined, or a time of "0" was set, do nothing
4900
                if (!empty($workingTime)) {
4901
                    // If some time is set, get the list of docs handed in by
4902
                    // this student (to make sure we count the time only once)
4903
                    $userWorks = get_work_user_list(
4904
                        0,
4905
                        100,
4906
                        null,
4907
                        null,
4908
                        $workInfo['id'],
4909
                        null,
4910
                        $userId,
4911
                        false,
4912
                        $courseId,
4913
                        $sessionId
4914
                    );
4915
4916
                    if (1 == count($userWorks)) {
4917
                        // The student only uploaded one doc so far, so add the
4918
                        // considered work time to his course connection time
4919
                        Event::eventAddVirtualCourseTime(
4920
                            $courseId,
4921
                            $userId,
4922
                            $sessionId,
4923
                            $workingTime,
4924
                            $workInfo['iid']
4925
                        );
4926
                    }
4927
                }
4928
            }
4929
            $workData = get_work_data_by_id($workId);
4930
            if ($workData && $showFlashMessage) {
4931
                Display::addFlash(Display::return_message(get_lang('DocAdd')));
4932
            }
4933
        }
4934
    } else {
4935
        if ($showFlashMessage) {
4936
            Display::addFlash(
4937
                Display::return_message(
4938
                    $message ? $message : get_lang('ImpossibleToSaveTheDocument'),
4939
                    'error'
4940
                )
4941
            );
4942
        }
4943
    }
4944
4945
    return $workData;
4946
}
4947
4948
/**
4949
 * Creates a new task (directory) in the assignment tool.
4950
 *
4951
 * @param array $formValues
4952
 * @param int   $user_id
4953
 * @param array $courseInfo
4954
 * @param int   $groupId
4955
 * @param int   $sessionId
4956
 *
4957
 * @return bool|int
4958
 * @note $params can have the following elements, but should at least have the 2 first ones: (
4959
 *       'new_dir' => 'some-name',
4960
 *       'description' => 'some-desc',
4961
 *       'qualification' => 20 (e.g. 20),
4962
 *       'weight' => 50 (percentage) to add to gradebook (e.g. 50),
4963
 *       'allow_text_assignment' => 0/1/2,
4964
 *
4965
 * @todo Rename createAssignment or createWork, or something like that
4966
 */
4967
function addDir($formValues, $user_id, $courseInfo, $groupId, $sessionId = 0)
4968
{
4969
    $em = Database::getManager();
4970
4971
    $user_id = (int) $user_id;
4972
    $groupId = (int) $groupId;
4973
    $sessionId = (int) $sessionId;
4974
4975
    $groupIid = 0;
4976
    $groupInfo = [];
4977
    if (!empty($groupId)) {
4978
        $groupInfo = GroupManager::get_group_properties($groupId);
4979
        $groupIid = $groupInfo['iid'];
4980
    }
4981
    $session = $em->find('ChamiloCoreBundle:Session', $sessionId);
4982
4983
    $base_work_dir = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/work';
4984
    $course_id = $courseInfo['real_id'];
4985
4986
    $directory = api_replace_dangerous_char($formValues['new_dir']);
4987
    $directory = disable_dangerous_file($directory);
4988
4989
    if (strlen($directory) > CStudentPublication::WORK_TITLE_MAX_LENGTH) {
4990
        $directory = api_substr($directory, 0, CStudentPublication::WORK_TITLE_MAX_LENGTH);
4991
    }
4992
4993
    $created_dir = create_unexisting_work_directory($base_work_dir, $directory);
4994
4995
    if (empty($created_dir)) {
4996
        return false;
4997
    }
4998
4999
    $enableEndDate = isset($formValues['enableEndDate']) ? true : false;
5000
    $enableExpiryDate = isset($formValues['enableExpiryDate']) ? true : false;
5001
5002
    if ($enableEndDate && $enableExpiryDate) {
5003
        if ($formValues['expires_on'] > $formValues['ends_on']) {
5004
            Display::addFlash(
5005
                Display::return_message(
5006
                    get_lang('DateExpiredNotBeLessDeadLine'),
5007
                    'warning'
5008
                )
5009
            );
5010
5011
            return false;
5012
        }
5013
    }
5014
5015
    $dirName = '/'.$created_dir;
5016
    $today = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
5017
    $title = isset($formValues['work_title']) ? $formValues['work_title'] : $formValues['new_dir'];
5018
5019
    $workTable = new CStudentPublication();
5020
    $workTable
5021
        ->setCId($course_id)
5022
        ->setUrl($dirName)
5023
        ->setTitle($title)
5024
        ->setDescription($formValues['description'])
5025
        ->setActive(true)
5026
        ->setAccepted(true)
5027
        ->setFiletype('folder')
5028
        ->setPostGroupId($groupIid)
5029
        ->setSentDate($today)
5030
        ->setQualification($formValues['qualification'] != '' ? $formValues['qualification'] : 0)
5031
        ->setParentId(0)
5032
        ->setQualificatorId(0)
5033
        ->setWeight(!empty($formValues['weight']) ? $formValues['weight'] : 0)
5034
        ->setSession($session)
5035
        ->setAllowTextAssignment($formValues['allow_text_assignment'])
5036
        ->setContainsFile(0)
5037
        ->setUserId($user_id)
5038
        ->setHasProperties(0)
5039
        ->setDocumentId(0);
5040
5041
    $em->persist($workTable);
5042
    $em->flush();
5043
5044
    $workTable->setId($workTable->getIid());
5045
    $em->merge($workTable);
5046
    $em->flush();
5047
5048
    // Folder created
5049
    api_item_property_update(
5050
        $courseInfo,
5051
        'work',
5052
        $workTable->getIid(),
5053
        'DirectoryCreated',
5054
        $user_id,
5055
        $groupInfo
5056
    );
5057
5058
    updatePublicationAssignment(
5059
        $workTable->getIid(),
5060
        $formValues,
5061
        $courseInfo,
5062
        $groupIid
5063
    );
5064
5065
    // Added the new Work ID to the extra field values
5066
    $formValues['item_id'] = $workTable->getIid();
5067
5068
    $workFieldValue = new ExtraFieldValue('work');
5069
    $workFieldValue->saveFieldValues($formValues);
5070
5071
    $sendEmailAlert = api_get_course_setting('email_alert_students_on_new_homework');
5072
5073
    switch ($sendEmailAlert) {
5074
        case 1:
5075
            sendEmailToStudentsOnHomeworkCreation(
5076
                $workTable->getIid(),
5077
                $course_id,
5078
                $sessionId
5079
            );
5080
            //no break
5081
        case 2:
5082
            sendEmailToDrhOnHomeworkCreation(
5083
                $workTable->getIid(),
5084
                $course_id,
5085
                $sessionId
5086
            );
5087
            break;
5088
    }
5089
5090
    return $workTable->getIid();
5091
}
5092
5093
/**
5094
 * @param int   $workId
5095
 * @param array $courseInfo
5096
 *
5097
 * @return int
5098
 */
5099
function agendaExistsForWork($workId, $courseInfo)
5100
{
5101
    $workTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
5102
    $courseId = $courseInfo['real_id'];
5103
    $workId = (int) $workId;
5104
5105
    $sql = "SELECT add_to_calendar FROM $workTable
5106
            WHERE c_id = $courseId AND publication_id = ".$workId;
5107
    $res = Database::query($sql);
5108
    if (Database::num_rows($res)) {
5109
        $row = Database::fetch_array($res, 'ASSOC');
5110
        if (!empty($row['add_to_calendar'])) {
5111
            return $row['add_to_calendar'];
5112
        }
5113
    }
5114
5115
    return 0;
5116
}
5117
5118
/**
5119
 * Update work description, qualification, weight, allow_text_assignment.
5120
 *
5121
 * @param int   $workId     (iid)
5122
 * @param array $params
5123
 * @param array $courseInfo
5124
 * @param int   $sessionId
5125
 */
5126
function updateWork($workId, $params, $courseInfo, $sessionId = 0)
5127
{
5128
    $workTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
5129
    $filteredParams = [
5130
        'description' => $params['description'],
5131
        'qualification' => $params['qualification'],
5132
        'weight' => $params['weight'],
5133
        'allow_text_assignment' => $params['allow_text_assignment'],
5134
    ];
5135
5136
    Database::update(
5137
        $workTable,
5138
        $filteredParams,
5139
        [
5140
            'iid = ? AND c_id = ?' => [
5141
                $workId,
5142
                $courseInfo['real_id'],
5143
            ],
5144
        ]
5145
    );
5146
5147
    $workFieldValue = new ExtraFieldValue('work');
5148
    $workFieldValue->saveFieldValues($params);
5149
}
5150
5151
/**
5152
 * @param int   $workId
5153
 * @param array $params
5154
 * @param array $courseInfo
5155
 * @param int   $groupId
5156
 */
5157
function updatePublicationAssignment($workId, $params, $courseInfo, $groupId)
5158
{
5159
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
5160
    $workTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
5161
    $workId = (int) $workId;
5162
    $now = api_get_utc_datetime();
5163
    $course_id = $courseInfo['real_id'];
5164
5165
    // Insert into agenda
5166
    $agendaId = 0;
5167
    if (isset($params['add_to_calendar']) && $params['add_to_calendar'] == 1) {
5168
        // Setting today date
5169
        $date = $end_date = $now;
5170
5171
        if (isset($params['enableExpiryDate'])) {
5172
            $end_date = $params['expires_on'];
5173
            $date = $end_date;
5174
        }
5175
5176
        $title = sprintf(get_lang('HandingOverOfTaskX'), $params['new_dir']);
5177
        $description = isset($params['description']) ? $params['description'] : '';
5178
        $content = '<a href="'.api_get_path(WEB_CODE_PATH).'work/work_list.php?'.api_get_cidreq().'&id='.$workId.'">'
5179
            .$params['new_dir'].'</a>'.$description;
5180
5181
        $agendaId = agendaExistsForWork($workId, $courseInfo);
5182
5183
        // Add/edit agenda
5184
        $agenda = new Agenda('course');
5185
        $agenda->set_course($courseInfo);
5186
5187
        if (!empty($agendaId)) {
5188
            // add_to_calendar is set but it doesnt exists then invalidate
5189
            $eventInfo = $agenda->get_event($agendaId);
5190
            if (empty($eventInfo)) {
5191
                $agendaId = 0;
5192
            }
5193
        }
5194
5195
        $eventColor = $agenda->eventStudentPublicationColor;
5196
5197
        if (empty($agendaId)) {
5198
            $agendaId = $agenda->addEvent(
5199
                $date,
5200
                $end_date,
5201
                'false',
5202
                $title,
5203
                $content,
5204
                ['GROUP:'.$groupId],
5205
                false,
5206
                null,
5207
                [],
5208
                [],
5209
                null,
5210
                $eventColor
5211
            );
5212
        } else {
5213
            $agenda->editEvent(
5214
                $agendaId,
5215
                $end_date,
5216
                $end_date,
5217
                'false',
5218
                $title,
5219
                $content,
5220
                [],
5221
                [],
5222
                [],
5223
                null,
5224
                $eventColor
5225
            );
5226
        }
5227
    }
5228
5229
    $qualification = isset($params['qualification']) && !empty($params['qualification']) ? 1 : 0;
5230
    $expiryDate = isset($params['enableExpiryDate']) && (int) $params['enableExpiryDate'] == 1 ? api_get_utc_datetime($params['expires_on']) : '';
5231
    $endDate = isset($params['enableEndDate']) && (int) $params['enableEndDate'] == 1 ? api_get_utc_datetime($params['ends_on']) : '';
5232
    $data = get_work_assignment_by_id($workId, $course_id);
5233
    if (!empty($expiryDate)) {
5234
        $expiryDateCondition = "expires_on = '".Database::escape_string($expiryDate)."', ";
5235
    } else {
5236
        $expiryDateCondition = "expires_on = null, ";
5237
    }
5238
5239
    if (!empty($endDate)) {
5240
        $endOnCondition = "ends_on = '".Database::escape_string($endDate)."', ";
5241
    } else {
5242
        $endOnCondition = 'ends_on = null, ';
5243
    }
5244
5245
    if (empty($data)) {
5246
        $sql = "INSERT INTO $table SET
5247
                c_id = $course_id ,
5248
                $expiryDateCondition
5249
                $endOnCondition
5250
                add_to_calendar = $agendaId,
5251
                enable_qualification = '$qualification',
5252
                publication_id = '$workId'";
5253
        Database::query($sql);
5254
        $my_last_id = Database::insert_id();
5255
5256
        if ($my_last_id) {
5257
            $sql = "UPDATE $table SET
5258
                        id = iid
5259
                    WHERE iid = $my_last_id";
5260
            Database::query($sql);
5261
5262
            $sql = "UPDATE $workTable SET
5263
                        has_properties  = $my_last_id,
5264
                        view_properties = 1
5265
                    WHERE c_id = $course_id AND id = $workId";
5266
            Database::query($sql);
5267
        }
5268
    } else {
5269
        $sql = "UPDATE $table SET
5270
                    $expiryDateCondition
5271
                    $endOnCondition
5272
                    add_to_calendar  = $agendaId,
5273
                    enable_qualification = '".$qualification."'
5274
                WHERE
5275
                    publication_id = $workId AND
5276
                    c_id = $course_id AND
5277
                    iid = ".$data['iid'];
5278
        Database::query($sql);
5279
    }
5280
5281
    if (!empty($params['category_id'])) {
5282
        $link_info = GradebookUtils::isResourceInCourseGradebook(
5283
            $courseInfo['code'],
5284
            LINK_STUDENTPUBLICATION,
5285
            $workId,
5286
            api_get_session_id()
5287
        );
5288
5289
        $linkId = null;
5290
        if (!empty($link_info)) {
5291
            $linkId = $link_info['id'];
5292
        }
5293
5294
        if (isset($params['make_calification']) &&
5295
            $params['make_calification'] == 1
5296
        ) {
5297
            if (empty($linkId)) {
5298
                GradebookUtils::add_resource_to_course_gradebook(
5299
                    $params['category_id'],
5300
                    $courseInfo['code'],
5301
                    LINK_STUDENTPUBLICATION,
5302
                    $workId,
5303
                    $params['new_dir'],
5304
                    api_float_val($params['weight']),
5305
                    api_float_val($params['qualification']),
5306
                    $params['description'],
5307
                    1,
5308
                    api_get_session_id()
5309
                );
5310
            } else {
5311
                GradebookUtils::updateResourceFromCourseGradebook(
5312
                    $linkId,
5313
                    $courseInfo['code'],
5314
                    $params['weight']
5315
                );
5316
            }
5317
        } else {
5318
            // Delete everything of the gradebook for this $linkId
5319
            GradebookUtils::remove_resource_from_course_gradebook($linkId);
5320
        }
5321
    }
5322
}
5323
5324
/**
5325
 * Delete all work by student.
5326
 *
5327
 * @param int   $userId
5328
 * @param array $courseInfo
5329
 *
5330
 * @return array return deleted items
5331
 */
5332
function deleteAllWorkPerUser($userId, $courseInfo)
5333
{
5334
    $deletedItems = [];
5335
    $workPerUser = getWorkPerUser($userId);
5336
    if (!empty($workPerUser)) {
5337
        foreach ($workPerUser as $work) {
5338
            $work = $work['work'];
5339
            foreach ($work->user_results as $userResult) {
5340
                $result = deleteWorkItem($userResult['id'], $courseInfo);
5341
                if ($result) {
5342
                    $deletedItems[] = $userResult;
5343
                }
5344
            }
5345
        }
5346
    }
5347
5348
    return $deletedItems;
5349
}
5350
5351
/**
5352
 * @param int   $item_id
5353
 * @param array $courseInfo course info
5354
 *
5355
 * @return bool
5356
 */
5357
function deleteWorkItem($item_id, $courseInfo)
5358
{
5359
    $item_id = (int) $item_id;
5360
5361
    if (empty($item_id) || empty($courseInfo)) {
5362
        return false;
5363
    }
5364
5365
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
5366
    $TSTDPUBASG = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
5367
    $currentCourseRepositorySys = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/';
5368
    $is_allowed_to_edit = api_is_allowed_to_edit();
5369
    $file_deleted = false;
5370
    $is_author = user_is_author($item_id);
5371
    $work_data = get_work_data_by_id($item_id);
5372
    $locked = api_resource_is_locked_by_gradebook($work_data['parent_id'], LINK_STUDENTPUBLICATION);
5373
    $course_id = $courseInfo['real_id'];
5374
5375
    if (($is_allowed_to_edit && $locked == false) ||
5376
        (
5377
            $locked == false &&
5378
            $is_author &&
5379
            api_get_course_setting('student_delete_own_publication') == 1 &&
5380
            $work_data['qualificator_id'] == 0
5381
        )
5382
    ) {
5383
        // We found the current user is the author
5384
        $sql = "SELECT url, contains_file, user_id, session_id, parent_id
5385
                FROM $work_table
5386
                WHERE c_id = $course_id AND id = $item_id";
5387
        $result = Database::query($sql);
5388
        $row = Database::fetch_array($result);
5389
        $count = Database::num_rows($result);
5390
5391
        if ($count > 0) {
5392
            // If the "considered_working_time" option is enabled, check
5393
            // whether some time should be removed from track_e_course_access
5394
            $consideredWorkingTime = api_get_configuration_value('considered_working_time');
5395
            if ($consideredWorkingTime) {
5396
                $userWorks = get_work_user_list(
5397
                    0,
5398
                    100,
5399
                    null,
5400
                    null,
5401
                    $row['parent_id'],
5402
                    null,
5403
                    $row['user_id'],
5404
                    false,
5405
                    $course_id,
5406
                    $row['session_id']
5407
                );
5408
                // We're only interested in deleting the time if this is the latest work sent
5409
                if (count($userWorks) == 1) {
5410
                    // Get the "considered work time" defined for this work
5411
                    $fieldValue = new ExtraFieldValue('work');
5412
                    $resultExtra = $fieldValue->getAllValuesForAnItem(
5413
                        $row['parent_id'],
5414
                        true
5415
                    );
5416
5417
                    $workingTime = null;
5418
                    foreach ($resultExtra as $field) {
5419
                        $field = $field['value'];
5420
5421
                        if ($consideredWorkingTime == $field->getField()->getVariable()) {
5422
                            $workingTime = $field->getValue();
5423
                        }
5424
                    }
5425
                    // If no time was defined, or a time of "0" was set, do nothing
5426
                    if (!empty($workingTime)) {
5427
                        $sessionId = empty($row['session_id']) ? 0 : $row['session_id'];
5428
                        // Getting false from the following call would mean the
5429
                        // time record
5430
                        Event::eventRemoveVirtualCourseTime(
5431
                            $course_id,
5432
                            $row['user_id'],
5433
                            $sessionId,
5434
                            $workingTime,
5435
                            $row['parent_id']
5436
                        );
5437
                    }
5438
                }
5439
            } // end of considered_working_time check section
5440
5441
            $sql = "UPDATE $work_table SET active = 2
5442
                    WHERE c_id = $course_id AND id = $item_id";
5443
            Database::query($sql);
5444
            $sql = "DELETE FROM $TSTDPUBASG
5445
                    WHERE c_id = $course_id AND publication_id = $item_id";
5446
            Database::query($sql);
5447
5448
            Compilatio::plagiarismDeleteDoc($course_id, $item_id);
5449
5450
            api_item_property_update(
5451
                $courseInfo,
5452
                'work',
5453
                $item_id,
5454
                'DocumentDeleted',
5455
                api_get_user_id()
5456
            );
5457
5458
            Event::addEvent(
5459
                LOG_WORK_FILE_DELETE,
5460
                LOG_WORK_DATA,
5461
                [
5462
                    'id' => $work_data['id'],
5463
                    'url' => $work_data['url'],
5464
                    'title' => $work_data['title'],
5465
                ],
5466
                null,
5467
                api_get_user_id(),
5468
                api_get_course_int_id(),
5469
                api_get_session_id()
5470
            );
5471
5472
            $work = $row['url'];
5473
5474
            if ($row['contains_file'] == 1) {
5475
                if (!empty($work)) {
5476
                    if (api_get_setting('permanently_remove_deleted_files') === 'true') {
5477
                        my_delete($currentCourseRepositorySys.'/'.$work);
5478
                        $file_deleted = true;
5479
                    } else {
5480
                        $extension = pathinfo($work, PATHINFO_EXTENSION);
5481
                        $new_dir = $work.'_DELETED_'.$item_id.'.'.$extension;
5482
5483
                        if (file_exists($currentCourseRepositorySys.'/'.$work)) {
5484
                            rename($currentCourseRepositorySys.'/'.$work, $currentCourseRepositorySys.'/'.$new_dir);
5485
                            $file_deleted = true;
5486
                        }
5487
                    }
5488
                }
5489
            } else {
5490
                $file_deleted = true;
5491
            }
5492
        }
5493
    }
5494
5495
    return $file_deleted;
5496
}
5497
5498
/**
5499
 * @param FormValidator $form
5500
 * @param array         $defaults
5501
 * @param int           $workId
5502
 *
5503
 * @return FormValidator
5504
 */
5505
function getFormWork($form, $defaults = [], $workId = 0)
5506
{
5507
    $sessionId = api_get_session_id();
5508
    if (!empty($defaults)) {
5509
        if (isset($defaults['submit'])) {
5510
            unset($defaults['submit']);
5511
        }
5512
    }
5513
5514
    // Create the form that asks for the directory name
5515
    $form->addText(
5516
        'new_dir',
5517
        get_lang('AssignmentName'),
5518
        true,
5519
        ['maxlength' => 255]
5520
    );
5521
    $form->addHtmlEditor(
5522
        'description',
5523
        get_lang('Description'),
5524
        false,
5525
        false,
5526
        getWorkDescriptionToolbar()
5527
    );
5528
    $form->addButtonAdvancedSettings('advanced_params', get_lang('AdvancedParameters'));
5529
5530
    if (!empty($defaults) && (isset($defaults['enableEndDate']) || isset($defaults['enableExpiryDate']))) {
5531
        $form->addHtml('<div id="advanced_params_options" style="display:block">');
5532
    } else {
5533
        $form->addHtml('<div id="advanced_params_options" style="display:none">');
5534
    }
5535
5536
    // QualificationOfAssignment
5537
    $form->addElement('text', 'qualification', get_lang('QualificationNumeric'));
5538
5539
    if (($sessionId != 0 && Gradebook::is_active()) || $sessionId == 0) {
5540
        $form->addElement(
5541
            'checkbox',
5542
            'make_calification',
5543
            null,
5544
            get_lang('MakeQualifiable'),
5545
            [
5546
                'id' => 'make_calification_id',
5547
                'onclick' => "javascript: if(this.checked) { document.getElementById('option1').style.display='block';}else{document.getElementById('option1').style.display='none';}",
5548
            ]
5549
        );
5550
    } else {
5551
        // QualificationOfAssignment
5552
        $form->addElement('hidden', 'make_calification', false);
5553
    }
5554
5555
    if (!empty($defaults) && isset($defaults['category_id'])) {
5556
        $form->addHtml('<div id=\'option1\' style="display:block">');
5557
    } else {
5558
        $form->addHtml('<div id=\'option1\' style="display:none">');
5559
    }
5560
5561
    // Loading Gradebook select
5562
    GradebookUtils::load_gradebook_select_in_tool($form);
5563
5564
    $form->addElement('text', 'weight', get_lang('WeightInTheGradebook'));
5565
    $form->addHtml('</div>');
5566
5567
    $form->addElement('checkbox', 'enableExpiryDate', null, get_lang('EnableExpiryDate'), 'id="expiry_date"');
5568
    if (isset($defaults['enableExpiryDate']) && $defaults['enableExpiryDate']) {
5569
        $form->addHtml('<div id="option2" style="display: block;">');
5570
    } else {
5571
        $form->addHtml('<div id="option2" style="display: none;">');
5572
    }
5573
5574
    $timeNextWeek = time() + 86400 * 7;
5575
    $nextWeek = substr(api_get_local_time($timeNextWeek), 0, 10);
5576
    if (!isset($defaults['expires_on'])) {
5577
        $date = substr($nextWeek, 0, 10);
5578
        $defaults['expires_on'] = $date.' 23:59';
5579
    }
5580
5581
    $form->addElement('date_time_picker', 'expires_on', get_lang('ExpiresAt'));
5582
    $form->addHtml('</div>');
5583
    $form->addElement('checkbox', 'enableEndDate', null, get_lang('EnableEndDate'), 'id="end_date"');
5584
5585
    if (!isset($defaults['ends_on'])) {
5586
        $nextDay = substr(api_get_local_time($timeNextWeek + 86400), 0, 10);
5587
        $date = substr($nextDay, 0, 10);
5588
        $defaults['ends_on'] = $date.' 23:59';
5589
    }
5590
    if (isset($defaults['enableEndDate']) && $defaults['enableEndDate']) {
5591
        $form->addHtml('<div id="option3" style="display: block;">');
5592
    } else {
5593
        $form->addHtml('<div id="option3" style="display: none;">');
5594
    }
5595
5596
    $form->addElement('date_time_picker', 'ends_on', get_lang('EndsAt'));
5597
    $form->addHtml('</div>');
5598
5599
    $form->addElement('checkbox', 'add_to_calendar', null, get_lang('AddToCalendar'));
5600
    $form->addElement('select', 'allow_text_assignment', get_lang('DocumentType'), getUploadDocumentType());
5601
5602
    // Extra fields
5603
    $extraField = new ExtraField('work');
5604
    $extra = $extraField->addElements($form, $workId);
5605
5606
    $htmlHeadXtra[] = '
5607
        <script>
5608
        $(function() {
5609
            '.$extra['jquery_ready_content'].'
5610
        });
5611
        </script>';
5612
5613
    $form->addHtml('</div>');
5614
5615
    $skillList = Skill::addSkillsToForm($form, ITEM_TYPE_STUDENT_PUBLICATION, $workId);
5616
5617
    if (!empty($defaults)) {
5618
        $defaults['skills'] = array_keys($skillList);
5619
        $form->setDefaults($defaults);
5620
    }
5621
5622
    return $form;
5623
}
5624
5625
/**
5626
 * @return array
5627
 */
5628
function getUploadDocumentType()
5629
{
5630
    return [
5631
        0 => get_lang('AllowFileOrText'),
5632
        1 => get_lang('AllowOnlyText'),
5633
        2 => get_lang('AllowOnlyFiles'),
5634
    ];
5635
}
5636
5637
/**
5638
 * @param int   $itemId
5639
 * @param array $course_info
5640
 *
5641
 * @return bool
5642
 */
5643
function makeVisible($itemId, $course_info)
5644
{
5645
    $itemId = (int) $itemId;
5646
    if (empty($course_info) || empty($itemId)) {
5647
        return false;
5648
    }
5649
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
5650
    $course_id = $course_info['real_id'];
5651
5652
    $sql = "UPDATE $work_table SET accepted = 1
5653
            WHERE c_id = $course_id AND id = $itemId";
5654
    Database::query($sql);
5655
    api_item_property_update($course_info, 'work', $itemId, 'visible', api_get_user_id());
5656
5657
    return true;
5658
}
5659
5660
/**
5661
 * @param int   $itemId
5662
 * @param array $course_info
5663
 *
5664
 * @return int
5665
 */
5666
function makeInvisible($itemId, $course_info)
5667
{
5668
    $itemId = (int) $itemId;
5669
    if (empty($course_info) || empty($itemId)) {
5670
        return false;
5671
    }
5672
5673
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
5674
    $course_id = $course_info['real_id'];
5675
    $sql = "UPDATE $table
5676
            SET accepted = 0
5677
            WHERE c_id = $course_id AND id = '".$itemId."'";
5678
    Database::query($sql);
5679
    api_item_property_update(
5680
        $course_info,
5681
        'work',
5682
        $itemId,
5683
        'invisible',
5684
        api_get_user_id()
5685
    );
5686
5687
    return true;
5688
}
5689
5690
/**
5691
 * @param int    $item_id
5692
 * @param string $path
5693
 * @param array  $courseInfo
5694
 * @param int    $groupId    iid
5695
 * @param int    $sessionId
5696
 *
5697
 * @return string
5698
 */
5699
function generateMoveForm($item_id, $path, $courseInfo, $groupId, $sessionId)
5700
{
5701
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
5702
    $courseId = $courseInfo['real_id'];
5703
    $folders = [];
5704
    $session_id = (int) $sessionId;
5705
    $groupId = (int) $groupId;
5706
    $sessionCondition = empty($sessionId) ? ' AND (session_id = 0 OR session_id IS NULL) ' : " AND session_id='".$session_id."'";
5707
5708
    $groupIid = 0;
5709
    if ($groupId) {
5710
        $groupInfo = GroupManager::get_group_properties($groupId);
5711
        $groupIid = $groupInfo['iid'];
5712
    }
5713
5714
    $sql = "SELECT id, url, title
5715
            FROM $work_table
5716
            WHERE
5717
                c_id = $courseId AND
5718
                active IN (0, 1) AND
5719
                url LIKE '/%' AND
5720
                post_group_id = $groupIid
5721
                $sessionCondition";
5722
    $res = Database::query($sql);
5723
    while ($folder = Database::fetch_array($res)) {
5724
        $title = empty($folder['title']) ? basename($folder['url']) : $folder['title'];
5725
        $folders[$folder['id']] = $title;
5726
    }
5727
5728
    return build_work_move_to_selector($folders, $path, $item_id);
5729
}
5730
5731
/**
5732
 * @param int $workId
5733
 *
5734
 * @return string
5735
 */
5736
function showStudentList($workId)
5737
{
5738
    $columnModel = [
5739
        [
5740
            'name' => 'student',
5741
            'index' => 'student',
5742
            'width' => '350px',
5743
            'align' => 'left',
5744
            'sortable' => 'false',
5745
        ],
5746
        [
5747
            'name' => 'works',
5748
            'index' => 'works',
5749
            'align' => 'center',
5750
            'sortable' => 'false',
5751
        ],
5752
    ];
5753
    $token = null;
5754
    $url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_work_student_list_overview&work_id='.$workId.'&'.api_get_cidreq();
5755
5756
    $columns = [
5757
        get_lang('Students'),
5758
        get_lang('Works'),
5759
    ];
5760
5761
    $order = api_is_western_name_order() ? 'firstname' : 'lastname';
5762
    $params = [
5763
        'autowidth' => 'true',
5764
        'height' => 'auto',
5765
        'rowNum' => 5,
5766
        'sortname' => $order,
5767
        'sortorder' => 'asc',
5768
    ];
5769
5770
    $html = '<script>
5771
    $(function() {
5772
        '.Display::grid_js('studentList', $url, $columns, $columnModel, $params, [], null, true).'
5773
        $("#workList").jqGrid(
5774
            "navGrid",
5775
            "#studentList_pager",
5776
            { edit: false, add: false, del: false },
5777
            { height:280, reloadAfterSubmit:false }, // edit options
5778
            { height:280, reloadAfterSubmit:false }, // add options
5779
            { width:500 } // search options
5780
        );
5781
    });
5782
    </script>';
5783
    $html .= Display::grid_html('studentList');
5784
5785
    return $html;
5786
}
5787
5788
/**
5789
 * @param string $courseCode
5790
 * @param int    $sessionId
5791
 * @param int    $groupId
5792
 * @param int    $start
5793
 * @param int    $limit
5794
 * @param string $sidx
5795
 * @param string $sord
5796
 * @param $getCount
5797
 *
5798
 * @return array|int
5799
 */
5800
function getWorkUserList($courseCode, $sessionId, $groupId, $start, $limit, $sidx, $sord, $getCount = false)
5801
{
5802
    if (!empty($groupId)) {
5803
        $userList = GroupManager::get_users(
5804
            $groupId,
5805
            false,
5806
            $start,
5807
            $limit,
5808
            $getCount,
5809
            null,
5810
            $sidx,
5811
            $sord
5812
        );
5813
    } else {
5814
        $limitString = null;
5815
        if (!empty($start) && !empty($limit)) {
5816
            $start = (int) $start;
5817
            $limit = (int) $limit;
5818
            $limitString = " LIMIT $start, $limit";
5819
        }
5820
5821
        $orderBy = null;
5822
        if (!empty($sidx) && !empty($sord)) {
5823
            if (in_array($sidx, ['firstname', 'lastname'])) {
5824
                $orderBy = "ORDER BY `$sidx` $sord";
5825
            }
5826
        }
5827
5828
        if (empty($sessionId)) {
5829
            $userList = CourseManager::get_user_list_from_course_code(
5830
                $courseCode,
5831
                $sessionId,
5832
                $limitString,
5833
                $orderBy,
5834
                STUDENT,
5835
                $getCount
5836
            );
5837
        } else {
5838
            $userList = CourseManager::get_user_list_from_course_code(
5839
                $courseCode,
5840
                $sessionId,
5841
                $limitString,
5842
                $orderBy,
5843
                0,
5844
                $getCount
5845
            );
5846
        }
5847
5848
        if ($getCount == false) {
5849
            $userList = array_keys($userList);
5850
        }
5851
    }
5852
5853
    return $userList;
5854
}
5855
5856
/**
5857
 * @param int    $workId
5858
 * @param string $courseCode
5859
 * @param int    $sessionId
5860
 * @param int    $groupId
5861
 * @param int    $start
5862
 * @param int    $limit
5863
 * @param int    $sidx
5864
 * @param string $sord
5865
 * @param bool   $getCount
5866
 *
5867
 * @return array|int
5868
 */
5869
function getWorkUserListData(
5870
    $workId,
5871
    $courseCode,
5872
    $sessionId,
5873
    $groupId,
5874
    $start,
5875
    $limit,
5876
    $sidx,
5877
    $sord,
5878
    $getCount = false
5879
) {
5880
    $my_folder_data = get_work_data_by_id($workId);
5881
    $workParents = [];
5882
    if (empty($my_folder_data)) {
5883
        $workParents = getWorkList($workId, $my_folder_data, null);
5884
    }
5885
5886
    $workIdList = [];
5887
    if (!empty($workParents)) {
5888
        foreach ($workParents as $work) {
5889
            $workIdList[] = $work->id;
5890
        }
5891
    }
5892
5893
    $courseInfo = api_get_course_info($courseCode);
5894
5895
    $userList = getWorkUserList(
5896
        $courseCode,
5897
        $sessionId,
5898
        $groupId,
5899
        $start,
5900
        $limit,
5901
        $sidx,
5902
        $sord,
5903
        $getCount
5904
    );
5905
5906
    if ($getCount) {
5907
        return $userList;
5908
    }
5909
    $results = [];
5910
    if (!empty($userList)) {
5911
        foreach ($userList as $userId) {
5912
            $user = api_get_user_info($userId);
5913
            $link = api_get_path(WEB_CODE_PATH).'work/student_work.php?'.api_get_cidreq().'&studentId='.$user['user_id'];
5914
            $url = Display::url(api_get_person_name($user['firstname'], $user['lastname']), $link);
5915
            $userWorks = 0;
5916
            if (!empty($workIdList)) {
5917
                $userWorks = getUniqueStudentAttempts(
5918
                    $workIdList,
5919
                    $groupId,
5920
                    $courseInfo['real_id'],
5921
                    $sessionId,
5922
                    $user['user_id']
5923
                );
5924
            }
5925
            $works = $userWorks." / ".count($workParents);
5926
            $results[] = [
5927
                'student' => $url,
5928
                'works' => Display::url($works, $link),
5929
            ];
5930
        }
5931
    }
5932
5933
    return $results;
5934
}
5935
5936
/**
5937
 * @param int   $id
5938
 * @param array $course_info
5939
 * @param bool  $isCorrection
5940
 *
5941
 * @return bool
5942
 */
5943
function downloadFile($id, $course_info, $isCorrection)
5944
{
5945
    return getFile($id, $course_info, true, $isCorrection, true);
5946
}
5947
5948
/**
5949
 * @param int   $id
5950
 * @param array $course_info
5951
 * @param bool  $download
5952
 * @param bool  $isCorrection
5953
 * @param bool  $forceAccessForCourseAdmins
5954
 *
5955
 * @return bool
5956
 */
5957
function getFile($id, $course_info, $download = true, $isCorrection = false, $forceAccessForCourseAdmins = false)
5958
{
5959
    $file = getFileContents($id, $course_info, 0, $isCorrection, $forceAccessForCourseAdmins);
5960
    if (!empty($file) && is_array($file)) {
5961
        return DocumentManager::file_send_for_download(
5962
            $file['path'],
5963
            $download,
5964
            $file['title']
5965
        );
5966
    }
5967
5968
    return false;
5969
}
5970
5971
/**
5972
 * Get the file contents for an assigment.
5973
 *
5974
 * @param int   $id
5975
 * @param array $courseInfo
5976
 * @param int   $sessionId
5977
 * @param bool  $correction
5978
 * @param bool  $forceAccessForCourseAdmins
5979
 *
5980
 * @return array|bool
5981
 */
5982
function getFileContents($id, $courseInfo, $sessionId = 0, $correction = false, $forceAccessForCourseAdmins = false)
5983
{
5984
    $id = (int) $id;
5985
    if (empty($courseInfo) || empty($id)) {
5986
        return false;
5987
    }
5988
    if (empty($sessionId)) {
5989
        $sessionId = api_get_session_id();
5990
    }
5991
5992
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
5993
    if (!empty($courseInfo['real_id'])) {
5994
        $sql = "SELECT *
5995
                FROM $table
5996
                WHERE c_id = ".$courseInfo['real_id']." AND id = $id";
5997
5998
        $result = Database::query($sql);
5999
        if ($result && Database::num_rows($result)) {
6000
            $row = Database::fetch_array($result, 'ASSOC');
6001
6002
            if ($correction) {
6003
                $row['url'] = $row['url_correction'];
6004
            }
6005
6006
            if (empty($row['url'])) {
6007
                return false;
6008
            }
6009
6010
            $full_file_name = api_get_path(SYS_COURSE_PATH).api_get_course_path().'/'.$row['url'];
6011
6012
            $item_info = api_get_item_property_info(
6013
                api_get_course_int_id(),
6014
                'work',
6015
                $row['id'],
6016
                $sessionId
6017
            );
6018
6019
            if (empty($item_info)) {
6020
                return false;
6021
            }
6022
6023
            $isAllow = allowOnlySubscribedUser(
6024
                api_get_user_id(),
6025
                $row['parent_id'],
6026
                $courseInfo['real_id'],
6027
                $forceAccessForCourseAdmins
6028
            );
6029
6030
            if (empty($isAllow)) {
6031
                return false;
6032
            }
6033
6034
            /*
6035
            field show_score in table course :
6036
                0 =>    New documents are visible for all users
6037
                1 =>    New documents are only visible for the teacher(s)
6038
            field visibility in table item_property :
6039
                0 => eye closed, invisible for all students
6040
                1 => eye open
6041
            field accepted in table c_student_publication :
6042
                0 => eye closed, invisible for all students
6043
                1 => eye open
6044
            ( We should have visibility == accepted, otherwise there is an
6045
            inconsistency in the Database)
6046
            field value in table c_course_setting :
6047
                0 => Allow learners to delete their own publications = NO
6048
                1 => Allow learners to delete their own publications = YES
6049
6050
            +------------------+-------------------------+------------------------+
6051
            |Can download work?| doc visible for all = 0 | doc visible for all = 1|
6052
            +------------------+-------------------------+------------------------+
6053
            |  visibility = 0  | editor only             | editor only            |
6054
            |                  |                         |                        |
6055
            +------------------+-------------------------+------------------------+
6056
            |  visibility = 1  | editor                  | editor                 |
6057
            |                  | + owner of the work     | + any student          |
6058
            +------------------+-------------------------+------------------------+
6059
            (editor = teacher + admin + anybody with right api_is_allowed_to_edit)
6060
            */
6061
6062
            $work_is_visible = $item_info['visibility'] == 1 && $row['accepted'] == 1;
6063
            $doc_visible_for_all = (int) $courseInfo['show_score'] === 0;
6064
6065
            $is_editor = api_is_allowed_to_edit(true, true, true);
6066
            $student_is_owner_of_work = user_is_author($row['id'], api_get_user_id());
6067
6068
            if (($forceAccessForCourseAdmins && $isAllow) ||
6069
                $is_editor ||
6070
                $student_is_owner_of_work ||
6071
                ($doc_visible_for_all && $work_is_visible)
6072
            ) {
6073
                $title = $row['title'];
6074
                if ($correction) {
6075
                    $title = $row['title_correction'];
6076
                }
6077
                if (array_key_exists('filename', $row) && !empty($row['filename'])) {
6078
                    $title = $row['filename'];
6079
                }
6080
6081
                $title = str_replace(' ', '_', $title);
6082
6083
                if ($correction == false) {
6084
                    $userInfo = api_get_user_info($row['user_id']);
6085
                    if ($userInfo) {
6086
                        $date = api_get_local_time($row['sent_date']);
6087
                        $date = str_replace([':', '-', ' '], '_', $date);
6088
                        $title = $date.'_'.$userInfo['username'].'_'.$title;
6089
                    }
6090
                }
6091
6092
                if (Security::check_abs_path(
6093
                    $full_file_name,
6094
                    api_get_path(SYS_COURSE_PATH).api_get_course_path().'/'
6095
                )) {
6096
                    Event::event_download($title);
6097
6098
                    return [
6099
                        'path' => $full_file_name,
6100
                        'title' => $title,
6101
                        'title_correction' => $row['title_correction'],
6102
                    ];
6103
                }
6104
            }
6105
        }
6106
    }
6107
6108
    return false;
6109
}
6110
6111
/**
6112
 * @param int    $userId
6113
 * @param array  $courseInfo
6114
 * @param string $format
6115
 *
6116
 * @return bool
6117
 */
6118
function exportAllWork($userId, $courseInfo, $format = 'pdf')
6119
{
6120
    $userInfo = api_get_user_info($userId);
6121
    if (empty($userInfo) || empty($courseInfo)) {
6122
        return false;
6123
    }
6124
6125
    $workPerUser = getWorkPerUser($userId);
6126
6127
    switch ($format) {
6128
        case 'pdf':
6129
            if (!empty($workPerUser)) {
6130
                $pdf = new PDF();
6131
6132
                $content = null;
6133
                foreach ($workPerUser as $work) {
6134
                    $work = $work['work'];
6135
                    foreach ($work->user_results as $userResult) {
6136
                        $content .= $userResult['title'];
6137
                        // No need to use api_get_local_time()
6138
                        $content .= $userResult['sent_date'];
6139
                        $content .= $userResult['qualification'];
6140
                        $content .= $userResult['description'];
6141
                    }
6142
                }
6143
6144
                if (!empty($content)) {
6145
                    $pdf->content_to_pdf(
6146
                        $content,
6147
                        null,
6148
                        api_replace_dangerous_char($userInfo['complete_name']),
6149
                        $courseInfo['code']
6150
                    );
6151
                }
6152
            }
6153
            break;
6154
    }
6155
}
6156
6157
/**
6158
 * @param int    $workId
6159
 * @param array  $courseInfo
6160
 * @param int    $sessionId
6161
 * @param string $format
6162
 *
6163
 * @return bool
6164
 */
6165
function exportAllStudentWorkFromPublication(
6166
    $workId,
6167
    $courseInfo,
6168
    $sessionId,
6169
    $format = 'pdf'
6170
) {
6171
    if (empty($courseInfo)) {
6172
        return false;
6173
    }
6174
6175
    $workData = get_work_data_by_id($workId);
6176
    if (empty($workData)) {
6177
        return false;
6178
    }
6179
6180
    $assignment = get_work_assignment_by_id($workId);
6181
6182
    $courseCode = $courseInfo['code'];
6183
    $header = get_lang('Course').': '.$courseInfo['title'];
6184
    $teachers = CourseManager::getTeacherListFromCourseCodeToString(
6185
        $courseCode
6186
    );
6187
6188
    if (!empty($sessionId)) {
6189
        $sessionInfo = api_get_session_info($sessionId);
6190
        if (!empty($sessionInfo)) {
6191
            $header .= ' - '.$sessionInfo['name'];
6192
            $header .= '<br />'.$sessionInfo['description'];
6193
            $teachers = SessionManager::getCoachesByCourseSessionToString(
6194
                $sessionId,
6195
                $courseInfo['real_id']
6196
            );
6197
        }
6198
    }
6199
6200
    $header .= '<br />'.get_lang('Teachers').': '.$teachers.'<br />';
6201
    $header .= '<br />'.get_lang('Date').': '.api_get_local_time().'<br />';
6202
    $header .= '<br />'.get_lang('WorkName').': '.$workData['title'].'<br />';
6203
6204
    $content = null;
6205
    $expiresOn = null;
6206
6207
    if (!empty($assignment) && isset($assignment['expires_on'])) {
6208
        $content .= '<br /><strong>'.get_lang('PostedExpirationDate').'</strong>: '.api_get_local_time($assignment['expires_on']);
6209
        $expiresOn = api_get_local_time($assignment['expires_on']);
6210
    }
6211
6212
    if (!empty($workData['description'])) {
6213
        $content .= '<br /><strong>'.get_lang('Description').'</strong>: '.$workData['description'];
6214
    }
6215
6216
    $workList = get_work_user_list(null, null, null, null, $workId);
6217
6218
    switch ($format) {
6219
        case 'pdf':
6220
            if (!empty($workList)) {
6221
                $table = new HTML_Table(['class' => 'table table-hover table-striped data_table']);
6222
                $headers = [
6223
                    get_lang('Name'),
6224
                    get_lang('User'),
6225
                    get_lang('HandOutDateLimit'),
6226
                    get_lang('SentDate'),
6227
                    get_lang('FileName'),
6228
                    get_lang('Score'),
6229
                    get_lang('Feedback'),
6230
                ];
6231
6232
                $column = 0;
6233
                foreach ($headers as $header) {
6234
                    $table->setHeaderContents(0, $column, $header);
6235
                    $column++;
6236
                }
6237
6238
                $row = 1;
6239
6240
                //$pdf->set_custom_header($header);
6241
                foreach ($workList as $work) {
6242
                    $content .= '<hr />';
6243
                    // getWorkComments need c_id
6244
                    $work['c_id'] = $courseInfo['real_id'];
6245
6246
                    //$content .= get_lang('Date').': '.api_get_local_time($work['sent_date_from_db']).'<br />';
6247
                    $score = null;
6248
                    if (!empty($work['qualification_only'])) {
6249
                        $score = $work['qualification_only'];
6250
                    }
6251
6252
                    $comments = getWorkComments($work);
6253
6254
                    $feedback = null;
6255
                    if (!empty($comments)) {
6256
                        $content .= '<h4>'.get_lang('Feedback').': </h4>';
6257
                        foreach ($comments as $comment) {
6258
                            $feedback .= get_lang('User').': '.$comment['complete_name'].
6259
                                '<br />';
6260
                            $feedback .= $comment['comment'].'<br />';
6261
                        }
6262
                    }
6263
                    $table->setCellContents($row, 0, strip_tags($workData['title']));
6264
                    $table->setCellContents($row, 1, strip_tags($work['fullname']));
6265
                    $table->setCellContents($row, 2, $expiresOn);
6266
                    $table->setCellContents($row, 3, api_get_local_time($work['sent_date_from_db']));
6267
                    $table->setCellContents($row, 4, strip_tags($work['title']));
6268
                    $table->setCellContents($row, 5, $score);
6269
                    $table->setCellContents($row, 6, $feedback);
6270
6271
                    $row++;
6272
                }
6273
6274
                $content = $table->toHtml();
6275
6276
                if (!empty($content)) {
6277
                    $params = [
6278
                        'filename' => $workData['title'].'_'.api_get_local_time(),
6279
                        'pdf_title' => api_replace_dangerous_char($workData['title']),
6280
                        'course_code' => $courseInfo['code'],
6281
                    ];
6282
                    $pdf = new PDF('A4', null, $params);
6283
                    $pdf->html_to_pdf_with_template($content);
6284
                }
6285
                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...
6286
            }
6287
            break;
6288
    }
6289
}
6290
6291
/**
6292
 * Downloads all user files per user.
6293
 *
6294
 * @param int   $userId
6295
 * @param array $courseInfo
6296
 *
6297
 * @return bool
6298
 */
6299
function downloadAllFilesPerUser($userId, $courseInfo)
6300
{
6301
    $userInfo = api_get_user_info($userId);
6302
6303
    if (empty($userInfo) || empty($courseInfo)) {
6304
        return false;
6305
    }
6306
6307
    $tempZipFile = api_get_path(SYS_ARCHIVE_PATH).api_get_unique_id().".zip";
6308
    $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/work/';
6309
    $zip = new PclZip($tempZipFile);
6310
    $workPerUser = getWorkPerUser($userId);
6311
6312
    if (!empty($workPerUser)) {
6313
        $files = [];
6314
        foreach ($workPerUser as $work) {
6315
            $work = $work['work'];
6316
            foreach ($work->user_results as $userResult) {
6317
                if (empty($userResult['url']) || empty($userResult['contains_file'])) {
6318
                    continue;
6319
                }
6320
                $data = getFileContents($userResult['id'], $courseInfo);
6321
                if (!empty($data) && isset($data['path'])) {
6322
                    $files[basename($data['path'])] = [
6323
                        'title' => $data['title'],
6324
                        'path' => $data['path'],
6325
                    ];
6326
                }
6327
            }
6328
        }
6329
6330
        if (!empty($files)) {
6331
            Session::write('files', $files);
6332
            foreach ($files as $data) {
6333
                $zip->add(
6334
                    $data['path'],
6335
                    PCLZIP_OPT_REMOVE_PATH,
6336
                    $coursePath,
6337
                    PCLZIP_CB_PRE_ADD,
6338
                    'preAddAllWorkStudentCallback'
6339
                );
6340
            }
6341
        }
6342
6343
        // Start download of created file
6344
        $name = basename(api_replace_dangerous_char($userInfo['complete_name'])).'.zip';
6345
        Event::event_download($name.'.zip (folder)');
6346
        if (Security::check_abs_path($tempZipFile, api_get_path(SYS_ARCHIVE_PATH))) {
6347
            DocumentManager::file_send_for_download($tempZipFile, true, $name);
6348
            @unlink($tempZipFile);
6349
            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...
6350
        }
6351
    }
6352
    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...
6353
}
6354
6355
/**
6356
 * @param $p_event
6357
 * @param array $p_header
6358
 *
6359
 * @return int
6360
 */
6361
function preAddAllWorkStudentCallback($p_event, &$p_header)
6362
{
6363
    $files = Session::read('files');
6364
    if (isset($files[basename($p_header['stored_filename'])])) {
6365
        $p_header['stored_filename'] = $files[basename($p_header['stored_filename'])]['title'];
6366
6367
        return 1;
6368
    }
6369
6370
    return 0;
6371
}
6372
6373
/**
6374
 * Get all work created by a user.
6375
 *
6376
 * @param int $user_id
6377
 * @param int $courseId
6378
 * @param int $sessionId
6379
 *
6380
 * @return array
6381
 */
6382
function getWorkCreatedByUser($user_id, $courseId, $sessionId)
6383
{
6384
    $items = api_get_item_property_list_by_tool_by_user(
6385
        $user_id,
6386
        'work',
6387
        $courseId,
6388
        $sessionId
6389
    );
6390
6391
    $list = [];
6392
    if (!empty($items)) {
6393
        foreach ($items as $work) {
6394
            $item = get_work_data_by_id(
6395
                $work['ref'],
6396
                $courseId,
6397
                $sessionId
6398
            );
6399
            if (!empty($item)) {
6400
                $list[] = [
6401
                    $item['title'],
6402
                    api_get_local_time($work['insert_date']),
6403
                    api_get_local_time($work['lastedit_date']),
6404
                ];
6405
            }
6406
        }
6407
    }
6408
6409
    return $list;
6410
}
6411
6412
/**
6413
 * @param array $courseInfo
6414
 * @param int   $workId
6415
 *
6416
 * @return bool
6417
 */
6418
function protectWork($courseInfo, $workId)
6419
{
6420
    $userId = api_get_user_id();
6421
    $groupId = api_get_group_id();
6422
    $sessionId = api_get_session_id();
6423
    $workData = get_work_data_by_id($workId);
6424
6425
    if (empty($workData) || empty($courseInfo)) {
6426
        api_not_allowed(true);
6427
    }
6428
6429
    if (api_is_platform_admin() || api_is_allowed_to_edit()) {
6430
        return true;
6431
    }
6432
6433
    $workId = $workData['id'];
6434
6435
    if ($workData['active'] != 1) {
6436
        api_not_allowed(true);
6437
    }
6438
6439
    $visibility = api_get_item_visibility($courseInfo, 'work', $workId, $sessionId);
6440
6441
    if ($visibility != 1) {
6442
        api_not_allowed(true);
6443
    }
6444
6445
    $isAllow = allowOnlySubscribedUser($userId, $workId, $courseInfo['real_id']);
6446
    if (empty($isAllow)) {
6447
        api_not_allowed(true);
6448
    }
6449
6450
    $groupInfo = GroupManager::get_group_properties($groupId);
6451
6452
    if (!empty($groupId)) {
6453
        $showWork = GroupManager::user_has_access(
6454
            $userId,
6455
            $groupInfo['iid'],
6456
            GroupManager::GROUP_TOOL_WORK
6457
        );
6458
        if (!$showWork) {
6459
            api_not_allowed(true);
6460
        }
6461
    }
6462
}
6463
6464
/**
6465
 * @param array $courseInfo
6466
 * @param array $work
6467
 */
6468
function deleteCorrection($courseInfo, $work)
6469
{
6470
    if (isset($work['url_correction']) && !empty($work['url_correction']) && isset($work['iid'])) {
6471
        $id = $work['iid'];
6472
        $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
6473
        $sql = "UPDATE $table SET
6474
                    url_correction = '',
6475
                    title_correction = ''
6476
                WHERE iid = $id";
6477
        Database::query($sql);
6478
        $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/';
6479
        if (file_exists($coursePath.$work['url_correction'])) {
6480
            if (Security::check_abs_path($coursePath.$work['url_correction'], $coursePath)) {
6481
                unlink($coursePath.$work['url_correction']);
6482
            }
6483
        }
6484
    }
6485
}
6486
6487
/**
6488
 * @param int $workId
6489
 *
6490
 * @return string
6491
 */
6492
function workGetExtraFieldData($workId)
6493
{
6494
    $sessionField = new ExtraField('work');
6495
    $extraFieldData = $sessionField->getDataAndFormattedValues($workId);
6496
    $result = '';
6497
    if (!empty($extraFieldData)) {
6498
        $result .= '<div class="well">';
6499
        foreach ($extraFieldData as $data) {
6500
            $result .= $data['text'].': <b>'.$data['value'].'</b>';
6501
        }
6502
        $result .= '</div>';
6503
    }
6504
6505
    return $result;
6506
}
6507