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

getWorkListTeacherData()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 55
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 6
eloc 29
c 2
b 0
f 0
nc 10
nop 9
dl 0
loc 55
rs 8.8337

How to fix   Long Method    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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