Passed
Push — master ( 3ba91c...49b9ea )
by Julito
08:31
created

getWorkComments()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 38
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

    return false;
}

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

Loading history...
5458
        /** @var CStudentPublication $studentPublication */
5459
        $studentPublication = $file['entity'];
5460
    }
5461
5462
    return false;
5463
}
5464
5465
/**
5466
 * Get the file contents for an assigment.
5467
 *
5468
 * @param int   $id
5469
 * @param array $courseInfo
5470
 * @param int   $sessionId
5471
 * @param bool  $correction
5472
 * @param bool  $forceAccessForCourseAdmins
5473
 *
5474
 * @return array|bool
5475
 */
5476
function getFileContents($id, $courseInfo, $sessionId = 0, $correction = false, $forceAccessForCourseAdmins = false)
5477
{
5478
    $id = (int) $id;
5479
5480
    if (empty($courseInfo) || empty($id)) {
5481
        return false;
5482
    }
5483
    if (empty($sessionId)) {
5484
        $sessionId = api_get_session_id();
5485
    }
5486
5487
    $courseEntity = api_get_course_entity($courseInfo['real_id']);
5488
    $sessionEntity = api_get_session_entity($sessionId);
5489
5490
    $repo = Container::getStudentPublicationRepository();
5491
    /** @var CStudentPublication $studentPublication */
5492
    $studentPublication = $repo->find($id);
5493
5494
    if (empty($studentPublication)) {
5495
        return false;
5496
    }
5497
5498
    if ($correction) {
5499
        //$row['url'] = $row['url_correction'];
5500
    }
5501
    $hasFile = $studentPublication->getResourceNode()->hasResourceFile();
5502
    if (!$hasFile) {
5503
        return false;
5504
    }
5505
5506
    /*
5507
    $item_info = api_get_item_property_info(
5508
        api_get_course_int_id(),
5509
        'work',
5510
        $row['iid'],
5511
        $sessionId
5512
    );
5513
5514
    if (empty($item_info)) {
5515
        return false;
5516
    }*/
5517
5518
    $isAllow = allowOnlySubscribedUser(
5519
        api_get_user_id(),
5520
        $studentPublication->getParentId(),
5521
        $courseInfo['real_id'],
5522
        $forceAccessForCourseAdmins
5523
    );
5524
5525
    if (empty($isAllow)) {
5526
        return false;
5527
    }
5528
5529
    /*
5530
    field show_score in table course :
5531
        0 =>    New documents are visible for all users
5532
        1 =>    New documents are only visible for the teacher(s)
5533
    field visibility in table item_property :
5534
        0 => eye closed, invisible for all students
5535
        1 => eye open
5536
    field accepted in table c_student_publication :
5537
        0 => eye closed, invisible for all students
5538
        1 => eye open
5539
    ( We should have visibility == accepted, otherwise there is an
5540
    inconsistency in the Database)
5541
    field value in table c_course_setting :
5542
        0 => Allow learners to delete their own publications = NO
5543
        1 => Allow learners to delete their own publications = YES
5544
5545
    +------------------+-------------------------+------------------------+
5546
    |Can download work?| doc visible for all = 0 | doc visible for all = 1|
5547
    +------------------+-------------------------+------------------------+
5548
    |  visibility = 0  | editor only             | editor only            |
5549
    |                  |                         |                        |
5550
    +------------------+-------------------------+------------------------+
5551
    |  visibility = 1  | editor                  | editor                 |
5552
    |                  | + owner of the work     | + any student          |
5553
    +------------------+-------------------------+------------------------+
5554
    (editor = teacher + admin + anybody with right api_is_allowed_to_edit)
5555
    */
5556
5557
    $work_is_visible = $studentPublication->isVisible($courseEntity, $sessionEntity) && $studentPublication->getAccepted();
5558
    $doc_visible_for_all = 0 === (int) $courseInfo['show_score'];
5559
5560
    $is_editor = api_is_allowed_to_edit(true, true, true);
5561
    $student_is_owner_of_work = user_is_author($studentPublication->getIid(), api_get_user_id());
5562
5563
    if (($forceAccessForCourseAdmins && $isAllow) ||
5564
        $is_editor ||
5565
        $student_is_owner_of_work ||
5566
        ($doc_visible_for_all && $work_is_visible)
5567
    ) {
5568
        $title = $studentPublication->getTitle();
5569
        if ($correction) {
5570
            $title = $studentPublication->getTitleCorrection();
5571
        }
5572
        if ($hasFile) {
5573
            $title = $studentPublication->getResourceNode()->getResourceFile()->getName();
5574
        }
5575
5576
        $title = str_replace(' ', '_', $title);
5577
5578
        if (false == $correction) {
5579
            $userInfo = api_get_user_info($studentPublication->getUserId());
5580
            if ($userInfo) {
5581
                $date = api_get_local_time($studentPublication->getSentDate()->format('Y-m-d H:i:s'));
5582
                $date = str_replace([':', '-', ' '], '_', $date);
5583
                $title = $date.'_'.$userInfo['username'].'_'.$title;
5584
            }
5585
        }
5586
5587
        return [
5588
            //'path' => $full_file_name,
5589
            'title' => $title,
5590
            'title_correction' => $studentPublication->getTitleCorrection(),
5591
            'entity' => $studentPublication,
5592
        ];
5593
    }
5594
5595
    return false;
5596
}
5597
5598
/**
5599
 * @param int    $userId
5600
 * @param array  $courseInfo
5601
 * @param string $format
5602
 *
5603
 * @return bool
5604
 */
5605
function exportAllWork($userId, $courseInfo, $format = 'pdf')
5606
{
5607
    $userInfo = api_get_user_info($userId);
5608
    if (empty($userInfo) || empty($courseInfo)) {
5609
        return false;
5610
    }
5611
5612
    $workPerUser = getWorkPerUser($userId);
5613
5614
    switch ($format) {
5615
        case 'pdf':
5616
            if (!empty($workPerUser)) {
5617
                $pdf = new PDF();
5618
5619
                $content = null;
5620
                foreach ($workPerUser as $work) {
5621
                    $work = $work['work'];
5622
                    foreach ($work->user_results as $userResult) {
5623
                        $content .= $userResult['title'];
5624
                        // No need to use api_get_local_time()
5625
                        $content .= $userResult['sent_date'];
5626
                        $content .= $userResult['qualification'];
5627
                        $content .= $userResult['description'];
5628
                    }
5629
                }
5630
5631
                if (!empty($content)) {
5632
                    $pdf->content_to_pdf(
5633
                        $content,
5634
                        null,
5635
                        api_replace_dangerous_char($userInfo['complete_name']),
5636
                        $courseInfo['code']
5637
                    );
5638
                }
5639
            }
5640
5641
            break;
5642
    }
5643
}
5644
5645
/**
5646
 * @param int    $workId
5647
 * @param array  $courseInfo
5648
 * @param int    $sessionId
5649
 * @param string $format
5650
 *
5651
 * @return bool
5652
 */
5653
function exportAllStudentWorkFromPublication(
5654
    $workId,
5655
    $courseInfo,
5656
    $sessionId,
5657
    $format = 'pdf'
5658
) {
5659
    if (empty($courseInfo)) {
5660
        return false;
5661
    }
5662
5663
    $workData = get_work_data_by_id($workId);
5664
    if (empty($workData)) {
5665
        return false;
5666
    }
5667
5668
    $assignment = get_work_assignment_by_id($workId);
5669
5670
    $courseCode = $courseInfo['code'];
5671
    $header = get_lang('Course').': '.$courseInfo['title'];
5672
    $teachers = CourseManager::getTeacherListFromCourseCodeToString(
5673
        $courseCode
5674
    );
5675
5676
    if (!empty($sessionId)) {
5677
        $sessionInfo = api_get_session_info($sessionId);
5678
        if (!empty($sessionInfo)) {
5679
            $header .= ' - '.$sessionInfo['name'];
5680
            $header .= '<br />'.$sessionInfo['description'];
5681
            $teachers = SessionManager::getCoachesByCourseSessionToString(
5682
                $sessionId,
5683
                $courseInfo['real_id']
5684
            );
5685
        }
5686
    }
5687
5688
    $header .= '<br />'.get_lang('Trainers').': '.$teachers.'<br />';
5689
    $header .= '<br />'.get_lang('Date').': '.api_get_local_time().'<br />';
5690
    $header .= '<br />'.get_lang('Assignment name').': '.$workData['title'].'<br />';
5691
5692
    $content = null;
5693
    $expiresOn = null;
5694
5695
    if (!empty($assignment) && isset($assignment['expires_on'])) {
5696
        $content .= '<br /><strong>'.get_lang('Posted deadline for sending the work (Visible to the learner)').'</strong>: '.api_get_local_time($assignment['expires_on']);
5697
        $expiresOn = api_get_local_time($assignment['expires_on']);
5698
    }
5699
5700
    if (!empty($workData['description'])) {
5701
        $content .= '<br /><strong>'.get_lang('Description').'</strong>: '.$workData['description'];
5702
    }
5703
5704
    $workList = get_work_user_list(null, null, null, null, $workId);
5705
5706
    switch ($format) {
5707
        case 'pdf':
5708
            if (!empty($workList)) {
5709
                $table = new HTML_Table(['class' => 'data_table']);
5710
                $headers = [
5711
                    get_lang('Name'),
5712
                    get_lang('User'),
5713
                    get_lang('Deadline'),
5714
                    get_lang('Sent date'),
5715
                    get_lang('Filename'),
5716
                    get_lang('Score'),
5717
                    get_lang('Feedback'),
5718
                ];
5719
5720
                $column = 0;
5721
                foreach ($headers as $header) {
5722
                    $table->setHeaderContents(0, $column, $header);
5723
                    $column++;
5724
                }
5725
5726
                $row = 1;
5727
5728
                //$pdf->set_custom_header($header);
5729
                foreach ($workList as $work) {
5730
                    $content .= '<hr />';
5731
                    // getWorkComments need c_id
5732
                    $work['c_id'] = $courseInfo['real_id'];
5733
5734
                    //$content .= get_lang('Date').': '.api_get_local_time($work['sent_date_from_db']).'<br />';
5735
                    $score = null;
5736
                    if (!empty($work['qualification_only'])) {
5737
                        $score = $work['qualification_only'];
5738
                    }
5739
5740
                    $comments = getWorkComments($work);
5741
5742
                    $feedback = null;
5743
                    if (!empty($comments)) {
5744
                        $content .= '<h4>'.get_lang('Feedback').': </h4>';
5745
                        foreach ($comments as $comment) {
5746
                            $feedback .= get_lang('User').': '.$comment['complete_name'].
5747
                                '<br />';
5748
                            $feedback .= $comment['comment'].'<br />';
5749
                        }
5750
                    }
5751
                    $table->setCellContents($row, 0, strip_tags($workData['title']));
5752
                    $table->setCellContents($row, 1, strip_tags($work['fullname']));
5753
                    $table->setCellContents($row, 2, $expiresOn);
5754
                    $table->setCellContents($row, 3, api_get_local_time($work['sent_date_from_db']));
5755
                    $table->setCellContents($row, 4, strip_tags($work['title']));
5756
                    $table->setCellContents($row, 5, $score);
5757
                    $table->setCellContents($row, 6, $feedback);
5758
5759
                    $row++;
5760
                }
5761
5762
                $content = $table->toHtml();
5763
5764
                if (!empty($content)) {
5765
                    $params = [
5766
                        'filename' => $workData['title'].'_'.api_get_local_time(),
5767
                        'pdf_title' => api_replace_dangerous_char($workData['title']),
5768
                        'course_code' => $courseInfo['code'],
5769
                    ];
5770
                    $pdf = new PDF('A4', null, $params);
5771
                    $pdf->html_to_pdf_with_template($content);
5772
                }
5773
                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...
5774
            }
5775
5776
            break;
5777
    }
5778
}
5779
5780
/**
5781
 * Downloads all user files per user.
5782
 *
5783
 * @param int   $userId
5784
 * @param array $courseInfo
5785
 *
5786
 * @return bool
5787
 */
5788
function downloadAllFilesPerUser($userId, $courseInfo)
5789
{
5790
    throw new Exception('downloadAllFilesPerUser');
5791
    /*
5792
    $userInfo = api_get_user_info($userId);
5793
5794
    if (empty($userInfo) || empty($courseInfo)) {
5795
        return false;
5796
    }
5797
5798
    $tempZipFile = api_get_path(SYS_ARCHIVE_PATH).api_get_unique_id().'.zip';
5799
    $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/work/';
5800
    $zip = new PclZip($tempZipFile);
5801
    $workPerUser = getWorkPerUser($userId);
5802
5803
    if (!empty($workPerUser)) {
5804
        $files = [];
5805
        foreach ($workPerUser as $work) {
5806
            $work = $work['work'];
5807
            foreach ($work->user_results as $userResult) {
5808
                if (empty($userResult['url']) || empty($userResult['contains_file'])) {
5809
                    continue;
5810
                }
5811
                $data = getFileContents($userResult['iid'], $courseInfo);
5812
                if (!empty($data) && isset($data['path'])) {
5813
                    $files[basename($data['path'])] = [
5814
                        'title' => $data['title'],
5815
                        'path' => $data['path'],
5816
                    ];
5817
                }
5818
            }
5819
        }
5820
5821
        if (!empty($files)) {
5822
            Session::write('files', $files);
5823
            foreach ($files as $data) {
5824
                $zip->add(
5825
                    $data['path'],
5826
                    PCLZIP_OPT_REMOVE_PATH,
5827
                    $coursePath,
5828
                    PCLZIP_CB_PRE_ADD,
5829
                    'preAddAllWorkStudentCallback'
5830
                );
5831
            }
5832
        }
5833
5834
        // Start download of created file
5835
        $name = basename(api_replace_dangerous_char($userInfo['complete_name'])).'.zip';
5836
        Event::event_download($name.'.zip (folder)');
5837
        if (Security::check_abs_path($tempZipFile, api_get_path(SYS_ARCHIVE_PATH))) {
5838
            DocumentManager::file_send_for_download($tempZipFile, true, $name);
5839
            @unlink($tempZipFile);
5840
            exit;
5841
        }
5842
    }
5843
    exit;*/
5844
}
5845
5846
/**
5847
 * @param $p_event
5848
 * @param array $p_header
5849
 *
5850
 * @return int
5851
 */
5852
function preAddAllWorkStudentCallback($p_event, &$p_header)
5853
{
5854
    $files = Session::read('files');
5855
    if (isset($files[basename($p_header['stored_filename'])])) {
5856
        $p_header['stored_filename'] = $files[basename($p_header['stored_filename'])]['title'];
5857
5858
        return 1;
5859
    }
5860
5861
    return 0;
5862
}
5863
5864
/**
5865
 * Get all work created by a user.
5866
 *
5867
 * @param int $userId
5868
 * @param int $courseId
5869
 * @param int $sessionId
5870
 *
5871
 * @return array
5872
 */
5873
function getWorkCreatedByUser($userId, $courseId, $sessionId)
5874
{
5875
    $repo = Container::getStudentPublicationRepository();
5876
5877
    $courseEntity = api_get_course_entity($courseId);
5878
    $sessionEntity = api_get_session_entity($sessionId);
5879
5880
    $qb = $repo->getResourcesByCourse($courseEntity, $sessionEntity);
5881
5882
    $qb->andWhere('node.creator = :creator');
5883
    $qb->setParameter('creator', $userId);
5884
    $items = $qb->getQuery()->getResult();
5885
5886
    $list = [];
5887
    if (!empty($items)) {
5888
        /** @var CStudentPublication $work */
5889
        foreach ($items as $work) {
5890
            $list[] = [
5891
                $work->getTitle(),
5892
                api_get_local_time($work->getResourceNode()->getCreatedAt()),
5893
                api_get_local_time($work->getResourceNode()->getUpdatedAt()),
5894
            ];
5895
        }
5896
    }
5897
5898
    return $list;
5899
}
5900
5901
/**
5902
 * @param array $courseInfo
5903
 * @param int   $workId
5904
 *
5905
 * @return bool
5906
 */
5907
function protectWork($courseInfo, $workId)
5908
{
5909
    $userId = api_get_user_id();
5910
    $groupId = api_get_group_id();
5911
    $sessionId = api_get_session_id();
5912
    $workData = get_work_data_by_id($workId);
5913
5914
    if (empty($workData) || empty($courseInfo)) {
5915
        api_not_allowed(true);
5916
    }
5917
5918
    if (api_is_platform_admin() || api_is_allowed_to_edit()) {
5919
        return true;
5920
    }
5921
5922
    $workId = $workData['iid'];
5923
5924
    if (1 != $workData['active']) {
5925
        api_not_allowed(true);
5926
    }
5927
5928
    /*$visibility = api_get_item_visibility($courseInfo, 'work', $workId, $sessionId);
5929
    if ($visibility != 1) {
5930
        api_not_allowed(true);
5931
    }*/
5932
5933
    $isAllow = allowOnlySubscribedUser($userId, $workId, $courseInfo['real_id']);
5934
    if (empty($isAllow)) {
5935
        api_not_allowed(true);
5936
    }
5937
5938
    $groupInfo = GroupManager::get_group_properties($groupId);
5939
5940
    if (!empty($groupId)) {
5941
        $showWork = GroupManager::user_has_access(
5942
            $userId,
5943
            $groupInfo['iid'],
5944
            GroupManager::GROUP_TOOL_WORK
5945
        );
5946
        if (!$showWork) {
5947
            api_not_allowed(true);
5948
        }
5949
    }
5950
}
5951
5952
/**
5953
 * @param array $courseInfo
5954
 * @param array $work
5955
 */
5956
function deleteCorrection($courseInfo, $work)
5957
{
5958
    throw new Exception('deleteCorrection');
5959
    /*
5960
    if (isset($work['url_correction']) && !empty($work['url_correction']) && isset($work['iid'])) {
5961
        $id = $work['iid'];
5962
        $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
5963
        $sql = "UPDATE $table SET
5964
                    url_correction = '',
5965
                    title_correction = ''
5966
                WHERE iid = $id";
5967
        Database::query($sql);
5968
        $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/';
5969
        if (file_exists($coursePath.$work['url_correction'])) {
5970
            if (Security::check_abs_path($coursePath.$work['url_correction'], $coursePath)) {
5971
                unlink($coursePath.$work['url_correction']);
5972
            }
5973
        }
5974
    }*/
5975
}
5976
5977
/**
5978
 * @param int $workId
5979
 *
5980
 * @return string
5981
 */
5982
function workGetExtraFieldData($workId)
5983
{
5984
    $sessionField = new ExtraField('work');
5985
    $extraFieldData = $sessionField->getDataAndFormattedValues($workId);
5986
    $result = '';
5987
    if (!empty($extraFieldData)) {
5988
        $result .= '<div class="well">';
5989
        foreach ($extraFieldData as $data) {
5990
            $result .= $data['text'].': <b>'.$data['value'].'</b>';
5991
        }
5992
        $result .= '</div>';
5993
    }
5994
5995
    return $result;
5996
}
5997