Passed
Push — master ( f9e6b3...5e8c5a )
by Julito
09:39
created

getDocumentTemplateFromWork()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 27
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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