Test Failed
Push — master ( 482637...7bef58 )
by Julito
33:32
created

insert_all_directory_in_course_table()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 33
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 24
nc 8
nop 1
dl 0
loc 33
rs 8.5806
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CourseBundle\Entity\CStudentPublication;
5
use ChamiloSession as Session;
6
7
/**
8
 *  @package chamilo.work
9
 *
10
 *  @author Thomas, Hugues, Christophe - original version
11
 *  @author Patrick Cool <[email protected]>, Ghent University -
12
 * ability for course admins to specify wether uploaded documents are visible or invisible by default.
13
 *  @author Roan Embrechts, code refactoring and virtual course support
14
 *  @author Frederic Vauthier, directories management
15
 *  @author Julio Montoya <[email protected]> BeezNest 2011 LOTS of bug fixes
16
 *
17
 *  @todo   this lib should be convert in a static class and moved to main/inc/lib
18
 */
19
20
/**
21
 * Displays action links (for admins, authorized groups members and authorized students).
22
 *
23
 * @param   int Whether to show tool options
24
 * @param   int Whether to show upload form option
25
 * @param bool $isTutor
26
 */
27
function displayWorkActionLinks($id, $action, $isTutor)
28
{
29
    $id = $my_back_id = intval($id);
30
    if ($action == 'list') {
31
        $my_back_id = 0;
32
    }
33
34
    $output = '';
35
    $origin = api_get_origin();
36
37
    if (!empty($id)) {
38
        $output .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&id='.$my_back_id.'">'.
39
            Display::return_icon('back.png', get_lang('BackToWorksList'), '', ICON_SIZE_MEDIUM).
40
            '</a>';
41
    }
42
43
    if (($isTutor || api_is_allowed_to_edit(null, true)) &&
44
        $origin != 'learnpath'
45
    ) {
46
        // Create dir
47
        if (empty($id)) {
48
            $output .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=create_dir">';
49
            $output .= Display::return_icon(
50
                'new_work.png',
51
                get_lang('CreateAssignment'),
52
                '',
53
                ICON_SIZE_MEDIUM
54
            );
55
            $output .= '</a>';
56
        }
57
    }
58
59
    if (api_is_allowed_to_edit(null, true) && $origin != 'learnpath') {
60
        if (empty($id)) {
61
            // Options
62
            $output .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=settings">';
63
            $output .= Display::return_icon(
64
                'settings.png',
65
                get_lang('EditToolOptions'),
66
                '',
67
                ICON_SIZE_MEDIUM
68
            ).'</a>';
69
        }
70
        $output .= '<a id="open-view-list" href="#">'.
71
            Display::return_icon(
72
                'listwork.png',
73
                get_lang('ViewStudents'),
74
                '',
75
                ICON_SIZE_MEDIUM
76
            ).
77
            '</a>';
78
    }
79
80
    if ($output != '') {
81
        echo '<div class="actions">';
82
        echo $output;
83
        echo '</div>';
84
    }
85
}
86
87
/**
88
 * Returns a form displaying all options for this tool.
89
 * These are
90
 * - make all files visible / invisible
91
 * - set the default visibility of uploaded files.
92
 *
93
 * @param $defaults
94
 *
95
 * @return string The HTML form
96
 */
97
function settingsForm($defaults)
98
{
99
    $allowed = api_is_allowed_to_edit(null, true);
100
    if (!$allowed) {
101
        return;
102
    }
103
104
    $url = api_get_path(WEB_CODE_PATH).'work/work.php?'.api_get_cidreq().'&action=settings';
105
    $form = new FormValidator('edit_settings', 'post', $url);
106
    $form->addElement('hidden', 'changeProperties', 1);
107
    $form->addElement('header', get_lang('EditToolOptions'));
108
109
    $group = [
110
        $form->createElement('radio', 'show_score', null, get_lang('NewVisible'), 0),
111
        $form->createElement('radio', 'show_score', null, get_lang('NewUnvisible'), 1),
112
    ];
113
    $form->addGroup($group, '', get_lang('DefaultUpload'));
114
115
    $group = [
116
        $form->createElement('radio', 'student_delete_own_publication', null, get_lang('Yes'), 1),
117
        $form->createElement('radio', 'student_delete_own_publication', null, get_lang('No'), 0),
118
    ];
119
    $form->addGroup($group, '', get_lang('StudentAllowedToDeleteOwnPublication'));
120
    $form->addButtonSave(get_lang('Save'));
121
    $form->setDefaults($defaults);
122
123
    return $form->returnForm();
124
}
125
126
/**
127
 * @param string $path
128
 * @param int    $courseId
129
 *
130
 * @return array
131
 */
132
function get_work_data_by_path($path, $courseId = 0)
133
{
134
    $path = Database::escape_string($path);
135
    $courseId = intval($courseId);
136
    if (empty($courseId)) {
137
        $courseId = api_get_course_int_id();
138
    }
139
140
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
141
    $sql = "SELECT *  FROM $table
142
            WHERE url = '$path' AND c_id = $courseId ";
143
    $result = Database::query($sql);
144
    $return = [];
145
    if (Database::num_rows($result)) {
146
        $return = Database::fetch_array($result, 'ASSOC');
147
    }
148
149
    return $return;
150
}
151
152
/**
153
 * @param int $id
154
 * @param int $courseId
155
 * @param int $sessionId
156
 *
157
 * @return array
158
 */
159
function get_work_data_by_id($id, $courseId = 0, $sessionId = 0)
160
{
161
    $id = intval($id);
162
    $courseId = intval($courseId);
163
    if (empty($courseId)) {
164
        $courseId = api_get_course_int_id();
165
    }
166
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
167
168
    $sessionCondition = '';
169
    if (!empty($sessionId)) {
170
        $sessionCondition = api_get_session_condition($sessionId, true);
171
    }
172
173
    $sql = "SELECT * FROM $table
174
            WHERE
175
                id = $id AND c_id = $courseId
176
                $sessionCondition";
177
    $result = Database::query($sql);
178
    $work = [];
179
    if (Database::num_rows($result)) {
180
        $work = Database::fetch_array($result, 'ASSOC');
181
        if (empty($work['title'])) {
182
            $work['title'] = basename($work['url']);
183
        }
184
        $work['download_url'] = api_get_path(WEB_CODE_PATH).'work/download.php?id='.$work['id'].'&'.api_get_cidreq();
185
        $work['view_url'] = api_get_path(WEB_CODE_PATH).'work/view.php?id='.$work['id'].'&'.api_get_cidreq();
186
        $work['show_url'] = api_get_path(WEB_CODE_PATH).'work/show_file.php?id='.$work['id'].'&'.api_get_cidreq();
187
        $work['show_content'] = '';
188
        if ($work['contains_file']) {
189
            $fileInfo = pathinfo($work['title']);
190
            if (is_array($fileInfo) &&
191
                !empty($fileInfo['extension']) &&
192
                in_array($fileInfo['extension'], ['jpg', 'png', 'gif'])
193
            ) {
194
                $work['show_content'] = '<img src="'.$work['show_url'].'"/>';
195
            }
196
        }
197
198
        $fieldValue = new ExtraFieldValue('work');
199
        $work['extra'] = $fieldValue->getAllValuesForAnItem(
200
            $id,
201
            true
202
        );
203
    }
204
205
    return $work;
206
}
207
208
/**
209
 * @param int $user_id
210
 * @param int $work_id
211
 *
212
 * @return int
213
 */
214
function get_work_count_by_student($user_id, $work_id)
215
{
216
    $user_id = intval($user_id);
217
    $work_id = intval($work_id);
218
    $course_id = api_get_course_int_id();
219
    $session_id = api_get_session_id();
220
    $sessionCondition = api_get_session_condition($session_id);
221
222
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
223
    $sql = "SELECT COUNT(*) as count
224
            FROM  $table
225
            WHERE
226
                c_id = $course_id AND
227
                parent_id = $work_id AND
228
                user_id = $user_id AND
229
                active IN (0, 1)
230
                $sessionCondition";
231
    $result = Database::query($sql);
232
    $return = 0;
233
    if (Database::num_rows($result)) {
234
        $return = Database::fetch_row($result, 'ASSOC');
235
        $return = intval($return[0]);
236
    }
237
238
    return $return;
239
}
240
241
/**
242
 * @param int $id
243
 * @param int $courseId
244
 *
245
 * @return array
246
 */
247
function get_work_assignment_by_id($id, $courseId = 0)
248
{
249
    $courseId = intval($courseId);
250
    if (empty($courseId)) {
251
        $courseId = api_get_course_int_id();
252
    }
253
    $id = intval($id);
254
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
255
    $sql = "SELECT * FROM $table
256
            WHERE c_id = $courseId AND publication_id = $id";
257
    $result = Database::query($sql);
258
    $return = [];
259
    if (Database::num_rows($result)) {
260
        $return = Database::fetch_array($result, 'ASSOC');
261
    }
262
263
    return $return;
264
}
265
266
/**
267
 * @param int    $id
268
 * @param array  $my_folder_data
269
 * @param string $add_in_where_query
270
 * @param int    $course_id
271
 * @param int    $session_id
272
 *
273
 * @return array
274
 */
275
function getWorkList($id, $my_folder_data, $add_in_where_query = null, $course_id = 0, $session_id = 0)
276
{
277
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
278
279
    $course_id = $course_id ? $course_id : api_get_course_int_id();
280
    $session_id = $session_id ? $session_id : api_get_session_id();
281
    $condition_session = api_get_session_condition($session_id);
282
    $group_id = api_get_group_id();
283
284
    $groupIid = 0;
285
    if ($group_id) {
286
        $groupInfo = GroupManager::get_group_properties($group_id);
287
        if ($groupInfo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $groupInfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
288
            $groupIid = $groupInfo['iid'];
289
        }
290
    }
291
292
    $is_allowed_to_edit = api_is_allowed_to_edit(null, true);
293
    $linkInfo = GradebookUtils::isResourceInCourseGradebook(
294
        api_get_course_id(),
295
        3,
296
        $id,
297
        api_get_session_id()
298
    );
299
300
    if ($linkInfo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $linkInfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
301
        $workInGradeBookLinkId = $linkInfo['id'];
302
        if ($workInGradeBookLinkId) {
303
            if ($is_allowed_to_edit) {
304
                if (intval($my_folder_data['qualification']) == 0) {
305
                    echo Display::return_message(
306
                        get_lang('MaxWeightNeedToBeProvided'),
307
                        'warning'
308
                    );
309
                }
310
            }
311
        }
312
    }
313
314
    $contains_file_query = '';
315
    // Get list from database
316
    if ($is_allowed_to_edit) {
317
        $active_condition = ' active IN (0, 1)';
318
        $sql = "SELECT * FROM $work_table
319
                WHERE
320
                    c_id = $course_id
321
                    $add_in_where_query
322
                    $condition_session AND
323
                    $active_condition AND
324
                    (parent_id = 0)
325
                    $contains_file_query AND 
326
                    post_group_id = $groupIid
327
                ORDER BY sent_date DESC";
328
    } else {
329
        if (!empty($group_id)) {
330
            // set to select only messages posted by the user's group
331
            $group_query = " WHERE c_id = $course_id AND post_group_id = $groupIid";
332
            $subdirs_query = " AND parent_id = 0";
333
        } else {
334
            $group_query = " WHERE c_id = $course_id AND (post_group_id = '0' OR post_group_id is NULL) ";
335
            $subdirs_query = " AND parent_id = 0";
336
        }
337
        //@todo how we can active or not an assignment?
338
        $active_condition = ' AND active IN (1, 0)';
339
        $sql = "SELECT * FROM  $work_table
340
                $group_query
341
                $subdirs_query
342
                $add_in_where_query
343
                $active_condition
344
                $condition_session
345
                ORDER BY title";
346
    }
347
348
    $work_parents = [];
349
350
    $sql_result = Database::query($sql);
351
    if (Database::num_rows($sql_result)) {
352
        while ($work = Database::fetch_object($sql_result)) {
353
            if ($work->parent_id == 0) {
354
                $work_parents[] = $work;
355
            }
356
        }
357
    }
358
359
    return $work_parents;
360
}
361
362
/**
363
 * @param int $userId
364
 * @param int $courseId
365
 * @param int $sessionId
366
 *
367
 * @return array
368
 */
369
function getWorkPerUser($userId, $courseId = 0, $sessionId = 0)
370
{
371
    $works = getWorkList(null, null, null, $courseId, $sessionId);
372
    $result = [];
373
    if (!empty($works)) {
374
        foreach ($works as $workData) {
375
            $workId = $workData->id;
376
            $result[$workId]['work'] = $workData;
377
            $result[$workId]['work']->user_results = get_work_user_list(
378
                0,
379
                100,
380
                null,
381
                null,
382
                $workId,
383
                null,
384
                $userId,
385
                false,
386
                $courseId,
387
                $sessionId
388
            );
389
        }
390
    }
391
392
    return $result;
393
}
394
395
/**
396
 * @param int $workId
397
 * @param int $groupId
398
 * @param int $course_id
399
 * @param int $sessionId
400
 *
401
 * @return mixed
402
 */
403
function getUniqueStudentAttemptsTotal($workId, $groupId, $course_id, $sessionId)
404
{
405
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
406
    $user_table = Database::get_main_table(TABLE_MAIN_USER);
407
    $course_id = intval($course_id);
408
    $workId = intval($workId);
409
    $sessionId = intval($sessionId);
410
    $groupId = intval($groupId);
411
    $sessionCondition = api_get_session_condition(
412
        $sessionId,
413
        true,
414
        false,
415
        'w.session_id'
416
    );
417
418
    $groupIid = 0;
419
    if ($groupId) {
420
        $groupInfo = GroupManager::get_group_properties($groupId);
421
        $groupIid = $groupInfo['iid'];
422
    }
423
424
    $sql = "SELECT count(DISTINCT u.user_id)
425
            FROM $work_table w
426
            INNER JOIN $user_table u
427
            ON w.user_id = u.user_id
428
            WHERE
429
                w.c_id = $course_id
430
                $sessionCondition AND
431
                w.parent_id = $workId AND
432
                w.post_group_id = $groupIid AND
433
                w.active IN (0, 1)
434
            ";
435
436
    $res_document = Database::query($sql);
437
    $rowCount = Database::fetch_row($res_document);
438
439
    return $rowCount[0];
440
}
441
442
/**
443
 * @param mixed $workId
444
 * @param int   $groupId
445
 * @param int   $course_id
446
 * @param int   $sessionId
447
 * @param int   $userId       user id to filter
448
 * @param array $onlyUserList only parse this user list
449
 *
450
 * @return mixed
451
 */
452
function getUniqueStudentAttempts(
453
    $workId,
454
    $groupId,
455
    $course_id,
456
    $sessionId,
457
    $userId = null,
458
    $onlyUserList = []
459
) {
460
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
461
    $user_table = Database::get_main_table(TABLE_MAIN_USER);
462
463
    $course_id = intval($course_id);
464
    $workCondition = null;
465
    if (is_array($workId)) {
466
        $workId = array_map('intval', $workId);
467
        $workId = implode("','", $workId);
468
        $workCondition = " w.parent_id IN ('".$workId."') AND";
469
    } else {
470
        $workId = intval($workId);
471
        $workCondition = " w.parent_id = ".$workId." AND";
472
    }
473
474
    $sessionId = intval($sessionId);
475
    $groupId = intval($groupId);
476
    $studentCondition = null;
477
478
    if (!empty($onlyUserList)) {
479
        $onlyUserList = array_map('intval', $onlyUserList);
480
        $studentCondition = "AND u.user_id IN ('".implode("', '", $onlyUserList)."') ";
481
    } else {
482
        if (empty($userId)) {
483
            return 0;
484
        }
485
    }
486
487
    $groupIid = 0;
488
    if ($groupId) {
489
        $groupInfo = GroupManager::get_group_properties($groupId);
490
        $groupIid = $groupInfo['iid'];
491
    }
492
493
    $sessionCondition = api_get_session_condition(
494
        $sessionId,
495
        true,
496
        false,
497
        'w.session_id'
498
    );
499
500
    $sql = "SELECT count(*) FROM (
501
                SELECT count(*), w.parent_id
502
                FROM $work_table w
503
                INNER JOIN $user_table u
504
                ON w.user_id = u.user_id
505
                WHERE
506
                    w.filetype = 'file' AND
507
                    w.c_id = $course_id
508
                    $sessionCondition AND
509
                    $workCondition
510
                    w.post_group_id = $groupIid AND
511
                    w.active IN (0, 1) $studentCondition
512
                ";
513
    if (!empty($userId)) {
514
        $userId = intval($userId);
515
        $sql .= " AND u.user_id = ".$userId;
516
    }
517
    $sql .= " GROUP BY u.user_id, w.parent_id) as t";
518
    $result = Database::query($sql);
519
    $row = Database::fetch_row($result);
520
521
    return $row[0];
522
}
523
524
/**
525
 * Shows the work list (student view).
526
 *
527
 * @return string
528
 */
529
function showStudentWorkGrid()
530
{
531
    $courseInfo = api_get_course_info();
532
    $url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_work_student&'.api_get_cidreq();
533
534
    $columns = [
535
        get_lang('Type'),
536
        get_lang('Title'),
537
        get_lang('HandOutDateLimit'),
538
        get_lang('Feedback'),
539
        get_lang('LastUpload'),
540
    ];
541
542
    $columnModel = [
543
        ['name' => 'type', 'index' => 'type', 'width' => '30', 'align' => 'center', 'sortable' => 'false'],
544
        ['name' => 'title', 'index' => 'title', 'width' => '250', 'align' => 'left'],
545
        ['name' => 'expires_on', 'index' => 'expires_on', 'width' => '80', 'align' => 'center', 'sortable' => 'false'],
546
        ['name' => 'feedback', 'index' => 'feedback', 'width' => '80', 'align' => 'center', 'sortable' => 'false'],
547
        ['name' => 'last_upload', 'index' => 'feedback', 'width' => '125', 'align' => 'center', 'sortable' => 'false'],
548
    ];
549
550
    if ($courseInfo['show_score'] == 0) {
551
        $columnModel[] = [
552
            'name' => 'others',
553
            'index' => 'others',
554
            'width' => '80',
555
            'align' => 'left',
556
            'sortable' => 'false',
557
        ];
558
        $columns[] = get_lang('Others');
559
    }
560
561
    $params = [
562
        'autowidth' => 'true',
563
        'height' => 'auto',
564
    ];
565
566
    $html = '<script>
567
        $(function() {
568
            '.Display::grid_js('workList', $url, $columns, $columnModel, $params, [], null, true).'
569
        });
570
    </script>';
571
572
    $html .= Display::grid_html('workList');
573
574
    return $html;
575
}
576
577
/**
578
 * Shows the work list (teacher view).
579
 *
580
 * @return string
581
 */
582
function showTeacherWorkGrid()
583
{
584
    $columnModel = [
585
        ['name' => 'type', 'index' => 'type', 'width' => '35', 'align' => 'center', 'sortable' => 'false'],
586
        ['name' => 'title', 'index' => 'title', 'width' => '300', 'align' => 'left', 'wrap_cell' => "true"],
587
        ['name' => 'sent_date', 'index' => 'sent_date', 'width' => '125', 'align' => 'center'],
588
        ['name' => 'expires_on', 'index' => 'expires_on', 'width' => '125', 'align' => 'center'],
589
        ['name' => 'amount', 'index' => 'amount', 'width' => '110', 'align' => 'center', 'sortable' => 'false'],
590
        ['name' => 'actions', 'index' => 'actions', 'width' => '110', 'align' => 'left', 'sortable' => 'false'],
591
    ];
592
    $url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_work_teacher&'.api_get_cidreq();
593
    $deleteUrl = api_get_path(WEB_AJAX_PATH).'work.ajax.php?a=delete_work&'.api_get_cidreq();
594
595
    $columns = [
596
        get_lang('Type'),
597
        get_lang('Title'),
598
        get_lang('SentDate'),
599
        get_lang('HandOutDateLimit'),
600
        get_lang('AmountSubmitted'),
601
        get_lang('Actions'),
602
    ];
603
604
    $params = [
605
        'multiselect' => true,
606
        'autowidth' => 'true',
607
        'height' => 'auto',
608
    ];
609
610
    $html = '<script>
611
    $(function() {
612
        '.Display::grid_js('workList', $url, $columns, $columnModel, $params, [], null, true).'
613
        $("#workList").jqGrid(
614
            "navGrid",
615
            "#workList_pager",
616
            { edit: false, add: false, del: true },
617
            { height:280, reloadAfterSubmit:false }, // edit options
618
            { height:280, reloadAfterSubmit:false }, // add options
619
            { reloadAfterSubmit:false, url: "'.$deleteUrl.'" }, // del options
620
            { width:500 } // search options
621
        );
622
    });
623
    </script>';
624
    $html .= Display::grid_html('workList');
625
626
    return $html;
627
}
628
629
/**
630
 * Builds the form thats enables the user to
631
 * select a directory to browse/upload in
632
 * This function has been copied from the document/document.inc.php library.
633
 *
634
 * @param array  $folders
635
 * @param string $curdirpath
636
 * @param string $group_dir
637
 *
638
 * @return string html form
639
 */
640
// TODO: This function is a candidate for removal, it is not used anywhere.
641
function build_work_directory_selector($folders, $curdirpath, $group_dir = '')
642
{
643
    $form = '<form name="selector" action="'.api_get_self().'?'.api_get_cidreq().'" method="POST">';
644
    $form .= get_lang('CurrentDirectory').' 
645
             <select name="curdirpath" onchange="javascript: document.selector.submit();">';
646
    //group documents cannot be uploaded in the root
647
    if ($group_dir == '') {
648
        $form .= '<option value="/">/ ('.get_lang('Root').')</option>';
649
        if (is_array($folders)) {
650
            foreach ($folders as $folder) {
651
                $selected = ($curdirpath == $folder) ? ' selected="selected"' : '';
652
                $form .= '<option'.$selected.' value="'.$folder.'">'.$folder.'</option>'."\n";
653
            }
654
        }
655
    } else {
656
        foreach ($folders as $folder) {
657
            $selected = ($curdirpath == $folder) ? ' selected="selected"' : '';
658
            $display_folder = substr($folder, strlen($group_dir));
659
            $display_folder = ($display_folder == '') ? '/ ('.get_lang('Root').')' : $display_folder;
660
            $form .= '<option'.$selected.' value="'.$folder.'">'.$display_folder.'</option>'."\n";
661
        }
662
    }
663
664
    $form .= '</select>';
665
    $form .= '<noscript><input type="submit" name="change_path" value="'.get_lang('Ok').'" /></noscript>';
666
    $form .= '</form>';
667
668
    return $form;
669
}
670
671
/**
672
 * Builds the form that enables the user to
673
 * move a document from one directory to another
674
 * This function has been copied from the document/document.inc.php library.
675
 *
676
 * @param array  $folders
677
 * @param string $curdirpath
678
 * @param string $move_file
679
 * @param string $group_dir
680
 *
681
 * @return string html form
682
 */
683
function build_work_move_to_selector($folders, $curdirpath, $move_file, $group_dir = '')
684
{
685
    $course_id = api_get_course_int_id();
686
    $move_file = intval($move_file);
687
    $tbl_work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
688
    $sql = "SELECT title, url FROM $tbl_work
689
            WHERE c_id = $course_id AND id ='".$move_file."'";
690
    $result = Database::query($sql);
691
    $row = Database::fetch_array($result, 'ASSOC');
692
    $title = empty($row['title']) ? basename($row['url']) : $row['title'];
693
694
    $form = new FormValidator(
695
        'move_to_form',
696
        'post',
697
        api_get_self().'?'.api_get_cidreq().'&curdirpath='.Security::remove_XSS($curdirpath)
698
    );
699
700
    $form->addHeader(get_lang('MoveFile').' - '.Security::remove_XSS($title));
701
    $form->addHidden('item_id', $move_file);
702
    $form->addHidden('action', 'move_to');
703
704
    // Group documents cannot be uploaded in the root
705
    if ($group_dir == '') {
706
        if (is_array($folders)) {
707
            foreach ($folders as $fid => $folder) {
708
                //you cannot move a file to:
709
                //1. current directory
710
                //2. inside the folder you want to move
711
                //3. inside a subfolder of the folder you want to move
712
                if (($curdirpath != $folder) &&
713
                    ($folder != $move_file) &&
714
                    (substr($folder, 0, strlen($move_file) + 1) != $move_file.'/')
715
                ) {
716
                    $options[$fid] = $folder;
717
                }
718
            }
719
        }
720
    } else {
721
        if ($curdirpath != '/') {
722
            $form .= '<option value="0">/ ('.get_lang('Root').')</option>';
723
        }
724
        foreach ($folders as $fid => $folder) {
725
            if (($curdirpath != $folder) && ($folder != $move_file) &&
726
                (substr($folder, 0, strlen($move_file) + 1) != $move_file.'/')
727
            ) {
728
                //cannot copy dir into his own subdir
729
                $display_folder = substr($folder, strlen($group_dir));
730
                $display_folder = ($display_folder == '') ? '/ ('.get_lang('Root').')' : $display_folder;
731
                //$form .= '<option value="'.$fid.'">'.$display_folder.'</option>'."\n";
732
                $options[$fid] = $display_folder;
733
            }
734
        }
735
    }
736
737
    $form->addSelect('move_to_id', get_lang('Select'), $options);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $options does not seem to be defined for all execution paths leading up to this point.
Loading history...
738
    $form->addButtonSend(get_lang('MoveFile'), 'move_file_submit');
739
740
    return $form->returnForm();
741
}
742
743
/**
744
 * creates a new directory trying to find a directory name
745
 * that doesn't already exist.
746
 *
747
 * @author Hugues Peeters <[email protected]>
748
 * @author Bert Vanderkimpen
749
 * @author Yannick Warnier <[email protected]> Adaptation for work tool
750
 *
751
 * @param string $base_work_dir  Base work dir (.../work)
752
 * @param string $desiredDirName complete path of the desired name
753
 *
754
 * @return string actual directory name if it succeeds, boolean false otherwise
755
 */
756
function create_unexisting_work_directory($base_work_dir, $desired_dir_name)
757
{
758
    $nb = '';
759
    $base_work_dir = (substr($base_work_dir, -1, 1) == '/' ? $base_work_dir : $base_work_dir.'/');
760
    while (file_exists($base_work_dir.$desired_dir_name.$nb)) {
761
        $nb += 1;
762
    }
763
764
    if (@mkdir($base_work_dir.$desired_dir_name.$nb, api_get_permissions_for_new_directories())) {
765
        return $desired_dir_name.$nb;
766
    } else {
767
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
768
    }
769
}
770
771
/**
772
 * Delete a work-tool directory.
773
 *
774
 * @param int $id work directory id to delete
775
 *
776
 * @return int -1 on error
777
 */
778
function deleteDirWork($id)
779
{
780
    $locked = api_resource_is_locked_by_gradebook($id, LINK_STUDENTPUBLICATION);
781
782
    if ($locked == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
783
        echo Display::return_message(get_lang('ResourceLockedByGradebook'), 'warning');
784
785
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
786
    }
787
788
    $_course = api_get_course_info();
789
    $id = intval($id);
790
    $work_data = get_work_data_by_id($id);
791
792
    if (empty($work_data)) {
793
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
794
    }
795
796
    $base_work_dir = api_get_path(SYS_COURSE_PATH).$_course['path'].'/work';
797
    $work_data_url = $base_work_dir.$work_data['url'];
798
    $check = Security::check_abs_path($work_data_url.'/', $base_work_dir.'/');
799
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
800
    $TSTDPUBASG = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
801
    $t_agenda = Database::get_course_table(TABLE_AGENDA);
802
    $course_id = api_get_course_int_id();
803
    $sessionId = api_get_session_id();
804
805
    if (!empty($work_data['url'])) {
806
        if ($check) {
807
            $consideredWorkingTime = api_get_configuration_value('considered_working_time');
808
            if (!empty($consideredWorkingTime)) {
809
                $fieldValue = new ExtraFieldValue('work');
810
                $resultExtra = $fieldValue->getAllValuesForAnItem(
811
                    $work_data['id'],
812
                    true
813
                );
814
815
                $workingTime = null;
816
                foreach ($resultExtra as $field) {
817
                    $field = $field['value'];
818
                    if ($consideredWorkingTime == $field->getField()->getVariable()) {
819
                        $workingTime = $field->getValue();
820
821
                        break;
822
                    }
823
                }
824
825
                $courseUsers = CourseManager::get_user_list_from_course_code($_course['code'], $sessionId);
826
                if (!empty($workingTime)) {
827
                    foreach ($courseUsers as $user) {
828
                        $userWorks = get_work_user_list(
829
                            0,
830
                            100,
831
                            null,
832
                            null,
833
                            $work_data['id'],
834
                            null,
835
                            $user['user_id'],
836
                            false,
837
                            $course_id,
838
                            $sessionId
839
                        );
840
841
                        if (count($userWorks) != 1) {
842
                            continue;
843
                        }
844
                        Event::eventRemoveVirtualCourseTime($course_id, $user['user_id'], $sessionId, $workingTime);
845
                    }
846
                }
847
            }
848
849
            // Deleting all contents inside the folder
850
            $sql = "UPDATE $table SET active = 2
851
                    WHERE c_id = $course_id AND filetype = 'folder' AND id = $id";
852
            Database::query($sql);
853
854
            $sql = "UPDATE $table SET active = 2
855
                    WHERE c_id = $course_id AND parent_id = $id";
856
            Database::query($sql);
857
858
            $new_dir = $work_data_url.'_DELETED_'.$id;
859
860
            if (api_get_setting('permanently_remove_deleted_files') == 'true') {
861
                my_delete($work_data_url);
862
            } else {
863
                if (file_exists($work_data_url)) {
864
                    rename($work_data_url, $new_dir);
865
                }
866
            }
867
868
            // Gets calendar_id from student_publication_assigment
869
            $sql = "SELECT add_to_calendar FROM $TSTDPUBASG
870
                    WHERE c_id = $course_id AND publication_id = $id";
871
            $res = Database::query($sql);
872
            $calendar_id = Database::fetch_row($res);
873
874
            // delete from agenda if it exists
875
            if (!empty($calendar_id[0])) {
876
                $sql = "DELETE FROM $t_agenda
877
                        WHERE c_id = $course_id AND id = '".$calendar_id[0]."'";
878
                Database::query($sql);
879
            }
880
            $sql = "DELETE FROM $TSTDPUBASG
881
                    WHERE c_id = $course_id AND publication_id = $id";
882
            Database::query($sql);
883
884
            Skill::deleteSkillsFromItem($id, ITEM_TYPE_STUDENT_PUBLICATION);
885
886
            Event::addEvent(
887
                LOG_WORK_DIR_DELETE,
888
                LOG_WORK_DATA,
889
                [
890
                    'id' => $work_data['id'],
891
                    'url' => $work_data['url'],
892
                    'title' => $work_data['title'],
893
                ],
894
                null,
895
                api_get_user_id(),
896
                api_get_course_int_id(),
897
                $sessionId
898
            );
899
900
            $linkInfo = GradebookUtils::isResourceInCourseGradebook(
901
                api_get_course_id(),
902
                3,
903
                $id,
904
                api_get_session_id()
905
            );
906
            $link_id = $linkInfo['id'];
907
            if ($linkInfo !== false) {
908
                GradebookUtils::remove_resource_from_course_gradebook($link_id);
909
            }
910
911
            return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the documented return type integer.
Loading history...
912
        }
913
    }
914
}
915
916
/**
917
 * Get the path of a document in the student_publication table (path relative to the course directory).
918
 *
919
 * @param int $id
920
 *
921
 * @return string Path (or -1 on error)
922
 */
923
function get_work_path($id)
924
{
925
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
926
    $course_id = api_get_course_int_id();
927
    $sql = 'SELECT url FROM '.$table.'
928
            WHERE c_id = '.$course_id.' AND id='.intval($id);
929
    $res = Database::query($sql);
930
    if (Database::num_rows($res)) {
931
        $row = Database::fetch_array($res);
932
933
        return $row['url'];
934
    }
935
936
    return -1;
937
}
938
939
/**
940
 * Update the url of a work in the student_publication table.
941
 *
942
 * @param int    $id        of the work to update
943
 * @param string $new_path  Destination directory where the work has been moved (must end with a '/')
944
 * @param int    $parent_id
945
 *
946
 * @return mixed Int -1 on error, sql query result on success
947
 */
948
function updateWorkUrl($id, $new_path, $parent_id)
949
{
950
    if (empty($id)) {
951
        return -1;
952
    }
953
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
954
    $course_id = api_get_course_int_id();
955
    $id = intval($id);
956
    $parent_id = intval($parent_id);
957
958
    $sql = "SELECT * FROM $table
959
            WHERE c_id = $course_id AND id = $id";
960
    $res = Database::query($sql);
961
    if (Database::num_rows($res) != 1) {
962
        return -1;
963
    } else {
964
        $row = Database::fetch_array($res);
965
        $filename = basename($row['url']);
966
        $new_url = $new_path.$filename;
967
        $new_url = Database::escape_string($new_url);
968
969
        $sql = "UPDATE $table SET
970
                   url = '$new_url',
971
                   parent_id = '$parent_id'
972
                WHERE c_id = $course_id AND id = $id";
973
        $res = Database::query($sql);
974
975
        return $res;
976
    }
977
}
978
979
/**
980
 * Update the url of a dir in the student_publication table.
981
 *
982
 * @param array  $work_data work original data
983
 * @param string $newPath   Example: "folder1"
984
 *
985
 * @return bool
986
 */
987
function updateDirName($work_data, $newPath)
988
{
989
    $course_id = $work_data['c_id'];
990
    $work_id = intval($work_data['iid']);
991
    $oldPath = $work_data['url'];
992
    $originalNewPath = Database::escape_string($newPath);
993
    $newPath = Database::escape_string($newPath);
994
    $newPath = api_replace_dangerous_char($newPath);
995
    $newPath = disable_dangerous_file($newPath);
996
997
    if ($oldPath == '/'.$newPath) {
998
        return true;
999
    }
1000
1001
    if (!empty($newPath)) {
1002
        $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
1003
        $sql = "UPDATE $table SET
1004
                    title = '".$originalNewPath."'
1005
                WHERE
1006
                    c_id = $course_id AND
1007
                    iid = $work_id";
1008
        Database::query($sql);
1009
    }
1010
}
1011
1012
/**
1013
 * returns all the javascript that is required for easily
1014
 * validation when you create a work
1015
 * this goes into the $htmlHeadXtra[] array.
1016
 */
1017
function to_javascript_work()
1018
{
1019
    $js = '<script> 
1020
        function updateDocumentTitle(value) {
1021
            var temp = value.indexOf("/");            
1022
            //linux path
1023
            if(temp != -1){
1024
                temp=value.split("/");
1025
            } else {
1026
                temp=value.split("\\\");
1027
            }
1028
            
1029
            var fullFilename = temp[temp.length - 1];
1030
            var baseFilename = fullFilename;
1031
            
1032
            // get file extension
1033
            var fileExtension = "";
1034
            if (fullFilename.match(/\..+/)) {
1035
                fileInfo = fullFilename.match(/(.*)\.([^.]+)$/);
1036
                if (fileInfo.length > 1) {
1037
                    fileExtension = "."+fileInfo[fileInfo.length - 1];
1038
                    baseFilename = fileInfo[fileInfo.length - 2];
1039
                }
1040
            }
1041
            
1042
            document.getElementById("file_upload").value = baseFilename;
1043
            document.getElementById("file_extension").value = fileExtension;                
1044
            $("#contains_file_id").attr("value", 1);
1045
        }
1046
        function setFocus() {
1047
            $("#work_title").focus();
1048
        }
1049
1050
        $(document).ready(function() {
1051
            setFocus();
1052
            var checked = $("#expiry_date").attr("checked");
1053
            if (checked) {
1054
                $("#option2").show();                
1055
            } else {
1056
                $("#option2").hide();                
1057
            }
1058
            
1059
            var checkedEndDate = $("#end_date").attr("checked");            
1060
            if (checkedEndDate) {                
1061
                $("#option3").show();
1062
                $("#ends_on").attr("checked", true);
1063
            } else {
1064
                $("#option3").hide();                
1065
                $("#ends_on").attr("checked", false);
1066
            }
1067
1068
            $("#expiry_date").click(function() {
1069
                $("#option2").toggle();
1070
            });
1071
1072
            $("#end_date").click(function() {
1073
                $("#option3").toggle();
1074
            });
1075
        });
1076
    </script>';
1077
1078
    return $js;
1079
}
1080
1081
/**
1082
 * Gets the id of a student publication with a given path.
1083
 *
1084
 * @param string $path
1085
 *
1086
 * @return true if is found / false if not found
1087
 */
1088
// TODO: The name of this function does not fit with the kind of information it returns.
1089
// Maybe check_work_id() or is_work_id()?
1090
function get_work_id($path)
1091
{
1092
    $TBL_STUDENT_PUBLICATION = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
1093
    $TBL_PROP_TABLE = Database::get_course_table(TABLE_ITEM_PROPERTY);
1094
    $course_id = api_get_course_int_id();
1095
    $path = Database::escape_string($path);
1096
1097
    if (api_is_allowed_to_edit()) {
1098
        $sql = "SELECT work.id
1099
                FROM $TBL_STUDENT_PUBLICATION AS work, $TBL_PROP_TABLE AS props
1100
                WHERE
1101
                    props.c_id = $course_id AND
1102
                    work.c_id = $course_id AND
1103
                    props.tool='work' AND
1104
                    work.id=props.ref AND
1105
                    work.url LIKE 'work/".$path."%' AND
1106
                    work.filetype='file' AND
1107
                    props.visibility<>'2'";
1108
    } else {
1109
        $sql = "SELECT work.id
1110
                FROM $TBL_STUDENT_PUBLICATION AS work, $TBL_PROP_TABLE AS props
1111
                WHERE
1112
                    props.c_id = $course_id AND
1113
                    work.c_id = $course_id AND
1114
                    props.tool='work' AND
1115
                    work.id=props.ref AND
1116
                    work.url LIKE 'work/".$path."%' AND
1117
                    work.filetype='file' AND
1118
                    props.visibility<>'2' AND
1119
                    props.lastedit_user_id = '".api_get_user_id()."'";
1120
    }
1121
    $result = Database::query($sql);
1122
    $num_rows = Database::num_rows($result);
1123
1124
    if ($result && $num_rows > 0) {
1125
        return true;
1126
    } else {
1127
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type true.
Loading history...
1128
    }
1129
}
1130
1131
/**
1132
 * @param int $work_id
1133
 * @param int $onlyMeUserId show only my works
1134
 * @param int $notMeUserId  show works from everyone except me
1135
 *
1136
 * @return int
1137
 */
1138
function get_count_work($work_id, $onlyMeUserId = null, $notMeUserId = null)
1139
{
1140
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
1141
    $iprop_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
1142
    $user_table = Database::get_main_table(TABLE_MAIN_USER);
1143
1144
    $is_allowed_to_edit = api_is_allowed_to_edit(null, true);
1145
    $session_id = api_get_session_id();
1146
    $condition_session = api_get_session_condition(
1147
        $session_id,
1148
        true,
1149
        false,
1150
        'work.session_id'
1151
    );
1152
1153
    $group_id = api_get_group_id();
1154
    $course_info = api_get_course_info();
1155
    $course_id = $course_info['real_id'];
1156
    $work_id = intval($work_id);
1157
1158
    $groupIid = 0;
1159
    if ($group_id) {
1160
        $groupInfo = GroupManager::get_group_properties($group_id);
1161
        $groupIid = $groupInfo['iid'];
1162
    }
1163
1164
    if (!empty($group_id)) {
1165
        // set to select only messages posted by the user's group
1166
        $extra_conditions = " work.post_group_id = '".intval($groupIid)."' ";
1167
    } else {
1168
        $extra_conditions = " (work.post_group_id = '0' or work.post_group_id IS NULL) ";
1169
    }
1170
1171
    if ($is_allowed_to_edit) {
1172
        $extra_conditions .= ' AND work.active IN (0, 1) ';
1173
    } else {
1174
        $extra_conditions .= ' AND work.active IN (0, 1) AND accepted = 1';
1175
        if (isset($course_info['show_score']) && $course_info['show_score'] == 1) {
1176
            $extra_conditions .= " AND work.user_id = ".api_get_user_id()." ";
1177
        } else {
1178
            $extra_conditions .= '';
1179
        }
1180
    }
1181
1182
    $extra_conditions .= " AND parent_id  = ".$work_id."  ";
1183
    $where_condition = null;
1184
    if (!empty($notMeUserId)) {
1185
        $where_condition .= " AND u.user_id <> ".intval($notMeUserId);
1186
    }
1187
1188
    if (!empty($onlyMeUserId)) {
1189
        $where_condition .= " AND u.user_id =  ".intval($onlyMeUserId);
1190
    }
1191
1192
    $sql = "SELECT count(*) as count
1193
            FROM $iprop_table prop
1194
            INNER JOIN $work_table work
1195
            ON (
1196
                prop.ref = work.id AND
1197
                prop.c_id = $course_id AND
1198
                prop.tool='work' AND
1199
                prop.visibility <> 2 AND
1200
                work.c_id = $course_id
1201
            )
1202
            INNER JOIN $user_table u 
1203
            ON (work.user_id = u.user_id)
1204
            WHERE $extra_conditions $where_condition $condition_session";
1205
1206
    $result = Database::query($sql);
1207
1208
    $users_with_work = 0;
1209
    if (Database::num_rows($result)) {
1210
        $result = Database::fetch_array($result);
1211
        $users_with_work = $result['count'];
1212
    }
1213
1214
    return $users_with_work;
1215
}
1216
1217
/**
1218
 * @param int    $start
1219
 * @param int    $limit
1220
 * @param string $column
1221
 * @param string $direction
1222
 * @param string $where_condition
1223
 * @param bool   $getCount
1224
 *
1225
 * @return array
1226
 */
1227
function getWorkListStudent(
1228
    $start,
1229
    $limit,
1230
    $column,
1231
    $direction,
1232
    $where_condition,
1233
    $getCount = false
1234
) {
1235
    $workTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
1236
    $workTableAssignment = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
1237
    $courseInfo = api_get_course_info();
1238
    $course_id = $courseInfo['real_id'];
1239
    $session_id = api_get_session_id();
1240
    $condition_session = api_get_session_condition($session_id);
1241
    $group_id = api_get_group_id();
1242
    $userId = api_get_user_id();
1243
1244
    $isDrhOfCourse = CourseManager::isUserSubscribedInCourseAsDrh(
1245
        api_get_user_id(),
1246
        $courseInfo
1247
    );
1248
1249
    if (!in_array($direction, ['asc', 'desc'])) {
1250
        $direction = 'desc';
1251
    }
1252
    if (!empty($where_condition)) {
1253
        $where_condition = ' AND '.$where_condition;
1254
    }
1255
1256
    $column = !empty($column) ? Database::escape_string($column) : 'sent_date';
1257
    $start = intval($start);
1258
    $limit = intval($limit);
1259
1260
    $groupIid = 0;
1261
    if ($group_id) {
1262
        $groupInfo = GroupManager::get_group_properties($group_id);
1263
        $groupIid = $groupInfo['iid'];
1264
    }
1265
    $groupIid = (int) $groupIid;
1266
1267
    // Get list from database
1268
    if (!empty($groupIid)) {
1269
        $group_query = " WHERE w.c_id = $course_id AND post_group_id = $groupIid";
1270
        $subdirs_query = "AND parent_id = 0";
1271
    } else {
1272
        $group_query = " WHERE w.c_id = $course_id AND (post_group_id = '0' or post_group_id is NULL)  ";
1273
        $subdirs_query = "AND parent_id = 0";
1274
    }
1275
1276
    $active_condition = ' AND active IN (1, 0)';
1277
1278
    if ($getCount) {
1279
        $select = "SELECT count(w.id) as count ";
1280
    } else {
1281
        $select = "SELECT w.*, a.expires_on, expires_on, ends_on, enable_qualification ";
1282
    }
1283
1284
    $sql = "$select
1285
            FROM $workTable w
1286
            LEFT JOIN $workTableAssignment a
1287
            ON (a.publication_id = w.id AND a.c_id = w.c_id)
1288
                $group_query
1289
                $subdirs_query
1290
                $active_condition
1291
                $condition_session
1292
                $where_condition
1293
            ";
1294
1295
    $sql .= " ORDER BY $column $direction ";
1296
1297
    if (!empty($start) && !empty($limit)) {
1298
        $sql .= " LIMIT $start, $limit";
1299
    }
1300
1301
    $result = Database::query($sql);
1302
1303
    if ($getCount) {
1304
        $row = Database::fetch_array($result);
1305
1306
        return $row['count'];
1307
    }
1308
1309
    $works = [];
1310
    $url = api_get_path(WEB_CODE_PATH).'work/work_list.php?'.api_get_cidreq();
1311
    if ($isDrhOfCourse) {
1312
        $url = api_get_path(WEB_CODE_PATH).'work/work_list_all.php?'.api_get_cidreq();
1313
    }
1314
1315
    $urlOthers = api_get_path(WEB_CODE_PATH).'work/work_list_others.php?'.api_get_cidreq().'&id=';
1316
    while ($work = Database::fetch_array($result, 'ASSOC')) {
1317
        $isSubscribed = userIsSubscribedToWork($userId, $work['id'], $course_id);
1318
        if ($isSubscribed == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
1319
            continue;
1320
        }
1321
1322
        $visibility = api_get_item_visibility($courseInfo, 'work', $work['id'], $session_id);
1323
1324
        if ($visibility != 1) {
1325
            continue;
1326
        }
1327
1328
        $work['type'] = Display::return_icon('work.png');
1329
        $work['expires_on'] = empty($work['expires_on']) ? null : api_get_local_time($work['expires_on']);
1330
1331
        if (empty($work['title'])) {
1332
            $work['title'] = basename($work['url']);
1333
        }
1334
1335
        $whereCondition = " AND u.user_id = ".intval($userId);
1336
1337
        $workList = get_work_user_list(
1338
            0,
1339
            1000,
1340
            null,
1341
            null,
1342
            $work['id'],
1343
            $whereCondition
1344
        );
1345
1346
        $count = getTotalWorkComment($workList, $courseInfo);
1347
        $lastWork = getLastWorkStudentFromParentByUser($userId, $work, $courseInfo);
1348
1349
        if (!is_null($count) && !empty($count)) {
1350
            $urlView = api_get_path(WEB_CODE_PATH).'work/view.php?id='.$lastWork['id'].'&'.api_get_cidreq();
1351
1352
            $feedback = '&nbsp;'.Display::url(
1353
                Display::returnFontAwesomeIcon('comments-o'),
1354
                $urlView,
1355
                ['title' => get_lang('View')]
1356
            );
1357
1358
            $work['feedback'] = ' '.Display::label($count.' '.get_lang('Feedback'), 'info').$feedback;
1359
        }
1360
1361
        if (!empty($lastWork)) {
1362
            $work['last_upload'] = (!empty($lastWork['qualification'])) ? $lastWork['qualification_rounded'].' - ' : '';
1363
            $work['last_upload'] .= api_get_local_time($lastWork['sent_date']);
1364
        }
1365
1366
        $work['title'] = Display::url($work['title'], $url.'&id='.$work['id']);
1367
        $work['others'] = Display::url(
1368
            Display::return_icon('group.png', get_lang('Others')),
1369
            $urlOthers.$work['id']
1370
        );
1371
        $works[] = $work;
1372
    }
1373
1374
    return $works;
1375
}
1376
1377
/**
1378
 * @param int    $start
1379
 * @param int    $limit
1380
 * @param string $column
1381
 * @param string $direction
1382
 * @param string $where_condition
1383
 * @param bool   $getCount
1384
 *
1385
 * @return array
1386
 */
1387
function getWorkListTeacher(
1388
    $start,
1389
    $limit,
1390
    $column,
1391
    $direction,
1392
    $where_condition,
1393
    $getCount = false
1394
) {
1395
    $workTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
1396
    $workTableAssignment = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
1397
1398
    $courseInfo = api_get_course_info();
1399
    $course_id = api_get_course_int_id();
1400
    $session_id = api_get_session_id();
1401
    $condition_session = api_get_session_condition($session_id);
1402
    $group_id = api_get_group_id();
1403
    $groupIid = 0;
1404
    if ($group_id) {
1405
        $groupInfo = GroupManager::get_group_properties($group_id);
1406
        $groupIid = $groupInfo['iid'];
1407
    }
1408
    $groupIid = (int) $groupIid;
1409
1410
    $is_allowed_to_edit = api_is_allowed_to_edit() || api_is_coach();
1411
    if (!in_array($direction, ['asc', 'desc'])) {
1412
        $direction = 'desc';
1413
    }
1414
    if (!empty($where_condition)) {
1415
        $where_condition = ' AND '.$where_condition;
1416
    }
1417
1418
    $column = !empty($column) ? Database::escape_string($column) : 'sent_date';
1419
    $start = intval($start);
1420
    $limit = intval($limit);
1421
    $works = [];
1422
1423
    // Get list from database
1424
    if ($is_allowed_to_edit) {
1425
        $active_condition = ' active IN (0, 1)';
1426
        if ($getCount) {
1427
            $select = " SELECT count(w.id) as count";
1428
        } else {
1429
            $select = " SELECT w.*, a.expires_on, expires_on, ends_on, enable_qualification ";
1430
        }
1431
        $sql = " $select
1432
                FROM $workTable w
1433
                LEFT JOIN $workTableAssignment a
1434
                ON (a.publication_id = w.id AND a.c_id = w.c_id)
1435
                WHERE
1436
                    w.c_id = $course_id
1437
                    $condition_session AND
1438
                    $active_condition AND
1439
                    parent_id = 0 AND
1440
                    post_group_id = $groupIid
1441
                    $where_condition
1442
                ORDER BY $column $direction
1443
                LIMIT $start, $limit";
1444
1445
        $result = Database::query($sql);
1446
1447
        if ($getCount) {
1448
            $row = Database::fetch_array($result);
1449
1450
            return $row['count'];
1451
        }
1452
1453
        $url = api_get_path(WEB_CODE_PATH).'work/work_list_all.php?'.api_get_cidreq();
1454
        while ($work = Database::fetch_array($result, 'ASSOC')) {
1455
            $workId = $work['id'];
1456
            $work['type'] = Display::return_icon('work.png');
1457
            $work['expires_on'] = empty($work['expires_on']) ? null : api_get_local_time($work['expires_on']);
1458
1459
            $countUniqueAttempts = getUniqueStudentAttemptsTotal(
1460
                $workId,
1461
                $group_id,
1462
                $course_id,
1463
                $session_id
1464
            );
1465
1466
            $totalUsers = getStudentSubscribedToWork(
1467
                $workId,
1468
                $course_id,
1469
                $group_id,
1470
                $session_id,
1471
                true
1472
            );
1473
1474
            $work['amount'] = Display::label(
1475
                $countUniqueAttempts.'/'.
1476
                $totalUsers,
0 ignored issues
show
Bug introduced by
Are you sure $totalUsers of type integer|array can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1476
                /** @scrutinizer ignore-type */ $totalUsers,
Loading history...
1477
                'success'
1478
            );
1479
1480
            $visibility = api_get_item_visibility($courseInfo, 'work', $workId, $session_id);
1481
1482
            if ($visibility == 1) {
1483
                $icon = 'visible.png';
1484
                $text = get_lang('Visible');
1485
                $action = 'invisible';
1486
                $class = '';
1487
            } else {
1488
                $icon = 'invisible.png';
1489
                $text = get_lang('Invisible');
1490
                $action = 'visible';
1491
                $class = 'muted';
1492
            }
1493
1494
            $visibilityLink = Display::url(
1495
                Display::return_icon($icon, $text, [], ICON_SIZE_SMALL),
1496
                api_get_path(WEB_CODE_PATH).'work/work.php?id='.$workId.'&action='.$action.'&'.api_get_cidreq()
1497
            );
1498
1499
            if (empty($work['title'])) {
1500
                $work['title'] = basename($work['url']);
1501
            }
1502
            $work['title'] = Display::url($work['title'], $url.'&id='.$workId, ['class' => $class]);
1503
            $work['title'] .= ' '.Display::label(get_count_work($work['id']), 'success');
1504
            $work['sent_date'] = api_get_local_time($work['sent_date']);
1505
1506
            $editLink = Display::url(
1507
                Display::return_icon('edit.png', get_lang('Edit'), [], ICON_SIZE_SMALL),
1508
                api_get_path(WEB_CODE_PATH).'work/edit_work.php?id='.$workId.'&'.api_get_cidreq()
1509
            );
1510
1511
            $correctionLink = '&nbsp;'.Display::url(
1512
                Display::return_icon('upload_package.png', get_lang('UploadCorrections'), '', ICON_SIZE_SMALL),
1513
                api_get_path(WEB_CODE_PATH).'work/upload_corrections.php?'.api_get_cidreq().'&id='.$workId
1514
            ).'&nbsp;';
1515
1516
            if ($countUniqueAttempts > 0) {
1517
                $downloadLink = Display::url(
1518
                    Display::return_icon(
1519
                        'save_pack.png',
1520
                        get_lang('Save'),
1521
                        [],
1522
                        ICON_SIZE_SMALL
1523
                    ),
1524
                    api_get_path(WEB_CODE_PATH).'work/downloadfolder.inc.php?id='.$workId.'&'.api_get_cidreq()
1525
                );
1526
            } else {
1527
                $downloadLink = Display::url(
1528
                    Display::return_icon(
1529
                        'save_pack_na.png',
1530
                        get_lang('Save'),
1531
                        [],
1532
                        ICON_SIZE_SMALL
1533
                    ),
1534
                    '#'
1535
                );
1536
            }
1537
            // Remove Delete Work Button from action List
1538
            // Because removeXSS "removes" the onClick JS Event to do the action (See model.ajax.php - Line 1639)
1539
            // But still can use the another jqgrid button to remove works (trash icon)
1540
            //
1541
            // $deleteUrl = api_get_path(WEB_CODE_PATH).'work/work.php?id='.$workId.'&action=delete_dir&'.api_get_cidreq();
1542
            // $deleteLink = '<a href="#" onclick="showConfirmationPopup(this, \'' . $deleteUrl . '\' ) " >' .
1543
            //     Display::return_icon(
1544
            //         'delete.png',
1545
            //         get_lang('Delete'),
1546
            //         [],
1547
            //         ICON_SIZE_SMALL
1548
            //     ) . '</a>';
1549
1550
            if (!api_is_allowed_to_edit()) {
1551
                // $deleteLink = null;
1552
                $editLink = null;
1553
            }
1554
            $work['actions'] = $visibilityLink.$correctionLink.$downloadLink.$editLink;
1555
            $works[] = $work;
1556
        }
1557
    }
1558
1559
    return $works;
1560
}
1561
1562
/**
1563
 * @param int    $start
1564
 * @param int    $limit
1565
 * @param string $column
1566
 * @param string $direction
1567
 * @param int    $workId
1568
 * @param int    $studentId
1569
 * @param string $whereCondition
1570
 * @param bool   $getCount
1571
 *
1572
 * @return array
1573
 */
1574
function get_work_user_list_from_documents(
1575
    $start,
1576
    $limit,
1577
    $column,
1578
    $direction,
1579
    $workId,
1580
    $studentId = null,
1581
    $whereCondition = '',
1582
    $getCount = false
1583
) {
1584
    if ($getCount) {
1585
        $select1 = " SELECT count(u.user_id) as count ";
1586
        $select2 = " SELECT count(u.user_id) as count ";
1587
    } else {
1588
        $select1 = " SELECT DISTINCT 
1589
                        u.firstname, 
1590
                        u.lastname, 
1591
                        u.user_id, 
1592
                        w.title,
1593
                        w.parent_id, 
1594
                        w.document_id document_id, 
1595
                        w.id, qualification, 
1596
                        qualificator_id, 
1597
                        w.sent_date,
1598
                        w.contains_file,
1599
                        w.url
1600
                    ";
1601
        $select2 = " SELECT DISTINCT 
1602
                        u.firstname, u.lastname,
1603
                        u.user_id, 
1604
                        d.title, 
1605
                        w.parent_id, 
1606
                        d.id document_id, 
1607
                        0, 
1608
                        0, 
1609
                        0,
1610
                        w.sent_date,
1611
                        w.contains_file,
1612
                        w.url                        
1613
                    ";
1614
    }
1615
1616
    $documentTable = Database::get_course_table(TABLE_DOCUMENT);
1617
    $workTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
1618
    $workRelDocument = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
1619
    $userTable = Database::get_main_table(TABLE_MAIN_USER);
1620
1621
    $courseId = api_get_course_int_id();
1622
    $sessionId = api_get_session_id();
1623
1624
    if (empty($studentId)) {
1625
        $studentId = api_get_user_id();
1626
    }
1627
    $studentId = intval($studentId);
1628
    $workId = intval($workId);
1629
1630
    $userCondition = " AND u.user_id = $studentId ";
1631
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'w.session_id');
1632
    $workCondition = " AND w_rel.work_id = $workId";
1633
    $workParentCondition = " AND w.parent_id = $workId";
1634
1635
    $sql = "(
1636
                $select1 FROM $userTable u
1637
                INNER JOIN $workTable w
1638
                ON (u.user_id = w.user_id AND w.active IN (0, 1) AND w.filetype = 'file')
1639
                WHERE
1640
                    w.c_id = $courseId
1641
                    $userCondition
1642
                    $sessionCondition
1643
                    $whereCondition
1644
                    $workParentCondition
1645
            ) UNION (
1646
                $select2 FROM $workTable w
1647
                INNER JOIN $workRelDocument w_rel
1648
                ON (w_rel.work_id = w.id AND w.active IN (0, 1) AND w_rel.c_id = w.c_id)
1649
                INNER JOIN $documentTable d
1650
                ON (w_rel.document_id = d.id AND d.c_id = w.c_id)
1651
                INNER JOIN $userTable u ON (u.user_id = $studentId)
1652
                WHERE
1653
                    w.c_id = $courseId
1654
                    $workCondition
1655
                    $sessionCondition AND
1656
                    d.id NOT IN (
1657
                        SELECT w.document_id id
1658
                        FROM $workTable w
1659
                        WHERE
1660
                            user_id = $studentId AND
1661
                            c_id = $courseId AND
1662
                            filetype = 'file' AND
1663
                            active IN (0, 1)
1664
                            $sessionCondition
1665
                            $workParentCondition
1666
                    )
1667
            )";
1668
1669
    $start = intval($start);
1670
    $limit = intval($limit);
1671
1672
    $direction = in_array(strtolower($direction), ['desc', 'asc']) ? $direction : 'desc';
1673
    $column = Database::escape_string($column);
1674
1675
    if ($getCount) {
1676
        $result = Database::query($sql);
1677
        $result = Database::fetch_array($result);
1678
1679
        return $result['count'];
1680
    }
1681
1682
    $sql .= " ORDER BY $column $direction";
1683
    $sql .= " LIMIT $start, $limit";
1684
1685
    $result = Database::query($sql);
1686
1687
    $currentUserId = api_get_user_id();
1688
    $work_data = get_work_data_by_id($workId);
1689
    $qualificationExists = false;
1690
1691
    if (!empty($work_data['qualification']) && intval($work_data['qualification']) > 0) {
1692
        $qualificationExists = true;
1693
    }
1694
1695
    $urlAdd = api_get_path(WEB_CODE_PATH).'work/upload_from_template.php?'.api_get_cidreq();
1696
    $urlEdit = api_get_path(WEB_CODE_PATH).'work/edit.php?'.api_get_cidreq();
1697
    $urlDelete = api_get_path(WEB_CODE_PATH).'work/work_list.php?action=delete&'.api_get_cidreq();
1698
    $urlView = api_get_path(WEB_CODE_PATH).'work/view.php?'.api_get_cidreq();
1699
    $urlDownload = api_get_path(WEB_CODE_PATH).'work/download.php?'.api_get_cidreq();
1700
1701
    $editIcon = Display::return_icon('edit.png', get_lang('Edit'));
1702
    $addIcon = Display::return_icon('add.png', get_lang('Add'));
1703
    $deleteIcon = Display::return_icon('delete.png', get_lang('Delete'));
1704
    $viewIcon = Display::return_icon('default.png', get_lang('View'));
1705
    $saveIcon = Display::return_icon(
1706
        'save.png',
1707
        get_lang('Save'),
1708
        [],
1709
        ICON_SIZE_SMALL
1710
    );
1711
    $allowEdition = api_get_course_setting('student_delete_own_publication') == 1;
1712
1713
    $workList = [];
1714
    while ($row = Database::fetch_array($result, 'ASSOC')) {
1715
        $userId = $row['user_id'];
1716
        $documentId = $row['document_id'];
1717
        $itemId = $row['id'];
1718
        $addLinkShowed = false;
1719
1720
        if (empty($documentId)) {
1721
            $url = $urlEdit.'&item_id='.$row['id'].'&id='.$workId;
1722
            $editLink = Display::url($editIcon, $url);
1723
            if ($allowEdition != 1) {
1724
                $editLink = null;
1725
            }
1726
        } else {
1727
            $documentToWork = getDocumentToWorkPerUser($documentId, $workId, $courseId, $sessionId, $userId);
1728
1729
            if (empty($documentToWork)) {
1730
                $url = $urlAdd.'&document_id='.$documentId.'&id='.$workId;
1731
                $editLink = Display::url($addIcon, $url);
1732
                $addLinkShowed = true;
1733
            } else {
1734
                $row['title'] = $documentToWork['title'];
1735
                $row['sent_date'] = $documentToWork['sent_date'];
1736
                $newWorkId = $documentToWork['id'];
1737
                $url = $urlEdit.'&item_id='.$newWorkId.'&id='.$workId;
1738
                $editLink = Display::url($editIcon, $url);
1739
1740
                if ($allowEdition != 1) {
1741
                    $editLink = '';
1742
                }
1743
            }
1744
        }
1745
1746
        $downloadLink = '';
1747
        // If URL is present then there's a file to download keep BC.
1748
        if ($row['contains_file'] || !empty($row['url'])) {
1749
            $downloadLink = Display::url($saveIcon, $urlDownload.'&id='.$row['id']).'&nbsp;';
1750
        }
1751
1752
        $viewLink = '';
1753
        if (!empty($itemId)) {
1754
            $viewLink = Display::url($viewIcon, $urlView.'&id='.$itemId);
1755
        }
1756
1757
        $deleteLink = '';
1758
        if ($allowEdition == 1 && !empty($itemId)) {
1759
            $deleteLink = Display::url($deleteIcon, $urlDelete.'&item_id='.$itemId.'&id='.$workId);
1760
        }
1761
1762
        $row['type'] = null;
1763
1764
        if ($qualificationExists) {
1765
            if (empty($row['qualificator_id'])) {
1766
                $status = Display::label(get_lang('NotRevised'), 'warning');
1767
            } else {
1768
                $status = Display::label(get_lang('Revised'), 'success');
1769
            }
1770
            $row['qualificator_id'] = $status;
1771
        }
1772
1773
        if (!empty($row['qualification'])) {
1774
            $row['qualification'] = Display::label($row['qualification'], 'info');
1775
        }
1776
1777
        if (!empty($row['sent_date'])) {
1778
            $row['sent_date'] = Display::dateToStringAgoAndLongDate($row['sent_date']);
1779
        }
1780
1781
        if ($userId == $currentUserId) {
1782
            $row['actions'] = $downloadLink.$viewLink.$editLink.$deleteLink;
1783
        }
1784
1785
        if ($addLinkShowed) {
1786
            $row['qualification'] = '';
1787
            $row['qualificator_id'] = '';
1788
        }
1789
1790
        $workList[] = $row;
1791
    }
1792
1793
    return $workList;
1794
}
1795
1796
/**
1797
 * @param int    $start
1798
 * @param int    $limit
1799
 * @param int    $column
1800
 * @param string $direction
1801
 * @param int    $work_id
1802
 * @param array  $where_condition
1803
 * @param int    $studentId
1804
 * @param bool   $getCount
1805
 * @param int    $courseId
1806
 * @param int    $sessionId
1807
 *
1808
 * @return array
1809
 */
1810
function get_work_user_list(
1811
    $start,
1812
    $limit,
1813
    $column,
1814
    $direction,
1815
    $work_id,
1816
    $where_condition = null,
1817
    $studentId = null,
1818
    $getCount = false,
1819
    $courseId = 0,
1820
    $sessionId = 0
1821
) {
1822
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
1823
    $user_table = Database::get_main_table(TABLE_MAIN_USER);
1824
1825
    $session_id = $sessionId ? $sessionId : api_get_session_id();
1826
    $group_id = api_get_group_id();
1827
    $course_info = api_get_course_info();
1828
    $course_info = empty($course_info) ? api_get_course_info_by_id($courseId) : $course_info;
1829
    $course_id = isset($course_info['real_id']) ? $course_info['real_id'] : $courseId;
1830
1831
    $work_id = intval($work_id);
1832
    $column = !empty($column) ? Database::escape_string($column) : 'sent_date';
1833
    $start = intval($start);
1834
    $limit = intval($limit);
1835
1836
    if (!in_array($direction, ['asc', 'desc'])) {
1837
        $direction = 'desc';
1838
    }
1839
1840
    $work_data = get_work_data_by_id($work_id, $courseId, $sessionId);
1841
    $is_allowed_to_edit = api_is_allowed_to_edit() || api_is_coach();
1842
    $condition_session = api_get_session_condition(
1843
        $session_id,
1844
        true,
1845
        false,
1846
        'work.session_id'
1847
    );
1848
    $locked = api_resource_is_locked_by_gradebook(
1849
        $work_id,
1850
        LINK_STUDENTPUBLICATION,
1851
        $course_info['code']
1852
    );
1853
1854
    $isDrhOfCourse = CourseManager::isUserSubscribedInCourseAsDrh(
1855
        api_get_user_id(),
1856
        $course_info
1857
    );
1858
1859
    $groupIid = 0;
1860
    if ($group_id) {
1861
        $groupInfo = GroupManager::get_group_properties($group_id);
1862
        $groupIid = $groupInfo['iid'];
1863
    }
1864
1865
    if (!empty($work_data)) {
1866
        if (!empty($group_id)) {
1867
            $extra_conditions = " work.post_group_id = '".intval($groupIid)."' ";
1868
        // set to select only messages posted by the user's group
1869
        } else {
1870
            $extra_conditions = " (work.post_group_id = '0' OR work.post_group_id is NULL) ";
1871
        }
1872
1873
        if ($is_allowed_to_edit || $isDrhOfCourse) {
1874
            $extra_conditions .= ' AND work.active IN (0, 1) ';
1875
        } else {
1876
            if (isset($course_info['show_score']) &&
1877
                $course_info['show_score'] == 1
1878
            ) {
1879
                $extra_conditions .= " AND (u.user_id = ".api_get_user_id()." AND work.active IN (0, 1)) ";
1880
            } else {
1881
                $extra_conditions .= ' AND work.active IN (0, 1) ';
1882
            }
1883
        }
1884
1885
        $extra_conditions .= " AND parent_id  = ".$work_id." ";
1886
1887
        $select = 'SELECT DISTINCT
1888
                        u.user_id,
1889
                        work.id as id,
1890
                        title as title,
1891
                        description,
1892
                        url,
1893
                        sent_date,
1894
                        contains_file,
1895
                        has_properties,
1896
                        view_properties,
1897
                        qualification,
1898
                        weight,
1899
                        allow_text_assignment,
1900
                        u.firstname,
1901
                        u.lastname,
1902
                        u.username,
1903
                        parent_id,
1904
                        accepted,
1905
                        qualificator_id,
1906
                        url_correction,
1907
                        title_correction
1908
                        ';
1909
        if ($getCount) {
1910
            $select = "SELECT DISTINCT count(u.user_id) as count ";
1911
        }
1912
1913
        $work_assignment = get_work_assignment_by_id($work_id, $courseId);
1914
1915
        if (!empty($studentId)) {
1916
            $where_condition .= " AND u.user_id = ".intval($studentId);
1917
        }
1918
1919
        $sql = " $select
1920
                FROM $work_table work 
1921
                INNER JOIN $user_table u  
1922
                ON (work.user_id = u.user_id)
1923
                WHERE
1924
                    work.c_id = $course_id AND
1925
                    $extra_conditions 
1926
                    $where_condition 
1927
                    $condition_session
1928
                    AND u.status != ".INVITEE."
1929
                ORDER BY $column $direction";
1930
1931
        if (!empty($start) && !empty($limit)) {
1932
            $sql .= " LIMIT $start, $limit";
1933
        }
1934
        $result = Database::query($sql);
1935
        $works = [];
1936
1937
        if ($getCount) {
1938
            $work = Database::fetch_array($result, 'ASSOC');
1939
1940
            return $work['count'];
1941
        }
1942
1943
        $url = api_get_path(WEB_CODE_PATH).'work/';
1944
        $unoconv = api_get_configuration_value('unoconv.binaries');
1945
        $loadingText = addslashes(get_lang('Loading'));
1946
        $uploadedText = addslashes(get_lang('Uploaded'));
1947
        $failsUploadText = addslashes(get_lang('UplNoFileUploaded'));
1948
        $failsUploadIcon = Display::return_icon(
1949
            'closed-circle.png',
1950
            '',
1951
            [],
1952
            ICON_SIZE_TINY
1953
        );
1954
        $saveIcon = Display::return_icon(
1955
            'save.png',
1956
            get_lang('Save'),
1957
            [],
1958
            ICON_SIZE_SMALL
1959
        );
1960
1961
        $correctionIcon = Display::return_icon(
1962
            'check-circle.png',
1963
            get_lang('Correction'),
1964
            null,
1965
            ICON_SIZE_SMALL
1966
        );
1967
1968
        $correctionIconSmall = Display::return_icon(
1969
            'check-circle.png',
1970
            get_lang('Correction'),
1971
            null,
1972
            ICON_SIZE_TINY
1973
        );
1974
1975
        $rateIcon = Display::return_icon(
1976
            'rate_work.png',
1977
            get_lang('CorrectAndRate'),
1978
            [],
1979
            ICON_SIZE_SMALL
1980
        );
1981
1982
        while ($work = Database::fetch_array($result, 'ASSOC')) {
1983
            $item_id = $work['id'];
1984
            // Get the author ID for that document from the item_property table
1985
            $is_author = false;
1986
            $can_read = false;
1987
            $owner_id = $work['user_id'];
1988
1989
            /* Because a bug found when saving items using the api_item_property_update()
1990
               the field $item_property_data['insert_user_id'] is not reliable. */
1991
            if (!$is_allowed_to_edit && $owner_id == api_get_user_id()) {
1992
                $is_author = true;
1993
            }
1994
1995
            if ($course_info['show_score'] == 0) {
1996
                $can_read = true;
1997
            }
1998
1999
            $qualification_exists = false;
2000
            if (!empty($work_data['qualification']) &&
2001
                intval($work_data['qualification']) > 0
2002
            ) {
2003
                $qualification_exists = true;
2004
            }
2005
2006
            $qualification_string = '';
2007
            if ($qualification_exists) {
2008
                if ($work['qualification'] == '') {
2009
                    $qualification_string = Display::label('-');
2010
                } else {
2011
                    $qualification_string = formatWorkScore($work['qualification'], $work_data['qualification']);
2012
                }
2013
            }
2014
2015
            $work['qualification_score'] = $work['qualification'];
2016
            $add_string = '';
2017
            $time_expires = '';
2018
            if (!empty($work_assignment['expires_on'])) {
2019
                $time_expires = api_strtotime(
2020
                    $work_assignment['expires_on'],
2021
                    'UTC'
2022
                );
2023
            }
2024
2025
            if (!empty($work_assignment['expires_on']) &&
2026
                !empty($time_expires) && ($time_expires < api_strtotime($work['sent_date'], 'UTC'))) {
2027
                $add_string = Display::label(get_lang('Expired'), 'important').' - ';
2028
            }
2029
2030
            if (($can_read && $work['accepted'] == '1') ||
2031
                ($is_author && in_array($work['accepted'], ['1', '0'])) ||
2032
                ($is_allowed_to_edit || api_is_drh())
2033
            ) {
2034
                // Firstname, lastname, username
2035
                $work['fullname'] = Display::div(
2036
                    api_get_person_name($work['firstname'], $work['lastname']),
2037
                    ['class' => 'work-name']
2038
                );
2039
                // Title
2040
                $work['title_clean'] = $work['title'];
2041
                $work['title'] = Security::remove_XSS($work['title']);
2042
                if (strlen($work['title']) > 30) {
2043
                    $short_title = substr($work['title'], 0, 27).'...';
2044
                    $work['title'] = Display::span($short_title, ['class' => 'work-title', 'title' => $work['title']]);
2045
                } else {
2046
                    $work['title'] = Display::div($work['title'], ['class' => 'work-title']);
2047
                }
2048
2049
                // Type.
2050
                $work['type'] = DocumentManager::build_document_icon_tag('file', $work['url']);
2051
2052
                // File name.
2053
                $linkToDownload = '';
2054
                // If URL is present then there's a file to download keep BC.
2055
                if ($work['contains_file'] || !empty($work['url'])) {
2056
                    $linkToDownload = '<a href="'.$url.'download.php?id='.$item_id.'&'.api_get_cidreq().'">'.$saveIcon.'</a> ';
2057
                }
2058
2059
                $feedback = '';
2060
                $count = getWorkCommentCount($item_id, $course_info);
2061
                if (!is_null($count) && !empty($count)) {
2062
                    if ($qualification_exists) {
2063
                        $feedback .= ' ';
2064
                    }
2065
                    $feedback .= '<a href="'.$url.'view.php?'.api_get_cidreq().'&id='.$item_id.'" title="'.get_lang('View').'">'.
2066
                    $count.' '.Display::returnFontAwesomeIcon('comments-o').'</a> ';
2067
                }
2068
2069
                $correction = '';
2070
                $hasCorrection = '';
2071
                if (!empty($work['url_correction'])) {
2072
                    $hasCorrection = Display::url(
2073
                        $correctionIcon,
2074
                        api_get_path(WEB_CODE_PATH).'work/download.php?id='.$item_id.'&'.api_get_cidreq().'&correction=1'
2075
                    );
2076
                }
2077
2078
                if ($qualification_exists) {
2079
                    $work['qualification'] = $qualification_string.$feedback;
2080
                } else {
2081
                    $work['qualification'] = $qualification_string.$feedback.$hasCorrection;
2082
                }
2083
2084
                $work['qualification_only'] = $qualification_string;
2085
2086
                // Date.
2087
                $work_date = api_get_local_time($work['sent_date']);
2088
                $date = date_to_str_ago($work['sent_date']).' '.$work_date;
2089
                $work['formatted_date'] = $work_date.' '.$add_string;
2090
                $work['sent_date_from_db'] = $work['sent_date'];
2091
                $work['sent_date'] = '<div class="work-date" title="'.$date.'">'.
2092
                    $add_string.' '.Display::dateToStringAgoAndLongDate($work['sent_date']).'</div>';
2093
                $work['status'] = $hasCorrection;
2094
                $work['has_correction'] = $hasCorrection;
2095
2096
                // Actions.
2097
                $action = '';
2098
                if (api_is_allowed_to_edit()) {
2099
                    $action .= '<a 
2100
                        href="'.$url.'view.php?'.api_get_cidreq().'&id='.$item_id.'" 
2101
                        title="'.get_lang('View').'">'.$rateIcon.'</a> ';
2102
2103
                    if ($unoconv && empty($work['contains_file'])) {
2104
                        $action .= '<a f
2105
                            href="'.$url.'work_list_all.php?'.api_get_cidreq().'&id='.$work_id.'&action=export_to_doc&item_id='.$item_id.'" 
2106
                            title="'.get_lang('ExportToDoc').'" >'.
2107
                            Display::return_icon('export_doc.png', get_lang('ExportToDoc'), [], ICON_SIZE_SMALL).'</a> ';
2108
                    }
2109
2110
                    $alreadyUploaded = '';
2111
                    if (!empty($work['url_correction'])) {
2112
                        $alreadyUploaded = '<br />'.$work['title_correction'].' '.$correctionIconSmall;
2113
                    }
2114
2115
                    $correction = '
2116
                        <form
2117
                        id="file_upload_'.$item_id.'"
2118
                        class="work_correction_file_upload file_upload_small fileinput-button"
2119
                        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"
2120
                        >
2121
                        <div id="progress_'.$item_id.'" class="text-center button-load">
2122
                            '.addslashes(get_lang('ClickOrDropOneFileHere')).'
2123
                            '.Display::return_icon('upload_file.png', get_lang('Correction'), [], ICON_SIZE_TINY).'
2124
                            '.$alreadyUploaded.'
2125
                        </div>
2126
                        <input id="file_'.$item_id.'" type="file" name="file" class="" multiple>
2127
                        </form>
2128
                    ';
2129
2130
                    $correction .= "<script>
2131
                    $(document).ready(function() {
2132
                        $('.work_correction_file_upload').each(function () {
2133
                            $(this).fileupload({
2134
                                dropZone: $(this)
2135
                            });
2136
                        });
2137
                        $('#file_upload_".$item_id."').fileupload({
2138
                            add: function (e, data) {
2139
                                $('#progress_$item_id').html();
2140
                                //$('#file_$item_id').remove();
2141
                                data.context = $('#progress_$item_id').html('$loadingText <br /> <em class=\"fa fa-spinner fa-pulse fa-fw\"></em>');
2142
                                data.submit();
2143
                                $(this).removeClass('hover');
2144
                            },
2145
                            dragover: function (e, data) {
2146
                                $(this).addClass('hover');
2147
                            },
2148
                            done: function (e, data) {
2149
                                if (data._response.result.name) {
2150
                                    $('#progress_$item_id').html('$uploadedText '+data._response.result.result+'<br />'+data._response.result.name);
2151
                                } else {
2152
                                    $('#progress_$item_id').html('$failsUploadText $failsUploadIcon');
2153
                                }
2154
                                $(this).removeClass('hover');
2155
                            }
2156
                        });
2157
                        $('#file_upload_".$item_id."').on('dragleave', function (e) {
2158
                            // dragleave callback implementation
2159
                            $(this).removeClass('hover');
2160
                        });
2161
                    });
2162
                    </script>";
2163
2164
                    if ($locked) {
2165
                        if ($qualification_exists) {
2166
                            $action .= Display::return_icon(
2167
                                'edit_na.png',
2168
                                get_lang('CorrectAndRate'),
2169
                                [],
2170
                                ICON_SIZE_SMALL
2171
                            );
2172
                        } else {
2173
                            $action .= Display::return_icon('edit_na.png', get_lang('Comment'), [], ICON_SIZE_SMALL);
2174
                        }
2175
                    } else {
2176
                        if ($qualification_exists) {
2177
                            $action .= '<a href="'.$url.'edit.php?'.api_get_cidreq().'&item_id='.$item_id.'&id='.$work['parent_id'].'" title="'.get_lang('Edit').'"  >'.
2178
                                Display::return_icon('edit.png', get_lang('Edit'), [], ICON_SIZE_SMALL).'</a>';
2179
                        } else {
2180
                            $action .= '<a href="'.$url.'edit.php?'.api_get_cidreq().'&item_id='.$item_id.'&id='.$work['parent_id'].'" title="'.get_lang('Modify').'">'.
2181
                                Display::return_icon('edit.png', get_lang('Edit'), [], ICON_SIZE_SMALL).'</a>';
2182
                        }
2183
                    }
2184
2185
                    if ($work['contains_file']) {
2186
                        if ($locked) {
2187
                            $action .= Display::return_icon(
2188
                                'move_na.png',
2189
                                get_lang('Move'),
2190
                                [],
2191
                                ICON_SIZE_SMALL
2192
                            );
2193
                        } else {
2194
                            $action .= '<a href="'.$url.'work.php?'.api_get_cidreq().'&action=move&item_id='.$item_id.'&id='.$work['parent_id'].'" title="'.get_lang('Move').'">'.
2195
                                Display::return_icon('move.png', get_lang('Move'), [], ICON_SIZE_SMALL).'</a>';
2196
                        }
2197
                    }
2198
2199
                    if ($work['accepted'] == '1') {
2200
                        $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').'" >'.
2201
                            Display::return_icon('visible.png', get_lang('Invisible'), [], ICON_SIZE_SMALL).'</a>';
2202
                    } else {
2203
                        $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').'" >'.
2204
                            Display::return_icon('invisible.png', get_lang('Visible'), [], ICON_SIZE_SMALL).'</a> ';
2205
                    }
2206
2207
                    if ($locked) {
2208
                        $action .= Display::return_icon('delete_na.png', get_lang('Delete'), '', ICON_SIZE_SMALL);
2209
                    } else {
2210
                        $action .= '<a href="'.$url.'work_list_all.php?'.api_get_cidreq().'&id='.$work_id.'&action=delete&item_id='.$item_id.'" onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES))."'".')) return false;" title="'.get_lang('Delete').'" >'.
2211
                            Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL).'</a>';
2212
                    }
2213
                } elseif ($is_author && (empty($work['qualificator_id']) || $work['qualificator_id'] == 0)) {
2214
                    $action .= '<a href="'.$url.'view.php?'.api_get_cidreq().'&id='.$item_id.'" title="'.get_lang('View').'">'.
2215
                        Display::return_icon('default.png', get_lang('View'), [], ICON_SIZE_SMALL).'</a>';
2216
2217
                    if (api_get_course_setting('student_delete_own_publication') == 1) {
2218
                        if (api_is_allowed_to_session_edit(false, true)) {
2219
                            $action .= '<a href="'.$url.'edit.php?'.api_get_cidreq().'&item_id='.$item_id.'&id='.$work['parent_id'].'" title="'.get_lang('Modify').'">'.
2220
                                Display::return_icon('edit.png', get_lang('Comment'), [], ICON_SIZE_SMALL).'</a>';
2221
                        }
2222
                        $action .= ' <a href="'.$url.'work_list.php?'.api_get_cidreq().'&action=delete&item_id='.$item_id.'&id='.$work['parent_id'].'" onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang('ConfirmYourChoice'), ENT_QUOTES))."'".')) return false;" title="'.get_lang('Delete').'"  >'.
2223
                            Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL).'</a>';
2224
                    }
2225
                } else {
2226
                    $action .= '<a href="'.$url.'view.php?'.api_get_cidreq().'&id='.$item_id.'" title="'.get_lang('View').'">'.
2227
                        Display::return_icon('default.png', get_lang('View'), [], ICON_SIZE_SMALL).'</a>';
2228
                }
2229
2230
                // Status.
2231
                if (empty($work['qualificator_id'])) {
2232
                    $qualificator_id = Display::label(get_lang('NotRevised'), 'warning');
2233
                } else {
2234
                    $qualificator_id = Display::label(get_lang('Revised'), 'success');
2235
                }
2236
                $work['qualificator_id'] = $qualificator_id.' '.$hasCorrection;
2237
                $work['actions'] = '<div class="work-action">'.$linkToDownload.$action.'</div>';
2238
                $work['correction'] = $correction;
2239
                $works[] = $work;
2240
            }
2241
        }
2242
2243
        return $works;
2244
    }
2245
}
2246
2247
/**
2248
 * Send reminder to users who have not given the task.
2249
 *
2250
 * @param int
2251
 *
2252
 * @return array
2253
 *
2254
 * @author cvargas [email protected] cfasanando, [email protected]
2255
 */
2256
function send_reminder_users_without_publication($task_data)
2257
{
2258
    $_course = api_get_course_info();
2259
    $task_id = $task_data['id'];
2260
    $task_title = !empty($task_data['title']) ? $task_data['title'] : basename($task_data['url']);
2261
    $subject = '['.api_get_setting('siteName').'] ';
2262
2263
    // The body can be as long as you wish, and any combination of text and variables
2264
    $content = get_lang('ReminderToSubmitPendingTask')."\n".get_lang('CourseName').' : '.$_course['name']."\n";
2265
    $content .= get_lang('WorkName').' : '.$task_title."\n";
2266
    $list_users = get_list_users_without_publication($task_id);
2267
    $mails_sent_to = [];
2268
    foreach ($list_users as $user) {
2269
        $name_user = api_get_person_name($user[1], $user[0], null, PERSON_NAME_EMAIL_ADDRESS);
2270
        $dear_line = get_lang('Dear')." ".api_get_person_name($user[1], $user[0]).", \n\n";
2271
        $body = $dear_line.$content;
2272
        MessageManager::send_message($user[3], $subject, $body);
2273
        $mails_sent_to[] = $name_user;
2274
    }
2275
2276
    return $mails_sent_to;
2277
}
2278
2279
/**
2280
 * @param int $workId    The work ID
2281
 * @param int $courseId  The course ID
2282
 * @param int $sessionId Optional. The session ID
2283
 */
2284
function sendEmailToDrhOnHomeworkCreation($workId, $courseId, $sessionId = 0)
2285
{
2286
    $courseInfo = api_get_course_info_by_id($courseId);
2287
    $assignment = get_work_assignment_by_id($workId, $courseId);
2288
    $work = get_work_data_by_id($workId, $courseId, $sessionId);
2289
    $workInfo = array_merge($assignment, $work);
2290
2291
    if (empty($sessionId)) {
2292
        $students = CourseManager::get_student_list_from_course_code($courseInfo['code']);
2293
    } else {
2294
        $students = CourseManager::get_student_list_from_course_code($courseInfo['code'], true, $sessionId);
2295
    }
2296
2297
    $bodyView = new Template(null, false, false, false, false, false);
2298
2299
    foreach ($students as $student) {
2300
        $studentInfo = api_get_user_info($student['user_id']);
2301
        if (empty($studentInfo)) {
2302
            continue;
2303
        }
2304
2305
        $hrms = UserManager::getDrhListFromUser($student['id']);
2306
        foreach ($hrms as $hrm) {
2307
            $hrmName = api_get_person_name($hrm['firstname'], $hrm['lastname'], null, PERSON_NAME_EMAIL_ADDRESS);
2308
2309
            $bodyView->assign('hrm_name', $hrmName);
2310
            $bodyView->assign('student', $studentInfo);
2311
            $bodyView->assign('course', $courseInfo);
2312
            $bodyView->assign('course_link', api_get_course_url($courseInfo['code'], $sessionId));
2313
            $bodyView->assign('work', $workInfo);
2314
2315
            $bodyTemplate = $bodyView->get_template('mail/new_work_alert_hrm.tpl');
2316
2317
            MessageManager::send_message(
2318
                $hrm['id'],
2319
                sprintf(
2320
                    get_lang('StudentXHasBeenAssignedNewWorkInCourseY'),
2321
                    $student['firstname'],
2322
                    $courseInfo['title']
2323
                ),
2324
                $bodyView->fetch($bodyTemplate)
2325
            );
2326
        }
2327
    }
2328
}
2329
2330
/**
2331
 * Sends an email to the students of a course when a homework is created.
2332
 *
2333
 * @param int $workId
2334
 * @param int $courseId
2335
 * @param int $sessionId
2336
 *
2337
 * @author Guillaume Viguier <[email protected]>
2338
 * @author Julio Montoya <[email protected]> Adding session support - 2011
2339
 */
2340
function sendEmailToStudentsOnHomeworkCreation($workId, $courseId, $sessionId = 0)
2341
{
2342
    $courseInfo = api_get_course_info_by_id($courseId);
2343
    $courseCode = $courseInfo['code'];
2344
    // Get the students of the course
2345
    if (empty($sessionId)) {
2346
        $students = CourseManager::get_student_list_from_course_code($courseCode);
2347
    } else {
2348
        $students = CourseManager::get_student_list_from_course_code($courseCode, true, $sessionId);
2349
    }
2350
    $emailsubject = '['.api_get_setting('siteName').'] '.get_lang('HomeworkCreated');
2351
    $currentUser = api_get_user_info(api_get_user_id());
2352
    if (!empty($students)) {
2353
        foreach ($students as $student) {
2354
            $user_info = api_get_user_info($student['user_id']);
2355
            if (!empty($user_info)) {
2356
                $link = api_get_path(WEB_CODE_PATH).'work/work_list.php?'.api_get_cidreq().'&id='.$workId;
2357
                $emailbody = get_lang('Dear')." ".$user_info['complete_name'].",\n\n";
2358
                $emailbody .= get_lang('HomeworkHasBeenCreatedForTheCourse')." ".$courseCode.". "."\n\n".
2359
                    '<a href="'.$link.'">'.get_lang('PleaseCheckHomeworkPage').'</a>';
2360
                $emailbody .= "\n\n".$currentUser['complete_name'];
2361
2362
                $additionalParameters = [
2363
                    'smsType' => SmsPlugin::ASSIGNMENT_BEEN_CREATED_COURSE,
2364
                    'userId' => $student['user_id'],
2365
                    'courseTitle' => $courseCode,
2366
                    'link' => $link,
2367
                ];
2368
2369
                MessageManager::send_message_simple(
2370
                    $student['user_id'],
2371
                    $emailsubject,
2372
                    $emailbody,
2373
                    null,
2374
                    false,
2375
                    false,
2376
                    $additionalParameters,
2377
                    false
2378
                );
2379
            }
2380
        }
2381
    }
2382
}
2383
2384
/**
2385
 * @param string $url
2386
 *
2387
 * @return bool
2388
 */
2389
function is_work_exist_by_url($url)
2390
{
2391
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
2392
    $url = Database::escape_string($url);
2393
    $sql = "SELECT id FROM $table WHERE url='$url'";
2394
    $result = Database::query($sql);
2395
    if (Database::num_rows($result) > 0) {
2396
        $row = Database::fetch_row($result);
2397
        if (empty($row)) {
2398
            return false;
2399
        } else {
2400
            return true;
2401
        }
2402
    } else {
2403
        return false;
2404
    }
2405
}
2406
2407
/**
2408
 * Check if a user is the author of a work document.
2409
 *
2410
 * @param int $itemId
2411
 * @param int $userId
2412
 * @param int $courseId
2413
 * @param int $sessionId
2414
 *
2415
 * @return bool
2416
 */
2417
function user_is_author($itemId, $userId = null, $courseId = 0, $sessionId = 0)
2418
{
2419
    if (empty($itemId)) {
2420
        return false;
2421
    }
2422
2423
    if (empty($userId)) {
2424
        $userId = api_get_user_id();
2425
    }
2426
2427
    $isAuthor = false;
2428
    $is_allowed_to_edit = api_is_allowed_to_edit();
2429
2430
    if ($is_allowed_to_edit) {
2431
        $isAuthor = true;
2432
    } else {
2433
        if (empty($courseId)) {
2434
            $courseId = api_get_course_int_id();
2435
        }
2436
        if (empty($sessionId)) {
2437
            $sessionId = api_get_session_id();
2438
        }
2439
2440
        $data = api_get_item_property_info($courseId, 'work', $itemId, $sessionId);
2441
        if ($data['insert_user_id'] == $userId) {
2442
            $isAuthor = true;
2443
        }
2444
2445
        $workData = get_work_data_by_id($itemId);
2446
        if ($workData['user_id'] == $userId) {
2447
            $isAuthor = true;
2448
        }
2449
    }
2450
2451
    if (!$isAuthor) {
2452
        return false;
2453
    }
2454
2455
    return $isAuthor;
2456
}
2457
2458
/**
2459
 * Get list of users who have not given the task.
2460
 *
2461
 * @param int
2462
 * @param int
2463
 *
2464
 * @return array
2465
 *
2466
 * @author cvargas
2467
 * @author Julio Montoya <[email protected]> Fixing query
2468
 */
2469
function get_list_users_without_publication($task_id, $studentId = 0)
2470
{
2471
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
2472
    $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2473
    $table_user = Database::get_main_table(TABLE_MAIN_USER);
2474
    $session_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2475
2476
    $users = getAllUserToWork($task_id, api_get_course_int_id());
2477
    $users = array_column($users, 'user_id');
2478
2479
    // Condition for the session
2480
    $session_id = api_get_session_id();
2481
    $course_id = api_get_course_int_id();
2482
    $task_id = intval($task_id);
2483
    $sessionCondition = api_get_session_condition($session_id);
2484
2485
    if ($session_id == 0) {
2486
        $sql = "SELECT user_id as id FROM $work_table
2487
                WHERE
2488
                    c_id = $course_id AND
2489
                    parent_id = '$task_id' AND
2490
                    active IN (0, 1)";
2491
    } else {
2492
        $sql = "SELECT user_id as id FROM $work_table
2493
                WHERE
2494
                    c_id = $course_id AND
2495
                    parent_id = '$task_id' $sessionCondition AND
2496
                    active IN (0, 1)";
2497
    }
2498
2499
    $result = Database::query($sql);
2500
    $users_with_tasks = [];
2501
    while ($row = Database::fetch_array($result)) {
2502
        $users_with_tasks[] = $row['id'];
2503
    }
2504
2505
    if ($session_id == 0) {
2506
        $sql_users = "SELECT cu.user_id, u.lastname, u.firstname, u.email
2507
                      FROM $table_course_user AS cu, $table_user AS u
2508
                      WHERE u.status != 1 and cu.c_id='".$course_id."' AND u.user_id = cu.user_id";
2509
    } else {
2510
        $sql_users = "SELECT cu.user_id, u.lastname, u.firstname, u.email
2511
                      FROM $session_course_rel_user AS cu, $table_user AS u
2512
                      WHERE
2513
                        u.status != 1 AND
2514
                        cu.c_id='".$course_id."' AND
2515
                        u.user_id = cu.user_id AND
2516
                        cu.session_id = '".$session_id."'";
2517
    }
2518
2519
    if (!empty($studentId)) {
2520
        $sql_users .= " AND u.user_id = ".intval($studentId);
2521
    }
2522
2523
    $group_id = api_get_group_id();
2524
    $new_group_user_list = [];
2525
2526
    if ($group_id) {
2527
        $groupInfo = GroupManager::get_group_properties($group_id);
2528
        $group_user_list = GroupManager::get_subscribed_users($groupInfo);
2529
        if (!empty($group_user_list)) {
2530
            foreach ($group_user_list as $group_user) {
2531
                $new_group_user_list[] = $group_user['user_id'];
2532
            }
2533
        }
2534
    }
2535
2536
    $result_users = Database::query($sql_users);
2537
    $users_without_tasks = [];
2538
    while ($rowUsers = Database::fetch_array($result_users)) {
2539
        $userId = $rowUsers['user_id'];
2540
        if (in_array($userId, $users_with_tasks)) {
2541
            continue;
2542
        }
2543
2544
        if ($group_id && !in_array($userId, $new_group_user_list)) {
2545
            continue;
2546
        }
2547
2548
        if (!empty($users)) {
2549
            if (!in_array($userId, $users)) {
2550
                continue;
2551
            }
2552
        }
2553
2554
        $row_users = [];
2555
        $row_users[0] = $rowUsers['lastname'];
2556
        $row_users[1] = $rowUsers['firstname'];
2557
        $row_users[2] = Display::encrypted_mailto_link($rowUsers['email']);
2558
        $row_users[3] = $userId;
2559
        $users_without_tasks[] = $row_users;
2560
    }
2561
2562
    return $users_without_tasks;
2563
}
2564
2565
/**
2566
 * Display list of users who have not given the task.
2567
 *
2568
 * @param int task id
2569
 * @param int $studentId
2570
 *
2571
 * @author cvargas [email protected] cfasanando, [email protected]
2572
 * @author Julio Montoya <[email protected]> Fixes
2573
 */
2574
function display_list_users_without_publication($task_id, $studentId = null)
0 ignored issues
show
Unused Code introduced by
The parameter $studentId is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

2574
function display_list_users_without_publication($task_id, /** @scrutinizer ignore-unused */ $studentId = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2575
{
2576
    $origin = api_get_origin();
2577
    $table_header[] = [get_lang('LastName'), true];
0 ignored issues
show
Comprehensibility Best Practice introduced by
$table_header was never initialized. Although not strictly required by PHP, it is generally a good practice to add $table_header = array(); before regardless.
Loading history...
2578
    $table_header[] = [get_lang('FirstName'), true];
2579
    $table_header[] = [get_lang('Email'), true];
2580
2581
    $data = get_list_users_without_publication($task_id);
2582
2583
    $sorting_options = [];
2584
    $sorting_options['column'] = 1;
2585
    $paging_options = [];
2586
    $my_params = [];
2587
2588
    if (isset($_GET['edit_dir'])) {
2589
        $my_params['edit_dir'] = Security::remove_XSS($_GET['edit_dir']);
2590
    }
2591
    if (isset($_GET['list'])) {
2592
        $my_params['list'] = Security::remove_XSS($_GET['list']);
2593
    }
2594
    $my_params['origin'] = $origin;
2595
    $my_params['id'] = intval($_GET['id']);
2596
2597
    //$column_show
2598
    $column_show[] = 1;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$column_show was never initialized. Although not strictly required by PHP, it is generally a good practice to add $column_show = array(); before regardless.
Loading history...
2599
    $column_show[] = 1;
2600
    $column_show[] = 1;
2601
    Display::display_sortable_config_table(
2602
        'work',
2603
        $table_header,
2604
        $data,
2605
        $sorting_options,
2606
        $paging_options,
2607
        $my_params,
2608
        $column_show
2609
    );
2610
}
2611
2612
/**
2613
 * @param int $documentId
2614
 * @param int $workId
2615
 * @param int $courseId
2616
 */
2617
function addDocumentToWork($documentId, $workId, $courseId)
2618
{
2619
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
2620
    $params = [
2621
        'document_id' => $documentId,
2622
        'work_id' => $workId,
2623
        'c_id' => $courseId,
2624
    ];
2625
    Database::insert($table, $params);
2626
}
2627
2628
/**
2629
 * @param int $documentId
2630
 * @param int $workId
2631
 * @param int $courseId
2632
 *
2633
 * @return array
2634
 */
2635
function getDocumentToWork($documentId, $workId, $courseId)
2636
{
2637
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
2638
    $params = [
2639
        'document_id = ? and work_id = ? and c_id = ?' => [$documentId, $workId, $courseId],
2640
    ];
2641
2642
    return Database::select('*', $table, ['where' => $params]);
2643
}
2644
2645
/**
2646
 * @param int $documentId
2647
 * @param int $workId
2648
 * @param int $courseId
2649
 * @param int $sessionId
2650
 * @param int $userId
2651
 * @param int $active
2652
 *
2653
 * @return array
2654
 */
2655
function getDocumentToWorkPerUser($documentId, $workId, $courseId, $sessionId, $userId, $active = 1)
2656
{
2657
    $workRel = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
2658
    $work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
2659
2660
    $documentId = intval($documentId);
2661
    $workId = intval($workId);
2662
    $courseId = intval($courseId);
2663
    $userId = intval($userId);
2664
    $sessionId = intval($sessionId);
2665
    $active = intval($active);
2666
    $sessionCondition = api_get_session_condition($sessionId);
2667
2668
    $sql = "SELECT w.* FROM $work w 
2669
            INNER JOIN $workRel rel 
2670
            ON (w.parent_id = rel.work_id)
2671
            WHERE
2672
                w.document_id = $documentId AND
2673
                w.parent_id = $workId AND
2674
                w.c_id = $courseId
2675
                $sessionCondition AND
2676
                user_id = $userId AND
2677
                active = $active
2678
            ";
2679
2680
    $result = Database::query($sql);
2681
    $workInfo = [];
2682
    if (Database::num_rows($result)) {
2683
        $workInfo = Database::fetch_array($result, 'ASSOC');
2684
    }
2685
2686
    return $workInfo;
2687
}
2688
2689
/**
2690
 * @param int $workId
2691
 * @param int $courseId
2692
 *
2693
 * @return array
2694
 */
2695
function getAllDocumentToWork($workId, $courseId)
2696
{
2697
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
2698
    $params = [
2699
        'work_id = ? and c_id = ?' => [$workId, $courseId],
2700
    ];
2701
2702
    return Database::select('*', $table, ['where' => $params]);
2703
}
2704
2705
/**
2706
 * @param int $documentId
2707
 * @param int $workId
2708
 * @param int $courseId
2709
 */
2710
function deleteDocumentToWork($documentId, $workId, $courseId)
2711
{
2712
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_DOCUMENT);
2713
    $params = [
2714
        'document_id = ? and work_id = ? and c_id = ?' => [$documentId, $workId, $courseId],
2715
    ];
2716
    Database::delete($table, $params);
2717
}
2718
2719
/**
2720
 * @param int $userId
2721
 * @param int $workId
2722
 * @param int $courseId
2723
 */
2724
function addUserToWork($userId, $workId, $courseId)
2725
{
2726
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_USER);
2727
    $params = [
2728
        'user_id' => $userId,
2729
        'work_id' => $workId,
2730
        'c_id' => $courseId,
2731
    ];
2732
    Database::insert($table, $params);
2733
}
2734
2735
/**
2736
 * @param int $userId
2737
 * @param int $workId
2738
 * @param int $courseId
2739
 *
2740
 * @return array
2741
 */
2742
function getUserToWork($userId, $workId, $courseId)
2743
{
2744
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_USER);
2745
    $params = [
2746
        'user_id = ? and work_id = ? and c_id = ?' => [$userId, $workId, $courseId],
2747
    ];
2748
2749
    return Database::select('*', $table, ['where' => $params]);
2750
}
2751
2752
/**
2753
 * @param int  $workId
2754
 * @param int  $courseId
2755
 * @param bool $getCount
2756
 *
2757
 * @return array|int
2758
 */
2759
function getAllUserToWork($workId, $courseId, $getCount = false)
2760
{
2761
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_USER);
2762
    $params = [
2763
        'work_id = ? and c_id = ?' => [$workId, $courseId],
2764
    ];
2765
    if ($getCount) {
2766
        $count = 0;
2767
        $result = Database::select(
2768
            'count(user_id) as count',
2769
            $table,
2770
            ['where' => $params],
2771
            'simple'
2772
        );
2773
        if (!empty($result)) {
2774
            $count = intval($result['count']);
2775
        }
2776
2777
        return $count;
2778
    } else {
2779
        return Database::select('*', $table, ['where' => $params]);
2780
    }
2781
}
2782
2783
/**
2784
 * @param int $userId
2785
 * @param int $workId
2786
 * @param int $courseId
2787
 */
2788
function deleteUserToWork($userId, $workId, $courseId)
2789
{
2790
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_REL_USER);
2791
    $params = [
2792
        'user_id = ? and work_id = ? and c_id = ?' => [$userId, $workId, $courseId],
2793
    ];
2794
    Database::delete($table, $params);
2795
}
2796
2797
/**
2798
 * @param int $userId
2799
 * @param int $workId
2800
 * @param int $courseId
2801
 *
2802
 * @return bool
2803
 */
2804
function userIsSubscribedToWork($userId, $workId, $courseId)
2805
{
2806
    $subscribedUsers = getAllUserToWork($workId, $courseId);
2807
2808
    if (empty($subscribedUsers)) {
2809
        return true;
2810
    } else {
2811
        $subscribedUsersList = [];
2812
        foreach ($subscribedUsers as $item) {
2813
            $subscribedUsersList[] = $item['user_id'];
2814
        }
2815
        if (in_array($userId, $subscribedUsersList)) {
2816
            return true;
2817
        }
2818
    }
2819
2820
    return false;
2821
}
2822
2823
/**
2824
 * Get the list of students that have to submit their work.
2825
 *
2826
 * @param int  $workId    The internal ID of the assignment
2827
 * @param int  $courseId  The course ID
2828
 * @param int  $groupId   The group ID, if any
2829
 * @param int  $sessionId The session ID, if any
2830
 * @param bool $getCount  Whether we want just the amount or the full result
2831
 *
2832
 * @return array|int An integer (if we just asked for the count) or an array of users
2833
 */
2834
function getStudentSubscribedToWork(
2835
    $workId,
2836
    $courseId,
2837
    $groupId = null,
2838
    $sessionId = null,
2839
    $getCount = false
2840
) {
2841
    $usersInWork = null;
2842
    $usersInCourse = null;
2843
2844
    if (empty($groupId)) {
2845
        $courseInfo = api_get_course_info_by_id($courseId);
2846
        $status = STUDENT;
2847
        if (!empty($sessionId)) {
2848
            $status = 0;
2849
        }
2850
        $usersInCourse = CourseManager::get_user_list_from_course_code(
2851
            $courseInfo['code'],
2852
            $sessionId,
2853
            null,
2854
            null,
2855
            $status,
2856
            $getCount
2857
        );
2858
    } else {
2859
        $usersInCourse = GroupManager::get_users(
2860
            $groupId,
2861
            false,
2862
            null,
2863
            null,
2864
            $getCount,
2865
            $courseId
2866
        );
2867
    }
2868
2869
    $usersInWork = getAllUserToWork($workId, $courseId, $getCount);
2870
2871
    if (empty($usersInWork)) {
2872
        return $usersInCourse;
2873
    } else {
2874
        return $usersInWork;
2875
    }
2876
}
2877
2878
/**
2879
 * @param int $userId
2880
 * @param int $workId
2881
 * @param int $courseId
2882
 *
2883
 * @return bool
2884
 */
2885
function allowOnlySubscribedUser($userId, $workId, $courseId)
2886
{
2887
    if (api_is_platform_admin() || api_is_allowed_to_edit()) {
2888
        return true;
2889
    }
2890
2891
    if (userIsSubscribedToWork($userId, $workId, $courseId) == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
2892
        api_not_allowed(true);
2893
    }
2894
}
2895
2896
/**
2897
 * @param int   $workId
2898
 * @param array $courseInfo
2899
 * @param int   $documentId
2900
 *
2901
 * @return array
2902
 */
2903
function getDocumentTemplateFromWork($workId, $courseInfo, $documentId)
2904
{
2905
    $documents = getAllDocumentToWork($workId, $courseInfo['real_id']);
2906
    if (!empty($documents)) {
2907
        foreach ($documents as $doc) {
2908
            if ($documentId != $doc['document_id']) {
2909
                continue;
2910
            }
2911
            $docData = DocumentManager::get_document_data_by_id($doc['document_id'], $courseInfo['code']);
2912
            $fileInfo = pathinfo($docData['path']);
2913
            if ($fileInfo['extension'] == 'html') {
2914
                if (file_exists($docData['absolute_path']) && is_file($docData['absolute_path'])) {
2915
                    $docData['file_content'] = file_get_contents($docData['absolute_path']);
2916
2917
                    return $docData;
2918
                }
2919
            }
2920
        }
2921
    }
2922
2923
    return [];
2924
}
2925
2926
/**
2927
 * @param int   $workId
2928
 * @param array $courseInfo
2929
 *
2930
 * @return string
2931
 */
2932
function getAllDocumentsFromWorkToString($workId, $courseInfo)
2933
{
2934
    $documents = getAllDocumentToWork($workId, $courseInfo['real_id']);
2935
    $content = null;
2936
    if (!empty($documents)) {
2937
        $content .= '<ul class="nav nav-list well">';
2938
        $content .= '<li class="nav-header">'.get_lang('Documents').'</li>';
2939
        foreach ($documents as $doc) {
2940
            $docData = DocumentManager::get_document_data_by_id($doc['document_id'], $courseInfo['code']);
2941
            if ($docData) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $docData of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2942
                $content .= '<li><a target="_blank" href="'.$docData['url'].'">'.$docData['title'].'</a></li>';
2943
            }
2944
        }
2945
        $content .= '</ul><br />';
2946
    }
2947
2948
    return $content;
2949
}
2950
2951
/**
2952
 * Returns fck editor toolbar.
2953
 *
2954
 * @return array
2955
 */
2956
function getWorkDescriptionToolbar()
2957
{
2958
    return [
2959
        'ToolbarStartExpanded' => 'true',
2960
        'ToolbarSet' => 'Work',
2961
        'Width' => '100%',
2962
        'Height' => '400',
2963
    ];
2964
}
2965
2966
/**
2967
 * @param array $work
2968
 *
2969
 * @return array
2970
 */
2971
function getWorkComments($work)
2972
{
2973
    $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
2974
    $userTable = Database::get_main_table(TABLE_MAIN_USER);
2975
2976
    $courseId = intval($work['c_id']);
2977
    $workId = intval($work['id']);
2978
2979
    if (empty($courseId) || empty($workId)) {
2980
        return [];
2981
    }
2982
2983
    $sql = "SELECT
2984
                c.id,
2985
                c.user_id
2986
            FROM $commentTable c
2987
            INNER JOIN $userTable u
2988
            ON (u.id = c.user_id)
2989
            WHERE c_id = $courseId AND work_id = $workId
2990
            ORDER BY sent_at
2991
            ";
2992
    $result = Database::query($sql);
2993
    $comments = Database::store_result($result, 'ASSOC');
2994
    if (!empty($comments)) {
2995
        foreach ($comments as &$comment) {
2996
            $userInfo = api_get_user_info($comment['user_id']);
2997
            $comment['picture'] = $userInfo['avatar'];
2998
            $comment['complete_name'] = $userInfo['complete_name_with_username'];
2999
            $commentInfo = getWorkComment($comment['id']);
3000
            if (!empty($commentInfo)) {
3001
                $comment = array_merge($comment, $commentInfo);
3002
            }
3003
        }
3004
    }
3005
3006
    return $comments;
3007
}
3008
3009
/**
3010
 * Get total score from a work list.
3011
 *
3012
 * @param $workList
3013
 *
3014
 * @return int|null
3015
 */
3016
function getTotalWorkScore($workList)
3017
{
3018
    $count = 0;
3019
    foreach ($workList as $data) {
3020
        $count += $data['qualification_score'];
3021
    }
3022
3023
    return $count;
3024
}
3025
3026
/**
3027
 * Get comment count from a work list (docs sent by students).
3028
 *
3029
 * @param array $workList
3030
 * @param array $courseInfo
3031
 *
3032
 * @return int|null
3033
 */
3034
function getTotalWorkComment($workList, $courseInfo = [])
3035
{
3036
    if (empty($courseInfo)) {
3037
        $courseInfo = api_get_course_info();
3038
    }
3039
3040
    $count = 0;
3041
    foreach ($workList as $data) {
3042
        $count += getWorkCommentCount($data['id'], $courseInfo);
3043
    }
3044
3045
    return $count;
3046
}
3047
3048
/**
3049
 * Get comment count for a specific work sent by a student.
3050
 *
3051
 * @param int   $id
3052
 * @param array $courseInfo
3053
 *
3054
 * @return int
3055
 */
3056
function getWorkCommentCount($id, $courseInfo = [])
3057
{
3058
    if (empty($courseInfo)) {
3059
        $courseInfo = api_get_course_info();
3060
    }
3061
3062
    $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
3063
    $id = intval($id);
3064
3065
    $sql = "SELECT count(*) as count
3066
            FROM $commentTable
3067
            WHERE work_id = $id AND c_id = ".$courseInfo['real_id'];
3068
3069
    $result = Database::query($sql);
3070
    if (Database::num_rows($result)) {
3071
        $comment = Database::fetch_array($result);
3072
3073
        return $comment['count'];
3074
    }
3075
3076
    return 0;
3077
}
3078
3079
/**
3080
 * Get comment count for a specific parent.
3081
 *
3082
 * @param int   $parentId
3083
 * @param array $courseInfo
3084
 * @param int   $sessionId
3085
 *
3086
 * @return int
3087
 */
3088
function getWorkCommentCountFromParent(
3089
    $parentId,
3090
    $courseInfo = [],
3091
    $sessionId = 0
3092
) {
3093
    if (empty($courseInfo)) {
3094
        $courseInfo = api_get_course_info();
3095
    }
3096
3097
    if (empty($sessionId)) {
3098
        $sessionId = api_get_session_id();
3099
    } else {
3100
        $sessionId = intval($sessionId);
3101
    }
3102
3103
    $work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
3104
    $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
3105
    $parentId = intval($parentId);
3106
    $sessionCondition = api_get_session_condition($sessionId, false, false, 'w.session_id');
3107
3108
    $sql = "SELECT count(*) as count
3109
            FROM $commentTable c INNER JOIN $work w
3110
            ON c.c_id = w.c_id AND w.id = c.work_id
3111
            WHERE
3112
                $sessionCondition AND
3113
                parent_id = $parentId AND
3114
                w.c_id = ".$courseInfo['real_id'];
3115
3116
    $result = Database::query($sql);
3117
    if (Database::num_rows($result)) {
3118
        $comment = Database::fetch_array($result);
3119
3120
        return $comment['count'];
3121
    }
3122
3123
    return 0;
3124
}
3125
3126
/**
3127
 * Get last work information from parent.
3128
 *
3129
 * @param int   $parentId
3130
 * @param array $courseInfo
3131
 * @param int   $sessionId
3132
 *
3133
 * @return int
3134
 */
3135
function getLastWorkStudentFromParent(
3136
    $parentId,
3137
    $courseInfo = [],
3138
    $sessionId = 0
3139
) {
3140
    if (empty($courseInfo)) {
3141
        $courseInfo = api_get_course_info();
3142
    }
3143
3144
    if (empty($sessionId)) {
3145
        $sessionId = api_get_session_id();
3146
    } else {
3147
        $sessionId = intval($sessionId);
3148
    }
3149
3150
    $work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
3151
    $sessionCondition = api_get_session_condition($sessionId, false);
3152
    $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
3153
    $parentId = intval($parentId);
3154
3155
    $sql = "SELECT w.*
3156
            FROM $commentTable c INNER JOIN $work w
3157
            ON c.c_id = w.c_id AND w.id = c.work_id
3158
            WHERE
3159
                $sessionCondition AND
3160
                parent_id = $parentId AND
3161
                w.c_id = ".$courseInfo['real_id']."
3162
            ORDER BY w.sent_date
3163
            LIMIT 1
3164
            ";
3165
3166
    $result = Database::query($sql);
3167
    if (Database::num_rows($result)) {
3168
        $comment = Database::fetch_array($result, 'ASSOC');
3169
3170
        return $comment;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $comment also could return the type array which is incompatible with the documented return type integer.
Loading history...
3171
    }
3172
3173
    return [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return array() returns the type array which is incompatible with the documented return type integer.
Loading history...
3174
}
3175
3176
/**
3177
 * Get last work information from parent.
3178
 *
3179
 * @param int   $userId
3180
 * @param array $parentInfo
3181
 * @param array $courseInfo
3182
 * @param int   $sessionId
3183
 *
3184
 * @return int
3185
 */
3186
function getLastWorkStudentFromParentByUser(
3187
    $userId,
3188
    $parentInfo,
3189
    $courseInfo = [],
3190
    $sessionId = 0
3191
) {
3192
    if (empty($courseInfo)) {
3193
        $courseInfo = api_get_course_info();
3194
    }
3195
3196
    if (empty($sessionId)) {
3197
        $sessionId = api_get_session_id();
3198
    } else {
3199
        $sessionId = intval($sessionId);
3200
    }
3201
3202
    $userId = intval($userId);
3203
    $work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
3204
    if (empty($parentInfo)) {
3205
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
3206
    }
3207
    $parentId = $parentInfo['id'];
3208
3209
    $sessionCondition = api_get_session_condition($sessionId);
3210
3211
    $sql = "SELECT *
3212
            FROM $work
3213
            WHERE
3214
                user_id = $userId
3215
                $sessionCondition AND
3216
                parent_id = $parentId AND
3217
                c_id = ".$courseInfo['real_id']."
3218
            ORDER BY sent_date DESC
3219
            LIMIT 1
3220
            ";
3221
    $result = Database::query($sql);
3222
    if (Database::num_rows($result)) {
3223
        $work = Database::fetch_array($result, 'ASSOC');
3224
        $work['qualification_rounded'] = formatWorkScore($work['qualification'], $parentInfo['qualification']);
3225
3226
        return $work;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $work also could return the type array which is incompatible with the documented return type integer.
Loading history...
3227
    }
3228
3229
    return [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return array() returns the type array which is incompatible with the documented return type integer.
Loading history...
3230
}
3231
3232
/**
3233
 * @param float $score
3234
 * @param int   $weight
3235
 *
3236
 * @return string
3237
 */
3238
function formatWorkScore($score, $weight)
3239
{
3240
    $label = 'info';
3241
    $weight = (int) $weight;
3242
    $relativeScore = 0;
3243
    if (!empty($weight)) {
3244
        $relativeScore = $score / $weight;
3245
    }
3246
3247
    if ($relativeScore < 0.5) {
3248
        $label = 'important';
3249
    } elseif ($relativeScore < 0.75) {
3250
        $label = 'warning';
3251
    }
3252
3253
    $scoreBasedInModel = ExerciseLib::convertScoreToModel($relativeScore * 100);
3254
    if (empty($scoreBasedInModel)) {
3255
        $finalScore = api_number_format($score, 1).' / '.$weight;
3256
3257
        return Display::label(
3258
            $finalScore,
3259
            $label
3260
        );
3261
    } else {
3262
        $finalScore = $scoreBasedInModel;
3263
3264
        return $finalScore;
3265
    }
3266
}
3267
3268
/**
3269
 * @param int   $id         comment id
3270
 * @param array $courseInfo
3271
 *
3272
 * @return string
3273
 */
3274
function getWorkComment($id, $courseInfo = [])
3275
{
3276
    if (empty($courseInfo)) {
3277
        $courseInfo = api_get_course_info();
3278
    }
3279
3280
    if (empty($courseInfo['real_id'])) {
3281
        return [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return array() returns the type array which is incompatible with the documented return type string.
Loading history...
3282
    }
3283
3284
    $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
3285
    $id = intval($id);
3286
3287
    $sql = "SELECT * FROM $commentTable
3288
            WHERE id = $id AND c_id = ".$courseInfo['real_id'];
3289
    $result = Database::query($sql);
3290
    $comment = [];
3291
    if (Database::num_rows($result)) {
3292
        $comment = Database::fetch_array($result, 'ASSOC');
3293
        $filePath = null;
3294
        $fileUrl = null;
3295
        $deleteUrl = null;
3296
        $fileName = null;
3297
        if (!empty($comment['file'])) {
3298
            $work = get_work_data_by_id($comment['work_id']);
3299
            $workParent = get_work_data_by_id($work['parent_id']);
3300
            $filePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/work/'.$workParent['url'].'/'.$comment['file'];
3301
            $fileUrl = api_get_path(WEB_CODE_PATH).'work/download_comment_file.php?comment_id='.$id.'&'.api_get_cidreq();
3302
            $deleteUrl = api_get_path(WEB_CODE_PATH).'work/view.php?'.api_get_cidreq().'&id='.$comment['work_id'].'&action=delete_attachment&comment_id='.$id;
3303
            $fileParts = explode('_', $comment['file']);
3304
            $fileName = str_replace($fileParts[0].'_'.$fileParts[1].'_', '', $comment['file']);
3305
        }
3306
        $comment['delete_file_url'] = $deleteUrl;
3307
        $comment['file_path'] = $filePath;
3308
        $comment['file_url'] = $fileUrl;
3309
        $comment['file_name_to_show'] = $fileName;
3310
        $comment['sent_at_with_label'] = Display::dateToStringAgoAndLongDate($comment['sent_at']);
3311
    }
3312
3313
    return $comment;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $comment also could return the type array which is incompatible with the documented return type string.
Loading history...
3314
}
3315
3316
/**
3317
 * @param int   $id
3318
 * @param array $courseInfo
3319
 */
3320
function deleteCommentFile($id, $courseInfo = [])
3321
{
3322
    $workComment = getWorkComment($id, $courseInfo);
3323
    if (isset($workComment['file']) && !empty($workComment['file'])) {
3324
        if (file_exists($workComment['file_path'])) {
3325
            $result = my_delete($workComment['file_path']);
3326
            if ($result) {
3327
                $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
3328
                $params = ['file' => ''];
3329
                Database::update(
3330
                    $commentTable,
3331
                    $params,
3332
                    ['id = ? AND c_id = ? ' => [$workComment['id'], $workComment['c_id']]]
3333
                );
3334
            }
3335
        }
3336
    }
3337
}
3338
3339
/**
3340
 * Adds a comments to the work document.
3341
 *
3342
 * @param array $courseInfo
3343
 * @param int   $userId
3344
 * @param array $parentWork
3345
 * @param array $work
3346
 * @param array $data
3347
 *
3348
 * @return int
3349
 */
3350
function addWorkComment($courseInfo, $userId, $parentWork, $work, $data)
3351
{
3352
    $fileData = isset($data['attachment']) ? $data['attachment'] : null;
3353
    $commentTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT_COMMENT);
3354
3355
    // If no attachment and no comment then don't save comment
3356
    if (empty($fileData['name']) && empty($data['comment'])) {
3357
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
3358
    }
3359
3360
    $params = [
3361
        'work_id' => $work['id'],
3362
        'c_id' => $work['c_id'],
3363
        'user_id' => $userId,
3364
        'comment' => $data['comment'],
3365
        'sent_at' => api_get_utc_datetime(),
3366
    ];
3367
3368
    $commentId = Database::insert($commentTable, $params);
3369
3370
    if ($commentId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $commentId of type integer|false is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
3371
        Display::addFlash(
3372
            Display::return_message(get_lang('CommentAdded'))
3373
        );
3374
3375
        $sql = "UPDATE $commentTable SET id = iid WHERE iid = $commentId";
3376
        Database::query($sql);
3377
    }
3378
3379
    $userIdListToSend = [];
3380
    if (api_is_allowed_to_edit()) {
3381
        if (isset($data['send_email']) && $data['send_email']) {
3382
            // Teacher sends a feedback
3383
            $userIdListToSend = [$work['user_id']];
3384
        }
3385
    } else {
3386
        $sessionId = api_get_session_id();
3387
        if (empty($sessionId)) {
3388
            $teachers = CourseManager::get_teacher_list_from_course_code(
3389
                $courseInfo['code']
3390
            );
3391
            if (!empty($teachers)) {
3392
                $userIdListToSend = array_keys($teachers);
3393
            }
3394
        } else {
3395
            $teachers = SessionManager::getCoachesByCourseSession(
3396
                $sessionId,
3397
                $courseInfo['real_id']
3398
            );
3399
3400
            if (!empty($teachers)) {
3401
                $userIdListToSend = array_values($teachers);
3402
            }
3403
        }
3404
3405
        $sendNotification = api_get_course_setting('email_to_teachers_on_new_work_feedback', api_get_course_id());
3406
        if ($sendNotification != 1) {
3407
            $userIdListToSend = [];
3408
        }
3409
    }
3410
3411
    $url = api_get_path(WEB_CODE_PATH).'work/view.php?'.api_get_cidreq().'&id='.$work['id'];
3412
    $subject = sprintf(get_lang('ThereIsANewWorkFeedback'), $parentWork['title']);
3413
    $content = sprintf(get_lang('ThereIsANewWorkFeedbackInWorkXHere'), $work['title'], $url);
3414
3415
    if (!empty($data['comment'])) {
3416
        $content .= '<br /><b>'.get_lang('Comment').':</b><br />'.$data['comment'];
3417
    }
3418
3419
    if (!empty($userIdListToSend)) {
3420
        foreach ($userIdListToSend as $userIdToSend) {
3421
            MessageManager::send_message_simple(
3422
                $userIdToSend,
3423
                $subject,
3424
                $content
3425
            );
3426
        }
3427
    }
3428
3429
    if (!empty($commentId) && !empty($fileData)) {
3430
        $workParent = get_work_data_by_id($work['parent_id']);
3431
        if (!empty($workParent)) {
3432
            $uploadDir = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/work'.$workParent['url'];
3433
            $newFileName = 'comment_'.$commentId.'_'.php2phps(api_replace_dangerous_char($fileData['name']));
3434
            $newFilePath = $uploadDir.'/'.$newFileName;
3435
            $result = move_uploaded_file($fileData['tmp_name'], $newFilePath);
3436
            if ($result) {
3437
                $params = ['file' => $newFileName];
3438
                Database::update(
3439
                    $commentTable,
3440
                    $params,
3441
                    ['id = ? AND c_id = ? ' => [$commentId, $work['c_id']]]
3442
                );
3443
            }
3444
        }
3445
    }
3446
}
3447
3448
/**
3449
 * @param array $work
3450
 * @param array $workParent
3451
 *
3452
 * @return string
3453
 */
3454
function getWorkCommentForm($work, $workParent)
3455
{
3456
    $url = api_get_path(WEB_CODE_PATH).'work/view.php?id='.$work['id'].'&action=send_comment&'.api_get_cidreq();
3457
    $form = new FormValidator(
3458
        'work_comment',
3459
        'post',
3460
        $url,
3461
        '',
3462
        ['enctype' => "multipart/form-data"]
3463
    );
3464
3465
    $qualification = $workParent['qualification'];
3466
3467
    if (api_is_allowed_to_edit()) {
3468
        if (!empty($qualification) && intval($qualification) > 0) {
3469
            $model = ExerciseLib::getCourseScoreModel();
3470
            if (empty($model)) {
3471
                $form->addFloat(
3472
                    'qualification',
3473
                    [get_lang('Qualification'), " / ".$qualification],
3474
                    false,
3475
                    [],
3476
                    false,
3477
                    0,
3478
                    $qualification
3479
                );
3480
            } else {
3481
                ExerciseLib::addScoreModelInput(
3482
                    $form,
3483
                    'qualification',
3484
                    $qualification,
3485
                    $work['qualification']
3486
                );
3487
            }
3488
            $form->addFile('file', get_lang('Correction'));
3489
            $form->setDefaults(['qualification' => $work['qualification']]);
3490
        }
3491
    }
3492
3493
    Skill::addSkillsToUserForm($form, ITEM_TYPE_STUDENT_PUBLICATION, $workParent['id'], $work['user_id'], $work['id']);
3494
    $form->addHtmlEditor('comment', get_lang('Comment'), false);
3495
    $form->addFile('attachment', get_lang('Attachment'));
3496
    $form->addElement('hidden', 'id', $work['id']);
3497
3498
    if (api_is_allowed_to_edit()) {
3499
        $form->addCheckBox(
3500
            'send_email',
3501
            null,
3502
            get_lang('SendMailToStudent')
3503
        );
3504
    }
3505
3506
    $form->addButtonSend(get_lang('Send'), 'button');
3507
3508
    return $form->returnForm();
3509
}
3510
3511
/**
3512
 * @param array $homework result of get_work_assignment_by_id()
3513
 *
3514
 * @return array
3515
 */
3516
function getWorkDateValidationStatus($homework)
3517
{
3518
    $message = null;
3519
    $has_expired = false;
3520
    $has_ended = false;
3521
3522
    if (!empty($homework)) {
3523
        if (!empty($homework['expires_on']) || !empty($homework['ends_on'])) {
3524
            $time_now = time();
3525
3526
            if (!empty($homework['expires_on'])) {
3527
                $time_expires = api_strtotime($homework['expires_on'], 'UTC');
3528
                $difference = $time_expires - $time_now;
3529
                if ($difference < 0) {
3530
                    $has_expired = true;
3531
                }
3532
            }
3533
3534
            if (empty($homework['expires_on'])) {
3535
                $has_expired = false;
3536
            }
3537
3538
            if (!empty($homework['ends_on'])) {
3539
                $time_ends = api_strtotime($homework['ends_on'], 'UTC');
3540
                $difference2 = $time_ends - $time_now;
3541
                if ($difference2 < 0) {
3542
                    $has_ended = true;
3543
                }
3544
            }
3545
3546
            $ends_on = api_convert_and_format_date($homework['ends_on']);
3547
            $expires_on = api_convert_and_format_date($homework['expires_on']);
3548
        }
3549
3550
        if ($has_ended) {
3551
            $message = Display::return_message(get_lang('EndDateAlreadyPassed').' '.$ends_on, 'error');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ends_on does not seem to be defined for all execution paths leading up to this point.
Loading history...
3552
        } elseif ($has_expired) {
3553
            $message = Display::return_message(get_lang('ExpiryDateAlreadyPassed').' '.$expires_on, 'warning');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $expires_on does not seem to be defined for all execution paths leading up to this point.
Loading history...
3554
        } else {
3555
            if ($has_expired) {
3556
                $message = Display::return_message(get_lang('ExpiryDateToSendWorkIs').' '.$expires_on);
3557
            }
3558
        }
3559
    }
3560
3561
    return [
3562
        'message' => $message,
3563
        'has_ended' => $has_ended,
3564
        'has_expired' => $has_expired,
3565
    ];
3566
}
3567
3568
/**
3569
 * @param FormValidator $form
3570
 * @param int           $uploadFormType
3571
 */
3572
function setWorkUploadForm($form, $uploadFormType = 0)
3573
{
3574
    $form->addHeader(get_lang('UploadADocument'));
3575
    $form->addHidden('contains_file', 0, ['id' => 'contains_file_id']);
3576
    $form->addHidden('active', 1);
3577
    $form->addHidden('accepted', 1);
3578
    $form->addElement('text', 'title', get_lang('Title'), ['id' => 'file_upload']);
3579
    $form->addElement(
3580
        'text',
3581
        'extension',
3582
        get_lang('FileExtension'),
3583
        ['id' => 'file_extension', 'readonly' => 'readonly']
3584
    );
3585
    $form->addRule('title', get_lang('ThisFieldIsRequired'), 'required');
3586
3587
    switch ($uploadFormType) {
3588
        case 0:
3589
            // File and text.
3590
            $form->addElement(
3591
                'file',
3592
                'file',
3593
                get_lang('UploadADocument'),
3594
                'size="40" onchange="updateDocumentTitle(this.value)"'
3595
            );
3596
            $form->addProgress();
3597
            $form->addHtmlEditor('description', get_lang('Description'), false, false, getWorkDescriptionToolbar());
3598
            break;
3599
        case 1:
3600
            // Only text.
3601
            $form->addHtmlEditor('description', get_lang('Description'), false, false, getWorkDescriptionToolbar());
3602
            $form->addRule('description', get_lang('ThisFieldIsRequired'), 'required');
3603
            break;
3604
        case 2:
3605
            // Only file.
3606
            $form->addElement(
3607
                'file',
3608
                'file',
3609
                get_lang('UploadADocument'),
3610
                'size="40" onchange="updateDocumentTitle(this.value)"'
3611
            );
3612
            $form->addProgress();
3613
            $form->addRule('file', get_lang('ThisFieldIsRequired'), 'required');
3614
            break;
3615
    }
3616
3617
    $form->addButtonUpload(get_lang('Upload'), 'submitWork');
3618
}
3619
3620
/**
3621
 * @param array $my_folder_data
3622
 * @param array $_course
3623
 * @param bool  $isCorrection
3624
 * @param array $workInfo
3625
 * @param array $file
3626
 *
3627
 * @return array
3628
 */
3629
function uploadWork($my_folder_data, $_course, $isCorrection = false, $workInfo = [], $file = [])
3630
{
3631
    if (isset($_FILES['file']) && !empty($_FILES['file'])) {
3632
        $file = $_FILES['file'];
3633
    }
3634
3635
    if (empty($file['size'])) {
3636
        return [
3637
            'error' => Display:: return_message(
3638
                get_lang('UplUploadFailedSizeIsZero'),
3639
                'error'
3640
            ),
3641
        ];
3642
    }
3643
    $updir = api_get_path(SYS_COURSE_PATH).$_course['path'].'/work/'; //directory path to upload
3644
3645
    // Try to add an extension to the file if it has'nt one
3646
    $filename = add_ext_on_mime(stripslashes($file['name']), $file['type']);
3647
3648
    // Replace dangerous characters
3649
    $filename = api_replace_dangerous_char($filename);
3650
3651
    // Transform any .php file in .phps fo security
3652
    $filename = php2phps($filename);
3653
    $filesize = filesize($file['tmp_name']);
3654
3655
    if (empty($filesize)) {
3656
        return [
3657
            'error' => Display::return_message(
3658
                get_lang('UplUploadFailedSizeIsZero'),
3659
                'error'
3660
            ),
3661
        ];
3662
    } elseif (!filter_extension($new_file_name)) {
3663
        return [
3664
            'error' => Display::return_message(
3665
                get_lang('UplUnableToSaveFileFilteredExtension'),
3666
                'error'
3667
            ),
3668
        ];
3669
    }
3670
3671
    $totalSpace = DocumentManager::documents_total_space($_course['real_id']);
3672
    $course_max_space = DocumentManager::get_course_quota($_course['code']);
3673
    $total_size = $filesize + $totalSpace;
3674
3675
    if ($total_size > $course_max_space) {
3676
        return [
3677
            'error' => Display::return_message(get_lang('NoSpace'), 'error'),
3678
        ];
3679
    }
3680
3681
    // Compose a unique file name to avoid any conflict
3682
    $new_file_name = api_get_unique_id();
3683
3684
    if ($isCorrection) {
3685
        if (!empty($workInfo['url'])) {
3686
            $new_file_name = basename($workInfo['url']).'_correction';
3687
        } else {
3688
            $new_file_name = $new_file_name.'_correction';
3689
        }
3690
    }
3691
3692
    $curdirpath = basename($my_folder_data['url']);
3693
3694
    // If we come from the group tools the groupid will be saved in $work_table
3695
    if (is_dir($updir.$curdirpath) || empty($curdirpath)) {
3696
        $result = move_uploaded_file(
3697
            $file['tmp_name'],
3698
            $updir.$curdirpath.'/'.$new_file_name
3699
        );
3700
    } else {
3701
        return [
3702
            'error' => Display :: return_message(
3703
                get_lang('FolderDoesntExistsInFileSystem'),
3704
                'error'
3705
            ),
3706
        ];
3707
    }
3708
3709
    if ($result) {
3710
        $url = 'work/'.$curdirpath.'/'.$new_file_name;
3711
    } else {
3712
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
3713
    }
3714
3715
    return [
3716
        'url' => $url,
3717
        'filename' => $filename,
3718
        'filesize' => $filesize,
3719
        'error' => '',
3720
    ];
3721
}
3722
3723
/**
3724
 * Send an e-mail to users related to this work (course teachers, usually, but
3725
 * might include other group members).
3726
 *
3727
 * @param int   $workId
3728
 * @param array $courseInfo
3729
 * @param int   $session_id
3730
 */
3731
function sendAlertToUsers($workId, $courseInfo, $session_id)
3732
{
3733
    $user_list = [];
3734
    $workData = get_work_data_by_id($workId, $courseInfo['real_id'], $session_id);
3735
    // last value is to check this is not "just" an edit
3736
    // YW Tis part serve to send a e-mail to the tutors when a new file is sent
3737
    $send = api_get_course_setting('email_alert_manager_on_new_doc');
3738
3739
    if ($send == SEND_EMAIL_EVERYONE || $send == SEND_EMAIL_TEACHERS) {
3740
        // Lets predefine some variables. Be sure to change the from address!
3741
        if (empty($session_id)) {
3742
            //Teachers
3743
            $user_list = CourseManager::get_user_list_from_course_code(
3744
                api_get_course_id(),
3745
                null,
3746
                null,
3747
                null,
3748
                COURSEMANAGER
3749
            );
3750
        } else {
3751
            // Coaches
3752
            $user_list = CourseManager::get_user_list_from_course_code(
3753
                api_get_course_id(),
3754
                $session_id,
3755
                null,
3756
                null,
3757
                2
3758
            );
3759
        }
3760
    }
3761
3762
    if ($send == SEND_EMAIL_EVERYONE || $send == SEND_EMAIL_STUDENTS) {
3763
        if (!$session_id) {
3764
            $session_id = null;
3765
        }
3766
        $student = CourseManager::get_user_list_from_course_code(
3767
            api_get_course_id(),
3768
            $session_id,
3769
            null,
3770
            null,
3771
            STUDENT,
3772
            null,
3773
            null,
3774
            null,
3775
            null,
3776
            null,
3777
            [api_get_user_id()]
3778
        );
3779
        $user_list = array_merge($user_list, $student);
0 ignored issues
show
Bug introduced by
It seems like $user_list can also be of type integer; however, parameter $array1 of array_merge() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3779
        $user_list = array_merge(/** @scrutinizer ignore-type */ $user_list, $student);
Loading history...
Bug introduced by
It seems like $student can also be of type integer; however, parameter $array2 of array_merge() does only seem to accept null|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3779
        $user_list = array_merge($user_list, /** @scrutinizer ignore-type */ $student);
Loading history...
3780
    }
3781
3782
    if ($send) {
3783
        $subject = "[".api_get_setting('siteName')."] ".get_lang('SendMailBody')."\n ".get_lang('CourseName').": ".$courseInfo['name']."  ";
3784
        foreach ($user_list as $user_data) {
3785
            $to_user_id = $user_data['user_id'];
3786
            $user_info = api_get_user_info($to_user_id);
3787
            $message = get_lang('SendMailBody')."\n".get_lang('CourseName')." : ".$courseInfo['name']."\n";
3788
            $message .= get_lang('UserName')." : ".$user_info['complete_name']."\n";
3789
            $message .= get_lang('DateSent')." : ".api_format_date(api_get_local_time())."\n";
3790
            $url = api_get_path(WEB_CODE_PATH)."work/work.php?cidReq=".$courseInfo['code']."&id_session=".$session_id."&id=".$workData['id'];
3791
            $message .= get_lang('WorkName')." : ".$workData['title']."\n\n".'<a href="'.$url.'">'.get_lang('DownloadLink')."</a>\n";
3792
            MessageManager::send_message_simple(
3793
                $to_user_id,
3794
                $subject,
3795
                $message,
3796
                0,
3797
                false,
3798
                false,
3799
                [],
3800
                false
3801
            );
3802
        }
3803
    }
3804
}
3805
3806
/**
3807
 * Check if the current uploaded work filename already exists in the current assement.
3808
 *
3809
 * @param string $filename
3810
 * @param int    $workId
3811
 *
3812
 * @return array
3813
 */
3814
function checkExistingWorkFileName($filename, $workId)
3815
{
3816
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
3817
    $filename = Database::escape_string($filename);
3818
    $workId = (int) $workId;
3819
3820
    $sql = "SELECT title FROM $table
3821
            WHERE parent_id = $workId AND title = '$filename' AND active = 1";
3822
    $result = Database::query($sql);
3823
3824
    return Database::fetch_assoc($result);
3825
}
3826
3827
/**
3828
 * @param array $workInfo
3829
 * @param array $values
3830
 * @param array $courseInfo
3831
 * @param int   $sessionId
3832
 * @param int   $groupId
3833
 * @param int   $userId
3834
 * @param array $file
3835
 * @param bool  $checkDuplicated
3836
 * @param bool  $showFlashMessage
3837
 *
3838
 * @return null|string
3839
 */
3840
function processWorkForm(
3841
    $workInfo,
3842
    $values,
3843
    $courseInfo,
3844
    $sessionId,
3845
    $groupId,
3846
    $userId,
3847
    $file = [],
3848
    $checkDuplicated = false,
3849
    $showFlashMessage = true
3850
) {
3851
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
3852
3853
    $courseId = $courseInfo['real_id'];
3854
    $groupId = (int) $groupId;
3855
    $sessionId = (int) $sessionId;
3856
    $userId = (int) $userId;
3857
3858
    $extension = '';
3859
    if (isset($values['extension'])) {
3860
        $extension = $values['extension'];
3861
    } else {
3862
        $fileInfo = pathinfo($values['title']);
3863
        if (isset($fileInfo['extension']) && !empty($fileInfo['extension'])) {
3864
            $extension = '.'.$fileInfo['extension'];
3865
            $values['title'] = $fileInfo['filename'];
3866
        }
3867
    }
3868
3869
    $title = $values['title'].$extension;
3870
    $description = isset($values['description']) ? $values['description'] : '';
3871
    $containsFile = isset($values['contains_file']) && !empty($values['contains_file']) ? (int) $values['contains_file'] : 0;
3872
3873
    $saveWork = true;
3874
    $filename = null;
3875
    $url = null;
3876
    $filesize = null;
3877
    $workData = [];
3878
    $message = null;
3879
3880
    if ($containsFile) {
3881
        $saveWork = false;
3882
        if ($checkDuplicated) {
3883
            if (checkExistingWorkFileName($file['name'], $workInfo['id'])) {
3884
                $saveWork = false;
3885
                $result['error'] = get_lang('YouAlreadySentThisFile');
0 ignored issues
show
Comprehensibility Best Practice introduced by
$result was never initialized. Although not strictly required by PHP, it is generally a good practice to add $result = array(); before regardless.
Loading history...
3886
                $workData['error'] = get_lang('UplAlreadyExists');
3887
            } else {
3888
                $result = uploadWork($workInfo, $courseInfo, false, [], $file);
3889
            }
3890
        } else {
3891
            $result = uploadWork($workInfo, $courseInfo, false, [], $file);
3892
        }
3893
3894
        if (isset($result['error'])) {
3895
            $saveWork = false;
3896
            if ($showFlashMessage) {
3897
                $message = $result['error'];
3898
            }
3899
            if (empty($result['error']) && isset($result['url']) && !empty($result['url'])) {
3900
                $saveWork = true;
3901
            }
3902
        }
3903
    }
3904
3905
    if ($saveWork) {
3906
        $filename = isset($result['filename']) ? $result['filename'] : null;
3907
        if (empty($title)) {
3908
            $title = isset($result['title']) && !empty($result['title']) ? $result['title'] : get_lang('Untitled');
3909
        }
3910
        $filesize = isset($result['filesize']) ? $result['filesize'] : null;
3911
        $url = isset($result['url']) ? $result['url'] : null;
3912
    }
3913
3914
    if (empty($title)) {
3915
        $title = get_lang('Untitled');
3916
    }
3917
3918
    $groupIid = 0;
3919
    $groupInfo = [];
3920
    if ($groupId) {
3921
        $groupInfo = GroupManager::get_group_properties($groupId);
3922
        $groupIid = $groupInfo['iid'];
3923
    }
3924
3925
    if ($saveWork) {
3926
        $active = '1';
3927
        $params = [
3928
            'c_id' => $courseId,
3929
            'url' => $url,
3930
            'filetype' => 'file',
3931
            'title' => $title,
3932
            'description' => $description,
3933
            'contains_file' => $containsFile,
3934
            'active' => $active,
3935
            'accepted' => '1',
3936
            'qualificator_id' => 0,
3937
            'document_id' => 0,
3938
            'weight' => 0,
3939
            'allow_text_assignment' => 0,
3940
            'post_group_id' => $groupIid,
3941
            'sent_date' => api_get_utc_datetime(),
3942
            'parent_id' => $workInfo['id'],
3943
            'session_id' => $sessionId ? $sessionId : null,
3944
            'user_id' => $userId,
3945
            'has_properties' => 0,
3946
            'qualification' => 0,
3947
            //'filesize' => $filesize
3948
        ];
3949
        $workId = Database::insert($work_table, $params);
3950
3951
        if ($workId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $workId of type integer|false is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
3952
            $sql = "UPDATE $work_table SET id = iid WHERE iid = $workId ";
3953
            Database::query($sql);
3954
3955
            if (array_key_exists('filename', $workInfo) && !empty($filename)) {
3956
                $filename = Database::escape_string($filename);
3957
                $sql = "UPDATE $work_table SET
3958
                            filename = '$filename'
3959
                        WHERE iid = $workId";
3960
                Database::query($sql);
3961
            }
3962
3963
            if (array_key_exists('document_id', $workInfo)) {
3964
                $documentId = isset($values['document_id']) ? intval($values['document_id']) : 0;
3965
                $sql = "UPDATE $work_table SET
3966
                            document_id = '$documentId'
3967
                        WHERE iid = $workId";
3968
                Database::query($sql);
3969
            }
3970
            api_item_property_update(
3971
                $courseInfo,
3972
                'work',
3973
                $workId,
3974
                'DocumentAdded',
3975
                $userId,
3976
                $groupInfo
3977
            );
3978
            sendAlertToUsers($workId, $courseInfo, $sessionId);
3979
            Event::event_upload($workId);
3980
3981
            // The following feature requires the creation of a work-type
3982
            // extra_field and the following setting in the configuration file
3983
            // (until moved to the database). It allows te teacher to set a
3984
            // "considered work time", meaning the time we assume a student
3985
            // would have spent, approximately, to prepare the task before
3986
            // handing it in Chamilo, adding this time to the student total
3987
            // course use time, as a register of time spent *before* his
3988
            // connection to the platform to hand the work in.
3989
            $consideredWorkingTime = api_get_configuration_value('considered_working_time');
3990
3991
            if (!empty($consideredWorkingTime)) {
3992
                // Get the "considered work time" defined for this work
3993
                $fieldValue = new ExtraFieldValue('work');
3994
                $resultExtra = $fieldValue->getAllValuesForAnItem(
3995
                    $workInfo['iid'], //the ID of the work *folder*, not the document uploaded by the student
3996
                    true
3997
                );
3998
3999
                $workingTime = null;
4000
                foreach ($resultExtra as $field) {
4001
                    $field = $field['value'];
4002
                    if ($consideredWorkingTime == $field->getField()->getVariable()) {
4003
                        $workingTime = $field->getValue();
4004
                    }
4005
                }
4006
4007
                // If no time was defined, or a time of "0" was set, do nothing
4008
                if (!empty($workingTime)) {
4009
                    // If some time is set, get the list of docs handed in by
4010
                    // this student (to make sure we count the time only once)
4011
                    $userWorks = get_work_user_list(
4012
                        0,
4013
                        100,
4014
                        null,
4015
                        null,
4016
                        $workInfo['id'],
4017
                        null,
4018
                        $userId,
4019
                        false,
4020
                        $courseId,
4021
                        $sessionId
4022
                    );
4023
4024
                    if (count($userWorks) == 1) {
4025
                        // The student only uploaded one doc so far, so add the
4026
                        // considered work time to his course connection time
4027
                        $ip = api_get_real_ip();
4028
                        Event::eventAddVirtualCourseTime($courseId, $userId, $sessionId, $workingTime, $ip);
4029
                    }
4030
                }
4031
            }
4032
            $workData = get_work_data_by_id($workId);
4033
            if ($workData && $showFlashMessage) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $workData of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
4034
                Display::addFlash(Display::return_message(get_lang('DocAdd')));
4035
            }
4036
        }
4037
    } else {
4038
        if ($showFlashMessage) {
4039
            Display::addFlash(
4040
                Display::return_message(
4041
                    $message ? $message : get_lang('ImpossibleToSaveTheDocument'),
4042
                    'error'
4043
                )
4044
            );
4045
        }
4046
    }
4047
4048
    return $workData;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $workData returns the type array|string[] which is incompatible with the documented return type null|string.
Loading history...
4049
}
4050
4051
/**
4052
 * Creates a new task (directory) in the assignment tool.
4053
 *
4054
 * @param array $formValues
4055
 * @param int   $user_id
4056
 * @param array $courseInfo
4057
 * @param int   $groupId
4058
 * @param int   $sessionId
4059
 *
4060
 * @return bool|int
4061
 * @note $params can have the following elements, but should at least have the 2 first ones: (
4062
 *       'new_dir' => 'some-name',
4063
 *       'description' => 'some-desc',
4064
 *       'qualification' => 20 (e.g. 20),
4065
 *       'weight' => 50 (percentage) to add to gradebook (e.g. 50),
4066
 *       'allow_text_assignment' => 0/1/2,
4067
 *
4068
 * @todo Rename createAssignment or createWork, or something like that
4069
 */
4070
function addDir($formValues, $user_id, $courseInfo, $groupId, $sessionId = 0)
4071
{
4072
    $em = Database::getManager();
4073
4074
    $user_id = intval($user_id);
4075
    $groupId = intval($groupId);
4076
4077
    $groupIid = 0;
4078
    $groupInfo = [];
4079
    if (!empty($groupId)) {
4080
        $groupInfo = GroupManager::get_group_properties($groupId);
4081
        $groupIid = $groupInfo['iid'];
4082
    }
4083
    $sessionId = (int) $sessionId;
4084
    $session = $em->find('ChamiloCoreBundle:Session', $sessionId);
4085
4086
    $base_work_dir = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/work';
4087
    $course_id = $courseInfo['real_id'];
4088
4089
    $directory = api_replace_dangerous_char($formValues['new_dir']);
4090
    $directory = disable_dangerous_file($directory);
4091
    $created_dir = create_unexisting_work_directory($base_work_dir, $directory);
4092
4093
    if (empty($created_dir)) {
4094
        return false;
4095
    }
4096
4097
    $enableEndDate = isset($formValues['enableEndDate']) ? true : false;
4098
    $enableExpiryDate = isset($formValues['enableExpiryDate']) ? true : false;
4099
4100
    if ($enableEndDate && $enableExpiryDate) {
4101
        if ($formValues['expires_on'] > $formValues['ends_on']) {
4102
            Display::addFlash(
4103
                Display::return_message(
4104
                    get_lang('DateExpiredNotBeLessDeadLine'),
4105
                    'warning'
4106
                )
4107
            );
4108
4109
            return false;
4110
        }
4111
    }
4112
4113
    $dirName = '/'.$created_dir;
4114
    $today = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
4115
    $title = isset($formValues['work_title']) ? $formValues['work_title'] : $formValues['new_dir'];
4116
4117
    $workTable = new CStudentPublication();
4118
    $workTable
4119
        ->setCId($course_id)
4120
        ->setUrl($dirName)
4121
        ->setTitle($title)
4122
        ->setDescription($formValues['description'])
4123
        ->setActive(true)
4124
        ->setAccepted(true)
4125
        ->setFiletype('folder')
4126
        ->setPostGroupId($groupIid)
4127
        ->setSentDate($today)
4128
        ->setQualification($formValues['qualification'] != '' ? $formValues['qualification'] : 0)
4129
        ->setParentId(0)
4130
        ->setQualificatorId(0)
4131
        ->setWeight(!empty($formValues['weight']) ? $formValues['weight'] : 0)
4132
        ->setSession($session)
4133
        ->setAllowTextAssignment($formValues['allow_text_assignment'])
4134
        ->setContainsFile(0)
4135
        ->setUserId($user_id)
4136
        ->setHasProperties(0)
4137
        ->setDocumentId(0);
4138
4139
    $em->persist($workTable);
4140
    $em->flush();
4141
4142
    $workTable->setId($workTable->getIid());
4143
    $em->merge($workTable);
4144
    $em->flush();
4145
4146
    // Folder created
4147
    api_item_property_update(
4148
        $courseInfo,
4149
        'work',
4150
        $workTable->getIid(),
4151
        'DirectoryCreated',
4152
        $user_id,
4153
        $groupInfo
4154
    );
4155
4156
    updatePublicationAssignment(
4157
        $workTable->getIid(),
4158
        $formValues,
4159
        $courseInfo,
4160
        $groupIid
4161
    );
4162
4163
    // Added the new Work ID to the extra field values
4164
    $formValues['item_id'] = $workTable->getIid();
4165
4166
    $workFieldValue = new ExtraFieldValue('work');
4167
    $workFieldValue->saveFieldValues($formValues);
4168
4169
    $sendEmailAlert = api_get_course_setting('email_alert_students_on_new_homework');
4170
4171
    switch ($sendEmailAlert) {
4172
        case 1:
4173
            sendEmailToStudentsOnHomeworkCreation(
4174
                $workTable->getIid(),
4175
                $course_id,
4176
                $sessionId
4177
            );
4178
            //no break
4179
        case 2:
4180
            sendEmailToDrhOnHomeworkCreation(
4181
                $workTable->getIid(),
4182
                $course_id,
4183
                $sessionId
4184
            );
4185
            break;
4186
    }
4187
4188
    return $workTable->getIid();
4189
}
4190
4191
/**
4192
 * @param int   $workId
4193
 * @param array $courseInfo
4194
 *
4195
 * @return int
4196
 */
4197
function agendaExistsForWork($workId, $courseInfo)
4198
{
4199
    $workTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
4200
    $courseId = $courseInfo['real_id'];
4201
    $workId = intval($workId);
4202
4203
    $sql = "SELECT add_to_calendar FROM $workTable
4204
            WHERE c_id = $courseId AND publication_id = ".$workId;
4205
    $res = Database::query($sql);
4206
    if (Database::num_rows($res)) {
4207
        $row = Database::fetch_array($res, 'ASSOC');
4208
        if (!empty($row['add_to_calendar'])) {
4209
            return $row['add_to_calendar'];
4210
        }
4211
    }
4212
4213
    return 0;
4214
}
4215
4216
/**
4217
 * Update work description, qualification, weight, allow_text_assignment.
4218
 *
4219
 * @param int   $workId     (iid)
4220
 * @param array $params
4221
 * @param array $courseInfo
4222
 * @param int   $sessionId
4223
 */
4224
function updateWork($workId, $params, $courseInfo, $sessionId = 0)
0 ignored issues
show
Unused Code introduced by
The parameter $sessionId is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

4224
function updateWork($workId, $params, $courseInfo, /** @scrutinizer ignore-unused */ $sessionId = 0)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
4225
{
4226
    $workTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
4227
    $filteredParams = [
4228
        'description' => $params['description'],
4229
        'qualification' => $params['qualification'],
4230
        'weight' => $params['weight'],
4231
        'allow_text_assignment' => $params['allow_text_assignment'],
4232
    ];
4233
4234
    Database::update(
4235
        $workTable,
4236
        $filteredParams,
4237
        [
4238
            'iid = ? AND c_id = ?' => [
4239
                $workId,
4240
                $courseInfo['real_id'],
4241
            ],
4242
        ]
4243
    );
4244
4245
    $workFieldValue = new ExtraFieldValue('work');
4246
    $workFieldValue->saveFieldValues($params);
4247
}
4248
4249
/**
4250
 * @param int   $workId
4251
 * @param array $params
4252
 * @param array $courseInfo
4253
 * @param int   $groupId
4254
 */
4255
function updatePublicationAssignment($workId, $params, $courseInfo, $groupId)
4256
{
4257
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
4258
    $workTable = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
4259
    $workId = intval($workId);
4260
    $now = api_get_utc_datetime();
4261
    $course_id = $courseInfo['real_id'];
4262
4263
    // Insert into agenda
4264
    $agendaId = 0;
4265
    if (isset($params['add_to_calendar']) && $params['add_to_calendar'] == 1) {
4266
        // Setting today date
4267
        $date = $end_date = $now;
4268
4269
        if (isset($params['enableExpiryDate'])) {
4270
            $end_date = $params['expires_on'];
4271
            $date = $end_date;
4272
        }
4273
4274
        $title = sprintf(get_lang('HandingOverOfTaskX'), $params['new_dir']);
4275
        $description = isset($params['description']) ? $params['description'] : '';
4276
        $content = '<a href="'.api_get_path(WEB_CODE_PATH).'work/work_list.php?'.api_get_cidreq().'&id='.$workId.'">'
4277
            .$params['new_dir'].'</a>'.$description;
4278
4279
        $agendaId = agendaExistsForWork($workId, $courseInfo);
4280
4281
        // Add/edit agenda
4282
        $agenda = new Agenda('course');
4283
        $agenda->set_course($courseInfo);
4284
4285
        if (!empty($agendaId)) {
4286
            // add_to_calendar is set but it doesnt exists then invalidate
4287
            $eventInfo = $agenda->get_event($agendaId);
4288
            if (empty($eventInfo)) {
4289
                $agendaId = 0;
4290
            }
4291
        }
4292
4293
        $eventColor = $agenda->eventStudentPublicationColor;
4294
4295
        if (empty($agendaId)) {
4296
            $agendaId = $agenda->addEvent(
4297
                $date,
4298
                $end_date,
4299
                'false',
4300
                $title,
4301
                $content,
4302
                ['GROUP:'.$groupId],
4303
                false,
4304
                null,
4305
                [],
4306
                [],
4307
                null,
4308
                $eventColor
4309
            );
4310
        } else {
4311
            $agenda->editEvent(
4312
                $agendaId,
4313
                $end_date,
4314
                $end_date,
4315
                'false',
4316
                $title,
4317
                $content,
4318
                [],
4319
                [],
4320
                [],
4321
                null,
4322
                $eventColor
4323
            );
4324
        }
4325
    }
4326
4327
    $qualification = isset($params['qualification']) && !empty($params['qualification']) ? 1 : 0;
4328
    $expiryDate = isset($params['enableExpiryDate']) && (int) $params['enableExpiryDate'] == 1 ? api_get_utc_datetime($params['expires_on']) : '';
4329
    $endDate = isset($params['enableEndDate']) && (int) $params['enableEndDate'] == 1 ? api_get_utc_datetime($params['ends_on']) : '';
4330
    $data = get_work_assignment_by_id($workId, $course_id);
4331
    if (!empty($expiryDate)) {
4332
        $expiryDateCondition = "expires_on = '".Database::escape_string($expiryDate)."', ";
4333
    } else {
4334
        $expiryDateCondition = "expires_on = null, ";
4335
    }
4336
4337
    if (!empty($endDate)) {
4338
        $endOnCondition = "ends_on = '".Database::escape_string($endDate)."', ";
4339
    } else {
4340
        $endOnCondition = "ends_on = null, ";
4341
    }
4342
4343
    if (empty($data)) {
4344
        $sql = "INSERT INTO $table SET
4345
                c_id = $course_id ,
4346
                $expiryDateCondition
4347
                $endOnCondition
4348
                add_to_calendar = $agendaId,
4349
                enable_qualification = '$qualification',
4350
                publication_id = '$workId'";
4351
        Database::query($sql);
4352
        $my_last_id = Database::insert_id();
4353
4354
        if ($my_last_id) {
4355
            $sql = "UPDATE $table SET
4356
                        id = iid
4357
                    WHERE iid = $my_last_id";
4358
            Database::query($sql);
4359
4360
            $sql = "UPDATE $workTable SET
4361
                        has_properties  = $my_last_id,
4362
                        view_properties = 1
4363
                    WHERE c_id = $course_id AND id = $workId";
4364
            Database::query($sql);
4365
        }
4366
    } else {
4367
        $sql = "UPDATE $table SET
4368
                    $expiryDateCondition
4369
                    $endOnCondition
4370
                    add_to_calendar  = $agendaId,
4371
                    enable_qualification = '".$qualification."'
4372
                WHERE
4373
                    publication_id = $workId AND
4374
                    c_id = $course_id AND
4375
                    iid = ".$data['iid'];
4376
        Database::query($sql);
4377
    }
4378
4379
    if (!empty($params['category_id'])) {
4380
        $link_info = GradebookUtils::isResourceInCourseGradebook(
4381
            $courseInfo['code'],
4382
            LINK_STUDENTPUBLICATION,
4383
            $workId,
4384
            api_get_session_id()
4385
        );
4386
4387
        $linkId = null;
4388
        if (!empty($link_info)) {
4389
            $linkId = $link_info['id'];
4390
        }
4391
4392
        if (isset($params['make_calification']) &&
4393
            $params['make_calification'] == 1
4394
        ) {
4395
            if (empty($linkId)) {
4396
                GradebookUtils::add_resource_to_course_gradebook(
4397
                    $params['category_id'],
4398
                    $courseInfo['code'],
4399
                    LINK_STUDENTPUBLICATION,
4400
                    $workId,
4401
                    $params['new_dir'],
4402
                    api_float_val($params['weight']),
4403
                    api_float_val($params['qualification']),
4404
                    $params['description'],
4405
                    1,
4406
                    api_get_session_id()
4407
                );
4408
            } else {
4409
                GradebookUtils::updateResourceFromCourseGradebook(
4410
                    $linkId,
4411
                    $courseInfo['code'],
4412
                    $params['weight']
4413
                );
4414
            }
4415
        } else {
4416
            // Delete everything of the gradebook for this $linkId
4417
            GradebookUtils::remove_resource_from_course_gradebook($linkId);
4418
        }
4419
    }
4420
}
4421
4422
/**
4423
 * Delete all work by student.
4424
 *
4425
 * @param int   $userId
4426
 * @param array $courseInfo
4427
 *
4428
 * @return array return deleted items
4429
 */
4430
function deleteAllWorkPerUser($userId, $courseInfo)
4431
{
4432
    $deletedItems = [];
4433
    $workPerUser = getWorkPerUser($userId);
4434
    if (!empty($workPerUser)) {
4435
        foreach ($workPerUser as $work) {
4436
            $work = $work['work'];
4437
            foreach ($work->user_results as $userResult) {
4438
                $result = deleteWorkItem($userResult['id'], $courseInfo);
4439
                if ($result) {
4440
                    $deletedItems[] = $userResult;
4441
                }
4442
            }
4443
        }
4444
    }
4445
4446
    return $deletedItems;
4447
}
4448
4449
/**
4450
 * @param int $item_id
4451
 * @param array course info
4452
 *
4453
 * @return bool
4454
 */
4455
function deleteWorkItem($item_id, $courseInfo)
4456
{
4457
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
4458
    $TSTDPUBASG = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
4459
    $currentCourseRepositorySys = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/';
4460
    $is_allowed_to_edit = api_is_allowed_to_edit();
4461
    $file_deleted = false;
4462
    $item_id = intval($item_id);
4463
4464
    $is_author = user_is_author($item_id);
4465
    $work_data = get_work_data_by_id($item_id);
4466
    $locked = api_resource_is_locked_by_gradebook($work_data['parent_id'], LINK_STUDENTPUBLICATION);
4467
    $course_id = $courseInfo['real_id'];
4468
4469
    if (($is_allowed_to_edit && $locked == false) ||
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
4470
        (
4471
            $locked == false &&
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
4472
            $is_author &&
4473
            api_get_course_setting('student_delete_own_publication') == 1 &&
4474
            $work_data['qualificator_id'] == 0
4475
        )
4476
    ) {
4477
        // We found the current user is the author
4478
        $sql = "SELECT url, contains_file, user_id, session_id, parent_id 
4479
                FROM $work_table
4480
                WHERE c_id = $course_id AND id = $item_id";
4481
        $result = Database::query($sql);
4482
        $row = Database::fetch_array($result);
4483
        $count = Database::num_rows($result);
4484
4485
        if ($count > 0) {
4486
            // If the "considered_working_time" option is enabled, check
4487
            // whether some time should be removed from track_e_course_access
4488
            $consideredWorkingTime = api_get_configuration_value('considered_working_time');
4489
            if ($consideredWorkingTime) {
4490
                $userWorks = get_work_user_list(
4491
                    0,
4492
                    100,
4493
                    null,
4494
                    null,
4495
                    $row['parent_id'],
4496
                    null,
4497
                    $row['user_id'],
4498
                    false,
4499
                    $course_id,
4500
                    $row['session_id']
4501
                );
4502
                // We're only interested in deleting the time if this is the latest work sent
4503
                if (count($userWorks) == 1) {
4504
                    // Get the "considered work time" defined for this work
4505
                    $fieldValue = new ExtraFieldValue('work');
4506
                    $resultExtra = $fieldValue->getAllValuesForAnItem(
4507
                        $row['parent_id'],
4508
                        true
4509
                    );
4510
4511
                    $workingTime = null;
4512
                    foreach ($resultExtra as $field) {
4513
                        $field = $field['value'];
4514
4515
                        if ($consideredWorkingTime == $field->getField()->getVariable()) {
4516
                            $workingTime = $field->getValue();
4517
                        }
4518
                    }
4519
                    // If no time was defined, or a time of "0" was set, do nothing
4520
                    if (!empty($workingTime)) {
4521
                        $sessionId = empty($row['session_id']) ? 0 : $row['session_id'];
4522
                        // Getting false from the following call would mean the
4523
                        // time record
4524
                        Event::eventRemoveVirtualCourseTime(
4525
                            $course_id,
4526
                            $row['user_id'],
4527
                            $sessionId,
4528
                            $workingTime
4529
                        );
4530
                    }
4531
                }
4532
            } // end of considered_working_time check section
4533
4534
            $sql = "UPDATE $work_table SET active = 2
4535
                    WHERE c_id = $course_id AND id = $item_id";
4536
            Database::query($sql);
4537
            $sql = "DELETE FROM $TSTDPUBASG
4538
                    WHERE c_id = $course_id AND publication_id = $item_id";
4539
            Database::query($sql);
4540
4541
            api_item_property_update(
4542
                $courseInfo,
4543
                'work',
4544
                $item_id,
4545
                'DocumentDeleted',
4546
                api_get_user_id()
4547
            );
4548
4549
            Event::addEvent(
4550
                LOG_WORK_FILE_DELETE,
4551
                LOG_WORK_DATA,
4552
                [
4553
                    'id' => $work_data['id'],
4554
                    'url' => $work_data['url'],
4555
                    'title' => $work_data['title'],
4556
                ],
4557
                null,
4558
                api_get_user_id(),
4559
                api_get_course_int_id(),
4560
                api_get_session_id()
4561
            );
4562
4563
            $work = $row['url'];
4564
4565
            if ($row['contains_file'] == 1) {
4566
                if (!empty($work)) {
4567
                    if (api_get_setting('permanently_remove_deleted_files') === 'true') {
4568
                        my_delete($currentCourseRepositorySys.'/'.$work);
4569
                        $file_deleted = true;
4570
                    } else {
4571
                        $extension = pathinfo($work, PATHINFO_EXTENSION);
4572
                        $new_dir = $work.'_DELETED_'.$item_id.'.'.$extension;
4573
4574
                        if (file_exists($currentCourseRepositorySys.'/'.$work)) {
4575
                            rename($currentCourseRepositorySys.'/'.$work, $currentCourseRepositorySys.'/'.$new_dir);
4576
                            $file_deleted = true;
4577
                        }
4578
                    }
4579
                }
4580
            } else {
4581
                $file_deleted = true;
4582
            }
4583
        }
4584
    }
4585
4586
    return $file_deleted;
4587
}
4588
4589
/**
4590
 * @param FormValidator $form
4591
 * @param array         $defaults
4592
 * @param int           $workId
4593
 *
4594
 * @return FormValidator
4595
 */
4596
function getFormWork($form, $defaults = [], $workId = 0)
4597
{
4598
    $sessionId = api_get_session_id();
4599
    if (!empty($defaults)) {
4600
        if (isset($defaults['submit'])) {
4601
            unset($defaults['submit']);
4602
        }
4603
    }
4604
4605
    // Create the form that asks for the directory name
4606
    $form->addText('new_dir', get_lang('AssignmentName'));
4607
    $form->addHtmlEditor(
4608
        'description',
4609
        get_lang('Description'),
4610
        false,
4611
        false,
4612
        getWorkDescriptionToolbar()
4613
    );
4614
    $form->addButtonAdvancedSettings('advanced_params', get_lang('AdvancedParameters'));
4615
4616
    if (!empty($defaults) && (isset($defaults['enableEndDate']) || isset($defaults['enableExpiryDate']))) {
4617
        $form->addHtml('<div id="advanced_params_options" style="display:block">');
4618
    } else {
4619
        $form->addHtml('<div id="advanced_params_options" style="display:none">');
4620
    }
4621
4622
    // QualificationOfAssignment
4623
    $form->addElement('text', 'qualification', get_lang('QualificationNumeric'));
4624
4625
    if (($sessionId != 0 && Gradebook::is_active()) || $sessionId == 0) {
4626
        $form->addElement(
4627
            'checkbox',
4628
            'make_calification',
4629
            null,
4630
            get_lang('MakeQualifiable'),
4631
            [
4632
                'id' => 'make_calification_id',
4633
                'onclick' => "javascript: if(this.checked) { document.getElementById('option1').style.display='block';}else{document.getElementById('option1').style.display='none';}",
4634
            ]
4635
        );
4636
    } else {
4637
        // QualificationOfAssignment
4638
        $form->addElement('hidden', 'make_calification', false);
4639
    }
4640
4641
    if (!empty($defaults) && isset($defaults['category_id'])) {
4642
        $form->addHtml('<div id=\'option1\' style="display:block">');
4643
    } else {
4644
        $form->addHtml('<div id=\'option1\' style="display:none">');
4645
    }
4646
4647
    // Loading Gradebook select
4648
    GradebookUtils::load_gradebook_select_in_tool($form);
4649
4650
    $form->addElement('text', 'weight', get_lang('WeightInTheGradebook'));
4651
    $form->addHtml('</div>');
4652
4653
    $form->addElement('checkbox', 'enableExpiryDate', null, get_lang('EnableExpiryDate'), 'id="expiry_date"');
4654
    if (isset($defaults['enableExpiryDate']) && $defaults['enableExpiryDate']) {
4655
        $form->addHtml('<div id="option2" style="display: block;">');
4656
    } else {
4657
        $form->addHtml('<div id="option2" style="display: none;">');
4658
    }
4659
4660
    $timeNextWeek = time() + 86400 * 7;
4661
    $nextWeek = substr(api_get_local_time($timeNextWeek), 0, 10);
4662
    if (!isset($defaults['expires_on'])) {
4663
        $date = substr($nextWeek, 0, 10);
4664
        $defaults['expires_on'] = $date.' 23:59';
4665
    }
4666
4667
    $form->addElement('date_time_picker', 'expires_on', get_lang('ExpiresAt'));
4668
    $form->addHtml('</div>');
4669
    $form->addElement('checkbox', 'enableEndDate', null, get_lang('EnableEndDate'), 'id="end_date"');
4670
4671
    if (!isset($defaults['ends_on'])) {
4672
        $nextDay = substr(api_get_local_time($timeNextWeek + 86400), 0, 10);
4673
        $date = substr($nextDay, 0, 10);
4674
        $defaults['ends_on'] = $date.' 23:59';
4675
    }
4676
    if (isset($defaults['enableEndDate']) && $defaults['enableEndDate']) {
4677
        $form->addHtml('<div id="option3" style="display: block;">');
4678
    } else {
4679
        $form->addHtml('<div id="option3" style="display: none;">');
4680
    }
4681
4682
    $form->addElement('date_time_picker', 'ends_on', get_lang('EndsAt'));
4683
    $form->addHtml('</div>');
4684
4685
    $form->addElement('checkbox', 'add_to_calendar', null, get_lang('AddToCalendar'));
4686
    $form->addElement('select', 'allow_text_assignment', get_lang('DocumentType'), getUploadDocumentType());
4687
4688
    // Extra fields
4689
    $extraField = new ExtraField('work');
4690
    $extra = $extraField->addElements($form, $workId);
4691
4692
    $htmlHeadXtra[] = '
0 ignored issues
show
Comprehensibility Best Practice introduced by
$htmlHeadXtra was never initialized. Although not strictly required by PHP, it is generally a good practice to add $htmlHeadXtra = array(); before regardless.
Loading history...
4693
        <script>
4694
        $(function() {
4695
            '.$extra['jquery_ready_content'].'
4696
        });
4697
        </script>';
4698
4699
    $form->addHtml('</div>');
4700
4701
    $skillList = Skill::addSkillsToForm($form, ITEM_TYPE_STUDENT_PUBLICATION, $workId);
4702
4703
    if (!empty($defaults)) {
4704
        $defaults['skills'] = array_keys($skillList);
4705
        $form->setDefaults($defaults);
4706
    }
4707
4708
    return $form;
4709
}
4710
4711
/**
4712
 * @return array
4713
 */
4714
function getUploadDocumentType()
4715
{
4716
    return [
4717
        0 => get_lang('AllowFileOrText'),
4718
        1 => get_lang('AllowOnlyText'),
4719
        2 => get_lang('AllowOnlyFiles'),
4720
    ];
4721
}
4722
4723
/**
4724
 * @param array $courseInfo
4725
 * @param bool  $showScore
4726
 * @param bool  $studentDeleteOwnPublication
4727
 *
4728
 * @return bool
4729
 */
4730
function updateSettings($courseInfo, $showScore, $studentDeleteOwnPublication)
4731
{
4732
    $showScore = (int) $showScore;
4733
    $courseId = api_get_course_int_id();
4734
    $main_course_table = Database::get_main_table(TABLE_MAIN_COURSE);
4735
    $table_course_setting = Database::get_course_table(TOOL_COURSE_SETTING);
4736
4737
    if (empty($courseId)) {
4738
        return false;
4739
    }
4740
4741
    $query = "UPDATE $main_course_table
4742
              SET show_score = '$showScore'
4743
              WHERE id = $courseId";
4744
    Database::query($query);
4745
4746
    /**
4747
     * Course data are cached in session so we need to update both the database
4748
     * and the session data.
4749
     */
4750
    $courseInfo['show_score'] = $showScore;
4751
    Session::write('_course', $courseInfo);
4752
4753
    // changing the tool setting: is a student allowed to delete his/her own document
4754
    // counting the number of occurrences of this setting (if 0 => add, if 1 => update)
4755
    $query = "SELECT * FROM $table_course_setting
4756
              WHERE
4757
                c_id = $courseId AND
4758
                variable = 'student_delete_own_publication'";
4759
4760
    $result = Database::query($query);
4761
    $number_of_setting = Database::num_rows($result);
4762
4763
    if ($number_of_setting == 1) {
4764
        $query = "UPDATE $table_course_setting SET
4765
                  value = '".Database::escape_string($studentDeleteOwnPublication)."'
4766
                  WHERE variable = 'student_delete_own_publication' AND c_id = $courseId";
4767
        Database::query($query);
4768
    } else {
4769
        $params = [
4770
            'c_id' => $courseId,
4771
            'variable' => 'student_delete_own_publication',
4772
            'value' => $studentDeleteOwnPublication,
4773
            'category' => 'work',
4774
        ];
4775
        Database::insert($table_course_setting, $params);
4776
    }
4777
4778
    return true;
4779
}
4780
4781
/**
4782
 * @param int   $item_id
4783
 * @param array $course_info
4784
 *
4785
 * @return bool
4786
 */
4787
function makeVisible($item_id, $course_info)
4788
{
4789
    if (empty($course_info) || empty($item_id)) {
4790
        return false;
4791
    }
4792
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
4793
    $course_id = $course_info['real_id'];
4794
    $item_id = intval($item_id);
4795
4796
    $sql = "UPDATE $work_table SET accepted = 1
4797
            WHERE c_id = $course_id AND id = $item_id";
4798
    Database::query($sql);
4799
    api_item_property_update($course_info, 'work', $item_id, 'visible', api_get_user_id());
4800
4801
    return true;
4802
}
4803
4804
/**
4805
 * @param int   $item_id
4806
 * @param array $course_info
4807
 *
4808
 * @return int
4809
 */
4810
function makeInvisible($item_id, $course_info)
4811
{
4812
    if (empty($course_info) || empty($item_id)) {
4813
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
4814
    }
4815
4816
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
4817
    $item_id = intval($item_id);
4818
    $course_id = $course_info['real_id'];
4819
    $sql = "UPDATE $table
4820
            SET accepted = 0
4821
            WHERE c_id = $course_id AND id = '".$item_id."'";
4822
    Database::query($sql);
4823
    api_item_property_update(
4824
        $course_info,
4825
        'work',
4826
        $item_id,
4827
        'invisible',
4828
        api_get_user_id()
4829
    );
4830
4831
    return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the documented return type integer.
Loading history...
4832
}
4833
4834
/**
4835
 * @param int    $item_id
4836
 * @param string $path
4837
 * @param array  $courseInfo
4838
 * @param int    $groupId    iid
4839
 * @param int    $sessionId
4840
 *
4841
 * @return string
4842
 */
4843
function generateMoveForm($item_id, $path, $courseInfo, $groupId, $sessionId)
4844
{
4845
    $work_table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
4846
    $courseId = $courseInfo['real_id'];
4847
    $folders = [];
4848
    $session_id = intval($sessionId);
4849
    $groupId = intval($groupId);
4850
    $sessionCondition = empty($sessionId) ? " AND (session_id = 0 OR session_id IS NULL) " : " AND session_id='".$session_id."'";
4851
4852
    $groupIid = 0;
4853
    if ($groupId) {
4854
        $groupInfo = GroupManager::get_group_properties($groupId);
4855
        $groupIid = $groupInfo['iid'];
4856
    }
4857
4858
    $sql = "SELECT id, url, title
4859
            FROM $work_table
4860
            WHERE
4861
                c_id = $courseId AND
4862
                active IN (0, 1) AND
4863
                url LIKE '/%' AND
4864
                post_group_id = $groupIid
4865
                $sessionCondition";
4866
    $res = Database::query($sql);
4867
    while ($folder = Database::fetch_array($res)) {
4868
        $title = empty($folder['title']) ? basename($folder['url']) : $folder['title'];
4869
        $folders[$folder['id']] = $title;
4870
    }
4871
4872
    return build_work_move_to_selector($folders, $path, $item_id);
4873
}
4874
4875
/**
4876
 * @param int $workId
4877
 *
4878
 * @return string
4879
 */
4880
function showStudentList($workId)
4881
{
4882
    $columnModel = [
4883
        [
4884
            'name' => 'student',
4885
            'index' => 'student',
4886
            'width' => '350px',
4887
            'align' => 'left',
4888
            'sortable' => 'false',
4889
        ],
4890
        [
4891
            'name' => 'works',
4892
            'index' => 'works',
4893
            'align' => 'center',
4894
            'sortable' => 'false',
4895
        ],
4896
    ];
4897
    $token = null;
4898
    $url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_work_student_list_overview&work_id='.$workId.'&'.api_get_cidreq();
4899
4900
    $columns = [
4901
        get_lang('Students'),
4902
        get_lang('Works'),
4903
    ];
4904
4905
    $order = api_is_western_name_order() ? 'firstname' : 'lastname';
4906
    $params = [
4907
        'autowidth' => 'true',
4908
        'height' => 'auto',
4909
        'rowNum' => 5,
4910
        'sortname' => $order,
4911
        'sortorder' => 'asc',
4912
    ];
4913
4914
    $html = '<script>
4915
    $(function() {
4916
        '.Display::grid_js('studentList', $url, $columns, $columnModel, $params, [], null, true).'
4917
        $("#workList").jqGrid(
4918
            "navGrid",
4919
            "#studentList_pager",
4920
            { edit: false, add: false, del: false },
4921
            { height:280, reloadAfterSubmit:false }, // edit options
4922
            { height:280, reloadAfterSubmit:false }, // add options
4923
            { width:500 } // search options
4924
        );
4925
    });
4926
    </script>';
4927
    $html .= Display::grid_html('studentList');
4928
4929
    return $html;
4930
}
4931
4932
/**
4933
 * @param string $courseCode
4934
 * @param int    $sessionId
4935
 * @param int    $groupId
4936
 * @param int    $start
4937
 * @param int    $limit
4938
 * @param string $sidx
4939
 * @param string $sord
4940
 * @param $getCount
4941
 *
4942
 * @return array|int
4943
 */
4944
function getWorkUserList($courseCode, $sessionId, $groupId, $start, $limit, $sidx, $sord, $getCount = false)
4945
{
4946
    if (!empty($groupId)) {
4947
        $userList = GroupManager::get_users(
4948
            $groupId,
4949
            false,
4950
            $start,
4951
            $limit,
4952
            $getCount,
4953
            null,
4954
            $sidx,
4955
            $sord
4956
        );
4957
    } else {
4958
        $limitString = null;
4959
        if (!empty($start) && !empty($limit)) {
4960
            $start = intval($start);
4961
            $limit = intval($limit);
4962
            $limitString = " LIMIT $start, $limit";
4963
        }
4964
4965
        $orderBy = null;
4966
4967
        if (!empty($sidx) && !empty($sord)) {
4968
            if (in_array($sidx, ['firstname', 'lastname'])) {
4969
                $orderBy = "ORDER BY $sidx $sord";
4970
            }
4971
        }
4972
4973
        if (empty($sessionId)) {
4974
            $userList = CourseManager::get_user_list_from_course_code(
4975
                $courseCode,
4976
                $sessionId,
4977
                $limitString,
4978
                $orderBy,
4979
                STUDENT,
4980
                $getCount
4981
            );
4982
        } else {
4983
            $userList = CourseManager::get_user_list_from_course_code(
4984
                $courseCode,
4985
                $sessionId,
4986
                $limitString,
4987
                $orderBy,
4988
                0,
4989
                $getCount
4990
            );
4991
        }
4992
4993
        if ($getCount == false) {
4994
            $userList = array_keys($userList);
0 ignored issues
show
Bug introduced by
It seems like $userList can also be of type integer; however, parameter $input of array_keys() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

4994
            $userList = array_keys(/** @scrutinizer ignore-type */ $userList);
Loading history...
4995
        }
4996
    }
4997
4998
    return $userList;
4999
}
5000
5001
/**
5002
 * @param int    $workId
5003
 * @param string $courseCode
5004
 * @param int    $sessionId
5005
 * @param int    $groupId
5006
 * @param int    $start
5007
 * @param int    $limit
5008
 * @param int    $sidx
5009
 * @param string $sord
5010
 * @param bool   $getCount
5011
 *
5012
 * @return array|int
5013
 */
5014
function getWorkUserListData(
5015
    $workId,
5016
    $courseCode,
5017
    $sessionId,
5018
    $groupId,
5019
    $start,
5020
    $limit,
5021
    $sidx,
5022
    $sord,
5023
    $getCount = false
5024
) {
5025
    $my_folder_data = get_work_data_by_id($workId);
5026
    $workParents = [];
5027
    if (empty($my_folder_data)) {
5028
        $workParents = getWorkList($workId, $my_folder_data, null);
5029
    }
5030
5031
    $workIdList = [];
5032
    if (!empty($workParents)) {
5033
        foreach ($workParents as $work) {
5034
            $workIdList[] = $work->id;
5035
        }
5036
    }
5037
5038
    $courseInfo = api_get_course_info($courseCode);
5039
5040
    $userList = getWorkUserList(
5041
        $courseCode,
5042
        $sessionId,
5043
        $groupId,
5044
        $start,
5045
        $limit,
5046
        $sidx,
5047
        $sord,
5048
        $getCount
5049
    );
5050
5051
    if ($getCount) {
5052
        return $userList;
5053
    }
5054
    $results = [];
5055
    if (!empty($userList)) {
5056
        foreach ($userList as $userId) {
5057
            $user = api_get_user_info($userId);
5058
            $link = api_get_path(WEB_CODE_PATH).'work/student_work.php?'.api_get_cidreq().'&studentId='.$user['user_id'];
5059
            $url = Display::url(api_get_person_name($user['firstname'], $user['lastname']), $link);
5060
            $userWorks = 0;
5061
            if (!empty($workIdList)) {
5062
                $userWorks = getUniqueStudentAttempts(
5063
                    $workIdList,
5064
                    $groupId,
5065
                    $courseInfo['real_id'],
5066
                    $sessionId,
5067
                    $user['user_id']
5068
                );
5069
            }
5070
            $works = $userWorks." / ".count($workParents);
5071
            $results[] = [
5072
                'student' => $url,
5073
                'works' => Display::url($works, $link),
5074
            ];
5075
        }
5076
    }
5077
5078
    return $results;
5079
}
5080
5081
/**
5082
 * @param int   $id
5083
 * @param array $course_info
5084
 * @param bool  $isCorrection
5085
 *
5086
 * @return bool
5087
 */
5088
function downloadFile($id, $course_info, $isCorrection)
5089
{
5090
    return getFile($id, $course_info, true, $isCorrection);
5091
}
5092
5093
/**
5094
 * @param int   $id
5095
 * @param array $course_info
5096
 * @param bool  $download
5097
 * @param bool  $isCorrection
5098
 *
5099
 * @return bool
5100
 */
5101
function getFile($id, $course_info, $download = true, $isCorrection = false)
5102
{
5103
    $file = getFileContents($id, $course_info, 0, $isCorrection);
5104
    if (!empty($file) && is_array($file)) {
5105
        return DocumentManager::file_send_for_download(
5106
            $file['path'],
5107
            $download,
5108
            $file['title']
5109
        );
5110
    }
5111
5112
    return false;
5113
}
5114
5115
/**
5116
 * Get the file contents for an assigment.
5117
 *
5118
 * @param int   $id
5119
 * @param array $course_info
5120
 * @param int Session ID
5121
 * @param $correction
5122
 *
5123
 * @return array|bool
5124
 */
5125
function getFileContents($id, $course_info, $sessionId = 0, $correction = false)
5126
{
5127
    $id = intval($id);
5128
    if (empty($course_info) || empty($id)) {
5129
        return false;
5130
    }
5131
    if (empty($sessionId)) {
5132
        $sessionId = api_get_session_id();
5133
    }
5134
5135
    $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
5136
    if (!empty($course_info['real_id'])) {
5137
        $sql = 'SELECT *
5138
                FROM '.$table.'
5139
                WHERE c_id = '.$course_info['real_id'].' AND id = "'.$id.'"';
5140
        $result = Database::query($sql);
5141
        if ($result && Database::num_rows($result)) {
5142
            $row = Database::fetch_array($result, 'ASSOC');
5143
5144
            if ($correction) {
5145
                $row['url'] = $row['url_correction'];
5146
            }
5147
5148
            if (empty($row['url'])) {
5149
                return false;
5150
            }
5151
5152
            $full_file_name = api_get_path(SYS_COURSE_PATH).api_get_course_path().'/'.$row['url'];
5153
5154
            $item_info = api_get_item_property_info(
5155
                api_get_course_int_id(),
5156
                'work',
5157
                $row['id'],
5158
                $sessionId
5159
            );
5160
5161
            if (empty($item_info)) {
5162
                return false;
5163
            }
5164
5165
            allowOnlySubscribedUser(
5166
                api_get_user_id(),
5167
                $row['parent_id'],
5168
                $course_info['real_id']
5169
            );
5170
5171
            /*
5172
            field show_score in table course :
5173
                0 =>    New documents are visible for all users
5174
                1 =>    New documents are only visible for the teacher(s)
5175
            field visibility in table item_property :
5176
                0 => eye closed, invisible for all students
5177
                1 => eye open
5178
            field accepted in table c_student_publication :
5179
                0 => eye closed, invisible for all students
5180
                1 => eye open
5181
            ( We should have visibility == accepted, otherwise there is an
5182
            inconsistency in the Database)
5183
            field value in table c_course_setting :
5184
                0 => Allow learners to delete their own publications = NO
5185
                1 => Allow learners to delete their own publications = YES
5186
5187
            +------------------+-------------------------+------------------------+
5188
            |Can download work?| doc visible for all = 0 | doc visible for all = 1|
5189
            +------------------+-------------------------+------------------------+
5190
            |  visibility = 0  | editor only             | editor only            |
5191
            |                  |                         |                        |
5192
            +------------------+-------------------------+------------------------+
5193
            |  visibility = 1  | editor                  | editor                 |
5194
            |                  | + owner of the work     | + any student          |
5195
            +------------------+-------------------------+------------------------+
5196
            (editor = teacher + admin + anybody with right api_is_allowed_to_edit)
5197
            */
5198
5199
            $work_is_visible = $item_info['visibility'] == 1 && $row['accepted'] == 1;
5200
            $doc_visible_for_all = $course_info['show_score'] == 1;
5201
5202
            $is_editor = api_is_allowed_to_edit(true, true, true);
5203
            $student_is_owner_of_work = user_is_author($row['id'], $row['user_id']);
5204
5205
            if ($is_editor ||
5206
                $student_is_owner_of_work ||
5207
                ($doc_visible_for_all && $work_is_visible)
5208
            ) {
5209
                $title = $row['title'];
5210
                if ($correction) {
5211
                    $title = $row['title_correction'];
5212
                }
5213
                if (array_key_exists('filename', $row) && !empty($row['filename'])) {
5214
                    $title = $row['filename'];
5215
                }
5216
5217
                $title = str_replace(' ', '_', $title);
5218
5219
                if ($correction == false) {
5220
                    $userInfo = api_get_user_info($row['user_id']);
5221
                    if ($userInfo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $userInfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
5222
                        $date = api_get_local_time($row['sent_date']);
5223
                        $date = str_replace([':', '-', ' '], '_', $date);
5224
                        $title = $date.'_'.$userInfo['username'].'_'.$title;
5225
                    }
5226
                }
5227
5228
                if (Security::check_abs_path(
5229
                    $full_file_name,
5230
                    api_get_path(SYS_COURSE_PATH).api_get_course_path().'/'
5231
                )) {
5232
                    Event::event_download($title);
5233
5234
                    return [
5235
                        'path' => $full_file_name,
5236
                        'title' => $title,
5237
                        'title_correction' => $row['title_correction'],
5238
                    ];
5239
                }
5240
            }
5241
        }
5242
    }
5243
5244
    return false;
5245
}
5246
5247
/**
5248
 * @param int    $userId
5249
 * @param array  $courseInfo
5250
 * @param string $format
5251
 *
5252
 * @return bool
5253
 */
5254
function exportAllWork($userId, $courseInfo, $format = 'pdf')
5255
{
5256
    $userInfo = api_get_user_info($userId);
5257
    if (empty($userInfo) || empty($courseInfo)) {
5258
        return false;
5259
    }
5260
5261
    $workPerUser = getWorkPerUser($userId);
5262
5263
    switch ($format) {
5264
        case 'pdf':
5265
            if (!empty($workPerUser)) {
5266
                $pdf = new PDF();
5267
5268
                $content = null;
5269
                foreach ($workPerUser as $work) {
5270
                    $work = $work['work'];
5271
                    foreach ($work->user_results as $userResult) {
5272
                        $content .= $userResult['title'];
5273
                        // No need to use api_get_local_time()
5274
                        $content .= $userResult['sent_date'];
5275
                        $content .= $userResult['qualification'];
5276
                        $content .= $userResult['description'];
5277
                    }
5278
                }
5279
5280
                if (!empty($content)) {
5281
                    $pdf->content_to_pdf(
5282
                        $content,
5283
                        null,
5284
                        api_replace_dangerous_char($userInfo['complete_name']),
5285
                        $courseInfo['code']
5286
                    );
5287
                }
5288
            }
5289
            break;
5290
    }
5291
}
5292
5293
/**
5294
 * @param int    $workId
5295
 * @param array  $courseInfo
5296
 * @param int    $sessionId
5297
 * @param string $format
5298
 *
5299
 * @return bool
5300
 */
5301
function exportAllStudentWorkFromPublication(
5302
    $workId,
5303
    $courseInfo,
5304
    $sessionId,
5305
    $format = 'pdf'
5306
) {
5307
    if (empty($courseInfo)) {
5308
        return false;
5309
    }
5310
5311
    $workData = get_work_data_by_id($workId);
5312
    if (empty($workData)) {
5313
        return false;
5314
    }
5315
5316
    $assignment = get_work_assignment_by_id($workId);
5317
5318
    $courseCode = $courseInfo['code'];
5319
    $header = get_lang('Course').': '.$courseInfo['title'];
5320
    $teachers = CourseManager::getTeacherListFromCourseCodeToString(
5321
        $courseCode
5322
    );
5323
5324
    if (!empty($sessionId)) {
5325
        $sessionInfo = api_get_session_info($sessionId);
5326
        if (!empty($sessionInfo)) {
5327
            $header .= ' - '.$sessionInfo['name'];
5328
            $header .= '<br />'.$sessionInfo['description'];
5329
            $teachers = SessionManager::getCoachesByCourseSessionToString(
5330
                $sessionId,
5331
                $courseInfo['real_id']
5332
            );
5333
        }
5334
    }
5335
5336
    $header .= '<br />'.get_lang('Teachers').': '.$teachers.'<br />';
5337
    $header .= '<br />'.get_lang('Date').': '.api_get_local_time().'<br />';
5338
    $header .= '<br />'.get_lang('WorkName').': '.$workData['title'].'<br />';
5339
5340
    $content = null;
5341
    $expiresOn = null;
5342
5343
    if (!empty($assignment) && isset($assignment['expires_on'])) {
5344
        $content .= '<br /><strong>'.get_lang('ExpirationDate').'</strong>: '.api_get_local_time($assignment['expires_on']);
5345
        $expiresOn = api_get_local_time($assignment['expires_on']);
5346
    }
5347
5348
    if (!empty($workData['description'])) {
5349
        $content .= '<br /><strong>'.get_lang('Description').'</strong>: '.$workData['description'];
5350
    }
5351
5352
    $workList = get_work_user_list(null, null, null, null, $workId);
5353
5354
    switch ($format) {
5355
        case 'pdf':
5356
            if (!empty($workList)) {
5357
                $table = new HTML_Table(['class' => 'data_table']);
5358
                $headers = [
5359
                    get_lang('Name'),
5360
                    get_lang('User'),
5361
                    get_lang('HandOutDateLimit'),
5362
                    get_lang('SentDate'),
5363
                    get_lang('FileName'),
5364
                    get_lang('Score'),
5365
                    get_lang('Feedback'),
5366
                ];
5367
5368
                $column = 0;
5369
                foreach ($headers as $header) {
5370
                    $table->setHeaderContents(0, $column, $header);
5371
                    $column++;
5372
                }
5373
5374
                $row = 1;
5375
5376
                //$pdf->set_custom_header($header);
5377
                foreach ($workList as $work) {
5378
                    $content .= '<hr />';
5379
                    // getWorkComments need c_id
5380
                    $work['c_id'] = $courseInfo['real_id'];
5381
5382
                    //$content .= get_lang('Date').': '.api_get_local_time($work['sent_date_from_db']).'<br />';
5383
                    $score = null;
5384
                    if (!empty($work['qualification_only'])) {
5385
                        $score = $work['qualification_only'];
5386
                    }
5387
5388
                    $comments = getWorkComments($work);
5389
5390
                    $feedback = null;
5391
                    if (!empty($comments)) {
5392
                        $content .= '<h4>'.get_lang('Feedback').': </h4>';
5393
                        foreach ($comments as $comment) {
5394
                            $feedback .= get_lang('User').': '.$comment['complete_name'].
5395
                                '<br />';
5396
                            $feedback .= $comment['comment'].'<br />';
5397
                        }
5398
                    }
5399
                    $table->setCellContents($row, 0, strip_tags($workData['title']));
5400
                    $table->setCellContents($row, 1, strip_tags($work['fullname']));
5401
                    $table->setCellContents($row, 2, $expiresOn);
5402
                    $table->setCellContents($row, 3, api_get_local_time($work['sent_date_from_db']));
5403
                    $table->setCellContents($row, 4, strip_tags($work['title']));
5404
                    $table->setCellContents($row, 5, $score);
5405
                    $table->setCellContents($row, 6, $feedback);
5406
5407
                    $row++;
5408
                }
5409
5410
                $content = $table->toHtml();
5411
5412
                if (!empty($content)) {
5413
                    $params = [
5414
                        'filename' => $workData['title'].'_'.api_get_local_time(),
5415
                        'pdf_title' => api_replace_dangerous_char($workData['title']),
5416
                        'course_code' => $courseInfo['code'],
5417
                    ];
5418
                    $pdf = new PDF('A4', null, $params);
5419
                    $pdf->html_to_pdf_with_template($content);
5420
                }
5421
                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...
5422
            }
5423
            break;
5424
    }
5425
}
5426
5427
/**
5428
 * Downloads all user files per user.
5429
 *
5430
 * @param int   $userId
5431
 * @param array $courseInfo
5432
 *
5433
 * @return bool
5434
 */
5435
function downloadAllFilesPerUser($userId, $courseInfo)
5436
{
5437
    $userInfo = api_get_user_info($userId);
5438
5439
    if (empty($userInfo) || empty($courseInfo)) {
5440
        return false;
5441
    }
5442
5443
    $tempZipFile = api_get_path(SYS_ARCHIVE_PATH).api_get_unique_id().".zip";
5444
    $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/work/';
5445
    $zip = new PclZip($tempZipFile);
5446
    $workPerUser = getWorkPerUser($userId);
5447
5448
    if (!empty($workPerUser)) {
5449
        $files = [];
5450
        foreach ($workPerUser as $work) {
5451
            $work = $work['work'];
5452
            foreach ($work->user_results as $userResult) {
5453
                if (empty($userResult['url']) || empty($userResult['contains_file'])) {
5454
                    continue;
5455
                }
5456
                $data = getFileContents($userResult['id'], $courseInfo);
5457
                if (!empty($data) && isset($data['path'])) {
5458
                    $files[basename($data['path'])] = [
5459
                        'title' => $data['title'],
5460
                        'path' => $data['path'],
5461
                    ];
5462
                }
5463
            }
5464
        }
5465
5466
        if (!empty($files)) {
5467
            Session::write('files', $files);
5468
            foreach ($files as $data) {
5469
                $zip->add(
5470
                    $data['path'],
5471
                    PCLZIP_OPT_REMOVE_PATH,
5472
                    $coursePath,
5473
                    PCLZIP_CB_PRE_ADD,
5474
                    'preAddAllWorkStudentCallback'
5475
                );
5476
            }
5477
        }
5478
5479
        // Start download of created file
5480
        $name = basename(api_replace_dangerous_char($userInfo['complete_name'])).'.zip';
5481
        Event::event_download($name.'.zip (folder)');
5482
        if (Security::check_abs_path($tempZipFile, api_get_path(SYS_ARCHIVE_PATH))) {
5483
            DocumentManager::file_send_for_download($tempZipFile, true, $name);
5484
            @unlink($tempZipFile);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

5484
            /** @scrutinizer ignore-unhandled */ @unlink($tempZipFile);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
5485
            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...
5486
        }
5487
    }
5488
    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...
5489
}
5490
5491
/**
5492
 * @param $p_event
5493
 * @param array $p_header
5494
 *
5495
 * @return int
5496
 */
5497
function preAddAllWorkStudentCallback($p_event, &$p_header)
0 ignored issues
show
Unused Code introduced by
The parameter $p_event is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

5497
function preAddAllWorkStudentCallback(/** @scrutinizer ignore-unused */ $p_event, &$p_header)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
5498
{
5499
    $files = Session::read('files');
5500
    if (isset($files[basename($p_header['stored_filename'])])) {
5501
        $p_header['stored_filename'] = $files[basename($p_header['stored_filename'])]['title'];
5502
5503
        return 1;
5504
    }
5505
5506
    return 0;
5507
}
5508
5509
/**
5510
 * Get all work created by a user.
5511
 *
5512
 * @param int $user_id
5513
 * @param int $courseId
5514
 * @param int $sessionId
5515
 *
5516
 * @return array
5517
 */
5518
function getWorkCreatedByUser($user_id, $courseId, $sessionId)
5519
{
5520
    $items = api_get_item_property_list_by_tool_by_user(
5521
        $user_id,
5522
        'work',
5523
        $courseId,
5524
        $sessionId
5525
    );
5526
5527
    $list = [];
5528
    if (!empty($items)) {
5529
        foreach ($items as $work) {
5530
            $item = get_work_data_by_id(
5531
                $work['ref'],
5532
                $courseId,
5533
                $sessionId
5534
            );
5535
            if (!empty($item)) {
5536
                $list[] = [
5537
                    $item['title'],
5538
                    api_get_local_time($work['insert_date']),
5539
                    api_get_local_time($work['lastedit_date']),
5540
                ];
5541
            }
5542
        }
5543
    }
5544
5545
    return $list;
5546
}
5547
5548
/**
5549
 * @param array $courseInfo
5550
 * @param int   $workId
5551
 *
5552
 * @return bool
5553
 */
5554
function protectWork($courseInfo, $workId)
5555
{
5556
    $userId = api_get_user_id();
5557
    $groupId = api_get_group_id();
5558
    $sessionId = api_get_session_id();
5559
    $workData = get_work_data_by_id($workId);
5560
5561
    if (empty($workData) || empty($courseInfo)) {
5562
        api_not_allowed(true);
5563
    }
5564
5565
    if (api_is_platform_admin() || api_is_allowed_to_edit()) {
5566
        return true;
5567
    }
5568
5569
    $workId = $workData['id'];
5570
5571
    if ($workData['active'] != 1) {
5572
        api_not_allowed(true);
5573
    }
5574
5575
    $visibility = api_get_item_visibility($courseInfo, 'work', $workId, $sessionId);
5576
5577
    if ($visibility != 1) {
5578
        api_not_allowed(true);
5579
    }
5580
5581
    allowOnlySubscribedUser($userId, $workId, $courseInfo['real_id']);
5582
    $groupInfo = GroupManager::get_group_properties($groupId);
5583
5584
    if (!empty($groupId)) {
5585
        $showWork = GroupManager::user_has_access(
5586
            $userId,
5587
            $groupInfo['iid'],
5588
            GroupManager::GROUP_TOOL_WORK
5589
        );
5590
        if (!$showWork) {
5591
            api_not_allowed(true);
5592
        }
5593
    }
5594
}
5595
5596
/**
5597
 * @param array $courseInfo
5598
 * @param array $work
5599
 */
5600
function deleteCorrection($courseInfo, $work)
5601
{
5602
    if (isset($work['url_correction']) && !empty($work['url_correction']) && isset($work['iid'])) {
5603
        $id = $work['iid'];
5604
        $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
5605
        $sql = "UPDATE $table SET
5606
                    url_correction = '',
5607
                    title_correction = ''
5608
                WHERE iid = $id";
5609
        Database::query($sql);
5610
        $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/';
5611
        if (file_exists($coursePath.$work['url_correction'])) {
5612
            if (Security::check_abs_path($coursePath.$work['url_correction'], $coursePath)) {
5613
                unlink($coursePath.$work['url_correction']);
5614
            }
5615
        }
5616
    }
5617
}
5618
5619
/**
5620
 * @param int $workId
5621
 *
5622
 * @return string
5623
 */
5624
function workGetExtraFieldData($workId)
5625
{
5626
    $sessionField = new ExtraField('work');
5627
    $extraFieldData = $sessionField->getDataAndFormattedValues($workId);
5628
    $result = '';
5629
    if (!empty($extraFieldData)) {
5630
        $result .= '<div class="well">';
5631
        foreach ($extraFieldData as $data) {
5632
            $result .= $data['text'].': <b>'.$data['value'].'</b>';
5633
        }
5634
        $result .= '</div>';
5635
    }
5636
5637
    return $result;
5638
}
5639