lib.php 148 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?PHP

// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17

moodler's avatar
moodler committed
18
19
20
21
/**
 * assignment_base is the base class for assignment types
 *
 * This class provides all the functionality for an assignment
22
 *
23
 * @package   mod-assignment
24
25
 * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
moodler's avatar
moodler committed
26
 */
27

28
/** Include eventslib.php */
29
require_once($CFG->libdir.'/eventslib.php');
30
/** Include formslib.php */
31
require_once($CFG->libdir.'/formslib.php');
32
33
/** Include calendar/lib.php */
require_once($CFG->dirroot.'/calendar/lib.php');
34

35
/** ASSIGNMENT_COUNT_WORDS = 1 */
Petr Skoda's avatar
Petr Skoda committed
36
define('ASSIGNMENT_COUNT_WORDS', 1);
37
/** ASSIGNMENT_COUNT_LETTERS = 2 */
Petr Skoda's avatar
Petr Skoda committed
38
define('ASSIGNMENT_COUNT_LETTERS', 2);
39

40
/**
moodler's avatar
moodler committed
41
 * Standard base class for all assignment submodules (assignment types).
42
 *
43
 * @package   mod-assignment
44
45
 * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
moodler's avatar
moodler committed
46
47
48
 */
class assignment_base {

49
50
51
52
    const FILTER_ALL             = 0;
    const FILTER_SUBMITTED       = 1;
    const FILTER_REQUIRE_GRADING = 2;

53
    /** @var object */
moodler's avatar
moodler committed
54
    var $cm;
55
    /** @var object */
moodler's avatar
moodler committed
56
    var $course;
57
58
    /** @var stdClass */
    var $coursecontext;
59
    /** @var object */
moodler's avatar
moodler committed
60
    var $assignment;
61
    /** @var string */
62
    var $strassignment;
63
    /** @var string */
64
    var $strassignments;
65
    /** @var string */
66
    var $strsubmissions;
67
    /** @var string */
68
    var $strlastmodified;
69
    /** @var string */
70
    var $pagetitle;
71
    /** @var bool */
72
    var $usehtmleditor;
73
74
75
    /**
     * @todo document this var
     */
76
    var $defaultformat;
77
78
79
    /**
     * @todo document this var
     */
80
    var $context;
81
    /** @var string */
82
    var $type;
moodler's avatar
moodler committed
83
84
85
86
87
88

    /**
     * Constructor for the base assignment class
     *
     * Constructor for the base assignment class.
     * If cmid is set create the cm, course, assignment objects.
89
90
     * If the assignment is hidden and the user is not a teacher then
     * this prints a page header and notice.
moodler's avatar
moodler committed
91
     *
92
93
94
95
96
97
     * @global object
     * @global object
     * @param int $cmid the current course module id - not set for new assignments
     * @param object $assignment usually null, but if we have it we pass it to save db access
     * @param object $cm usually null, but if we have it we pass it to save db access
     * @param object $course usually null, but if we have it we pass it to save db access
moodler's avatar
moodler committed
98
     */
99
    function assignment_base($cmid='staticonly', $assignment=NULL, $cm=NULL, $course=NULL) {
100
        global $COURSE, $DB;
101

102
103
104
105
        if ($cmid == 'staticonly') {
            //use static functions only!
            return;
        }
moodler's avatar
moodler committed
106
107
108

        global $CFG;

109
110
111
        if ($cm) {
            $this->cm = $cm;
        } else if (! $this->cm = get_coursemodule_from_id('assignment', $cmid)) {
dongsheng's avatar
dongsheng committed
112
            print_error('invalidcoursemodule');
113
        }
114

115
        $this->context = get_context_instance(CONTEXT_MODULE, $this->cm->id);
116

117
118
        if ($course) {
            $this->course = $course;
119
120
        } else if ($this->cm->course == $COURSE->id) {
            $this->course = $COURSE;
121
        } else if (! $this->course = $DB->get_record('course', array('id'=>$this->cm->course))) {
dongsheng's avatar
dongsheng committed
122
            print_error('invalidid', 'assignment');
123
        }
124
        $this->coursecontext = get_context_instance(CONTEXT_COURSE, $this->course->id);
125
        $courseshortname = format_text($this->course->shortname, true, array('context' => $this->coursecontext));
126

127
128
        if ($assignment) {
            $this->assignment = $assignment;
129
        } else if (! $this->assignment = $DB->get_record('assignment', array('id'=>$this->cm->instance))) {
dongsheng's avatar
dongsheng committed
130
            print_error('invalidid', 'assignment');
131
132
        }

133
        $this->assignment->cmidnumber = $this->cm->idnumber; // compatibility with modedit assignment obj
134
        $this->assignment->courseid   = $this->course->id; // compatibility with modedit assignment obj
moodler's avatar
   
moodler committed
135

136
137
138
139
        $this->strassignment = get_string('modulename', 'assignment');
        $this->strassignments = get_string('modulenameplural', 'assignment');
        $this->strsubmissions = get_string('submissions', 'assignment');
        $this->strlastmodified = get_string('lastmodified');
140
        $this->pagetitle = strip_tags($courseshortname.': '.$this->strassignment.': '.format_string($this->assignment->name, true, array('context' => $this->context)));
141

142
143
        // visibility handled by require_login() with $cm parameter
        // get current group only when really needed
moodler's avatar
   
moodler committed
144

145
    /// Set up things for a HTML editor if it's needed
146
        $this->defaultformat = editors_get_preferred_format();
moodler's avatar
   
moodler committed
147
148
    }

149
150
151
152
    /**
     * Display the assignment, used by view.php
     *
     * This in turn calls the methods producing individual parts of the page
moodler's avatar
moodler committed
153
     */
154
    function view() {
155

moodler's avatar
moodler committed
156
        $context = get_context_instance(CONTEXT_MODULE,$this->cm->id);
moodler's avatar
moodler committed
157
        require_capability('mod/assignment:view', $context);
158
159

        add_to_log($this->course->id, "assignment", "view", "view.php?id={$this->cm->id}",
moodler's avatar
moodler committed
160
                   $this->assignment->id, $this->cm->id);
161

162
        $this->view_header();
163

moodler's avatar
moodler committed
164
        $this->view_intro();
165

moodler's avatar
moodler committed
166
        $this->view_dates();
167

moodler's avatar
moodler committed
168
169
        $this->view_feedback();

moodler's avatar
moodler committed
170
        $this->view_footer();
171
172
    }

173
174
175
176
177
178
179
180
    /**
     * Display the header and top of a page
     *
     * (this doesn't change much for assignment types)
     * This is used by the view() method to print the header of view.php but
     * it can be used on other pages in which case the string to denote the
     * page in the navigation trail should be passed as an argument
     *
181
182
     * @global object
     * @param string $subpage Description of subpage to be used in navigation trail
183
184
     */
    function view_header($subpage='') {
185
        global $CFG, $PAGE, $OUTPUT;
186

187
        if ($subpage) {
188
            $PAGE->navbar->add($subpage);
189
        }
190

191
192
193
194
        $PAGE->set_title($this->pagetitle);
        $PAGE->set_heading($this->course->fullname);

        echo $OUTPUT->header();
195

196
        groups_print_activity_menu($this->cm, $CFG->wwwroot . '/mod/assignment/view.php?id=' . $this->cm->id);
197

198
        echo '<div class="reportlink">'.$this->submittedlink().'</div>';
199
        echo '<div class="clearer"></div>';
200
201
202
    }


203
    /**
moodler's avatar
moodler committed
204
     * Display the assignment intro
205
206
207
     *
     * This will most likely be extended by assignment type plug-ins
     * The default implementation prints the assignment description in a box
moodler's avatar
moodler committed
208
209
     */
    function view_intro() {
210
211
        global $OUTPUT;
        echo $OUTPUT->box_start('generalbox boxaligncenter', 'intro');
212
        echo format_module_intro('assignment', $this->assignment, $this->cm->id);
213
        echo $OUTPUT->box_end();
214
        plagiarism_print_disclosure($this->cm->id);
moodler's avatar
moodler committed
215
216
    }

217
    /**
moodler's avatar
moodler committed
218
     * Display the assignment dates
219
220
221
     *
     * Prints the assignment start and end dates in a box.
     * This will be suitable for most assignment types
moodler's avatar
moodler committed
222
223
     */
    function view_dates() {
224
        global $OUTPUT;
moodler's avatar
moodler committed
225
226
227
228
        if (!$this->assignment->timeavailable && !$this->assignment->timedue) {
            return;
        }

229
        echo $OUTPUT->box_start('generalbox boxaligncenter', 'dates');
moodler's avatar
moodler committed
230
231
232
233
234
235
236
237
238
239
        echo '<table>';
        if ($this->assignment->timeavailable) {
            echo '<tr><td class="c0">'.get_string('availabledate','assignment').':</td>';
            echo '    <td class="c1">'.userdate($this->assignment->timeavailable).'</td></tr>';
        }
        if ($this->assignment->timedue) {
            echo '<tr><td class="c0">'.get_string('duedate','assignment').':</td>';
            echo '    <td class="c1">'.userdate($this->assignment->timedue).'</td></tr>';
        }
        echo '</table>';
240
        echo $OUTPUT->box_end();
moodler's avatar
moodler committed
241
242
243
    }


244
245
246
247
248
    /**
     * Display the bottom and footer of a page
     *
     * This default method just prints the footer.
     * This will be suitable for most assignment types
249
250
     */
    function view_footer() {
251
252
        global $OUTPUT;
        echo $OUTPUT->footer();
253
254
    }

255
256
257
258
    /**
     * Display the feedback to the student
     *
     * This default method prints the teacher picture and name, date when marked,
259
     * grade and teacher submissioncomment.
260
     *
261
262
263
264
     * @global object
     * @global object
     * @global object
     * @param object $submission The submission object or NULL in which case it will be loaded
265
     */
266
    function view_feedback($submission=NULL) {
267
        global $USER, $CFG, $DB, $OUTPUT;
268
269
        require_once($CFG->libdir.'/gradelib.php');

270
        if (!is_enrolled($this->context, $USER, 'mod/assignment:view')) {
271
272
273
            // can not submit assignments -> no feedback
            return;
        }
moodler's avatar
   
moodler committed
274

275
276
        if (!$submission) { /// Get submission for this assignment
            $submission = $this->get_submission($USER->id);
moodler's avatar
moodler committed
277
        }
278
279
        // Check the user can submit
        $cansubmit = has_capability('mod/assignment:submit', $this->context, $USER->id, false);
Petr Skoda's avatar
Petr Skoda committed
280
        // If not then check if the user still has the view cap and has a previous submission
281
282
283
284
285
286
        $cansubmit = $cansubmit || (!empty($submission) && has_capability('mod/assignment:view', $this->context, $USER->id, false));

        if (!$cansubmit) {
            // can not submit assignments -> no feedback
            return;
        }
moodler's avatar
moodler committed
287

288
289
290
291
292
293
294
295
        $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, $USER->id);
        $item = $grading_info->items[0];
        $grade = $item->grades[$USER->id];

        if ($grade->hidden or $grade->grade === false) { // hidden or error
            return;
        }

296
        if ($grade->grade === null and empty($grade->str_feedback)) {   /// Nothing to show yet
moodler's avatar
moodler committed
297
            return;
298
        }
moodler's avatar
   
moodler committed
299

300
        $graded_date = $grade->dategraded;
301
        $graded_by   = $grade->usermodified;
moodler's avatar
   
moodler committed
302

303
    /// We need the teacher info
304
        if (!$teacher = $DB->get_record('user', array('id'=>$graded_by))) {
dongsheng's avatar
dongsheng committed
305
            print_error('cannotfindteacher');
306
        }
307

moodler's avatar
moodler committed
308
    /// Print the feedback
309
        echo $OUTPUT->heading(get_string('feedbackfromteacher', 'assignment', fullname($teacher)));
310

moodler's avatar
moodler committed
311
312
313
314
        echo '<table cellspacing="0" class="feedback">';

        echo '<tr>';
        echo '<td class="left picture">';
315
        if ($teacher) {
316
            echo $OUTPUT->user_picture($teacher);
317
        }
moodler's avatar
moodler committed
318
        echo '</td>';
319
        echo '<td class="topic">';
moodler's avatar
moodler committed
320
        echo '<div class="from">';
321
322
323
324
        if ($teacher) {
            echo '<div class="fullname">'.fullname($teacher).'</div>';
        }
        echo '<div class="time">'.userdate($graded_date).'</div>';
moodler's avatar
moodler committed
325
        echo '</div>';
moodler's avatar
moodler committed
326
327
328
329
330
        echo '</td>';
        echo '</tr>';

        echo '<tr>';
        echo '<td class="left side">&nbsp;</td>';
331
        echo '<td class="content">';
332
        echo '<div class="grade">';
333
        echo get_string("grade").': '.$grade->str_long_grade;
334
335
        echo '</div>';
        echo '<div class="clearer"></div>';
336

337
        echo '<div class="comment">';
338
        echo $grade->str_feedback;
339
        echo '</div>';
moodler's avatar
moodler committed
340
341
        echo '</tr>';

342
343
344
345
346
347
348
349
350
351
352
         if ($this->type == 'uploadsingle') { //@TODO: move to overload view_feedback method in the class or is uploadsingle merging into upload?
            $responsefiles = $this->print_responsefiles($submission->userid, true);
            if (!empty($responsefiles)) {
                echo '<tr>';
                echo '<td class="left side">&nbsp;</td>';
                echo '<td class="content">';
                echo $responsefiles;
                echo '</tr>';
            }
         }

moodler's avatar
moodler committed
353
        echo '</table>';
moodler's avatar
   
moodler committed
354
355
    }

356
    /**
357
     * Returns a link with info about the state of the assignment submissions
358
359
360
361
362
     *
     * This is used by view_header to put this link at the top right of the page.
     * For teachers it gives the number of submitted assignments with a link
     * For students it gives the time of their submission.
     * This will be suitable for most assignment types.
363
364
365
     *
     * @global object
     * @global object
366
     * @param bool $allgroup print all groups info if user can access all groups, suitable for index.php
367
     * @return string
368
     */
369
    function submittedlink($allgroups=false) {
370
        global $USER;
thepurpleblob's avatar
thepurpleblob committed
371
        global $CFG;
372
373

        $submitted = '';
thepurpleblob's avatar
thepurpleblob committed
374
        $urlbase = "{$CFG->wwwroot}/mod/assignment/";
375

376
        $context = get_context_instance(CONTEXT_MODULE,$this->cm->id);
377
        if (has_capability('mod/assignment:grade', $context)) {
378
379
            if ($allgroups and has_capability('moodle/site:accessallgroups', $context)) {
                $group = 0;
380
            } else {
381
                $group = groups_get_activity_group($this->cm);
382
            }
383
384
385
386
            if ($this->type == 'offline') {
                $submitted = '<a href="'.$urlbase.'submissions.php?id='.$this->cm->id.'">'.
                             get_string('viewfeedback', 'assignment').'</a>';
            } else if ($count = $this->count_real_submissions($group)) {
thepurpleblob's avatar
thepurpleblob committed
387
                $submitted = '<a href="'.$urlbase.'submissions.php?id='.$this->cm->id.'">'.
388
389
                             get_string('viewsubmissions', 'assignment', $count).'</a>';
            } else {
thepurpleblob's avatar
thepurpleblob committed
390
                $submitted = '<a href="'.$urlbase.'submissions.php?id='.$this->cm->id.'">'.
391
                             get_string('noattempts', 'assignment').'</a>';
392
393
            }
        } else {
394
            if (isloggedin()) {
395
396
                if ($submission = $this->get_submission($USER->id)) {
                    if ($submission->timemodified) {
skodak's avatar
skodak committed
397
                        if ($submission->timemodified <= $this->assignment->timedue || empty($this->assignment->timedue)) {
398
399
400
401
402
403
404
405
406
407
408
409
410
                            $submitted = '<span class="early">'.userdate($submission->timemodified).'</span>';
                        } else {
                            $submitted = '<span class="late">'.userdate($submission->timemodified).'</span>';
                        }
                    }
                }
            }
        }

        return $submitted;
    }


411
412
413
    /**
     * @todo Document this function
     */
414
    function setup_elements(&$mform) {
415

416
417
    }

418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
    /**
     * Any preprocessing needed for the settings form for
     * this assignment type
     *
     * @param array $default_values - array to fill in with the default values
     *      in the form 'formelement' => 'value'
     * @param object $form - the form that is to be displayed
     * @return none
     */
    function form_data_preprocessing(&$default_values, $form) {
    }

    /**
     * Any extra validation checks needed for the settings
     * form for this assignment type
     *
     * See lib/formslib.php, 'validation' function for details
     */
    function form_validation($data, $files) {
        return array();
    }

440
441
442
443
    /**
     * Create a new assignment activity
     *
     * Given an object containing all the necessary data,
444
     * (defined by the form in mod_form.php) this function
445
446
447
448
449
     * will create a new instance and return the id number
     * of the new instance.
     * The due data is added to the calendar
     * This is common to all assignment types.
     *
450
451
452
     * @global object
     * @global object
     * @param object $assignment The data from the form on mod_form.php
453
454
     * @return int The id of the assignment
     */
moodler's avatar
moodler committed
455
    function add_instance($assignment) {
skodak's avatar
skodak committed
456
        global $COURSE, $DB;
moodler's avatar
moodler committed
457
458

        $assignment->timemodified = time();
459
        $assignment->courseid = $assignment->course;
moodler's avatar
moodler committed
460

461
462
463
464
        $returnid = $DB->insert_record("assignment", $assignment);
        $assignment->id = $returnid;

        if ($assignment->timedue) {
465
            $event = new stdClass();
466
467
468
469
470
471
472
473
474
475
476
477
            $event->name        = $assignment->name;
            $event->description = format_module_intro('assignment', $assignment, $assignment->coursemodule);
            $event->courseid    = $assignment->course;
            $event->groupid     = 0;
            $event->userid      = 0;
            $event->modulename  = 'assignment';
            $event->instance    = $returnid;
            $event->eventtype   = 'due';
            $event->timestart   = $assignment->timedue;
            $event->timeduration = 0;

            calendar_event::create($event);
478
479
        }

480
        assignment_grade_item_update($assignment);
481

482
        return $returnid;
moodler's avatar
moodler committed
483
    }
484

485
486
487
    /**
     * Deletes an assignment activity
     *
488
     * Deletes all database records, files and calendar events for this assignment.
489
490
491
492
     *
     * @global object
     * @global object
     * @param object $assignment The assignment to be deleted
493
494
     * @return boolean False indicates error
     */
moodler's avatar
moodler committed
495
    function delete_instance($assignment) {
skodak's avatar
skodak committed
496
        global $CFG, $DB;
497

498
499
        $assignment->courseid = $assignment->course;

500
501
        $result = true;

502
        // now get rid of all files
503
504
505
        $fs = get_file_storage();
        if ($cm = get_coursemodule_from_instance('assignment', $assignment->id)) {
            $context = get_context_instance(CONTEXT_MODULE, $cm->id);
506
            $fs->delete_area_files($context->id);
507
508
        }

skodak's avatar
skodak committed
509
        if (! $DB->delete_records('assignment_submissions', array('assignment'=>$assignment->id))) {
510
511
512
            $result = false;
        }

513
        if (! $DB->delete_records('event', array('modulename'=>'assignment', 'instance'=>$assignment->id))) {
514
515
516
            $result = false;
        }

517
        if (! $DB->delete_records('assignment', array('id'=>$assignment->id))) {
518
519
            $result = false;
        }
520
        $mod = $DB->get_field('modules','id',array('name'=>'assignment'));
521
522

        assignment_grade_item_delete($assignment);
523

524
        return $result;
moodler's avatar
moodler committed
525
    }
526

527
528
529
530
    /**
     * Updates a new assignment activity
     *
     * Given an object containing all the necessary data,
531
     * (defined by the form in mod_form.php) this function
532
533
534
535
     * will update the assignment instance and return the id number
     * The due date is updated in the calendar
     * This is common to all assignment types.
     *
536
537
538
     * @global object
     * @global object
     * @param object $assignment The data from the form on mod_form.php
539
     * @return bool success
540
     */
moodler's avatar
moodler committed
541
    function update_instance($assignment) {
skodak's avatar
skodak committed
542
        global $COURSE, $DB;
moodler's avatar
moodler committed
543

moodler's avatar
moodler committed
544
545
        $assignment->timemodified = time();

moodler's avatar
moodler committed
546
        $assignment->id = $assignment->instance;
547
        $assignment->courseid = $assignment->course;
548

549
        $DB->update_record('assignment', $assignment);
550

551
        if ($assignment->timedue) {
552
            $event = new stdClass();
553

skodak's avatar
skodak committed
554
            if ($event->id = $DB->get_field('event', 'id', array('modulename'=>'assignment', 'instance'=>$assignment->id))) {
555

556
                $event->name        = $assignment->name;
557
                $event->description = format_module_intro('assignment', $assignment, $assignment->coursemodule);
558
                $event->timestart   = $assignment->timedue;
559

560
561
                $calendarevent = calendar_event::load($event->id);
                $calendarevent->update($event);
skodak's avatar
skodak committed
562
            } else {
563
                $event = new stdClass();
564
                $event->name        = $assignment->name;
565
                $event->description = format_module_intro('assignment', $assignment, $assignment->coursemodule);
566
567
568
569
570
571
572
573
574
                $event->courseid    = $assignment->course;
                $event->groupid     = 0;
                $event->userid      = 0;
                $event->modulename  = 'assignment';
                $event->instance    = $assignment->id;
                $event->eventtype   = 'due';
                $event->timestart   = $assignment->timedue;
                $event->timeduration = 0;

575
                calendar_event::create($event);
576
            }
577
        } else {
skodak's avatar
skodak committed
578
            $DB->delete_records('event', array('modulename'=>'assignment', 'instance'=>$assignment->id));
579
580
        }

581
        // get existing grade item
582
        assignment_grade_item_update($assignment);
583
584
585
586
587

        return true;
    }

    /**
588
     * Update grade item for this submission.
589
     */
590
    function update_grade($submission) {
591
        assignment_update_grades($this->assignment, $submission->userid);
moodler's avatar
moodler committed
592
593
    }

594
    /**
moodler's avatar
moodler committed
595
     * Top-level function for handling of submissions called by submissions.php
596
597
598
599
     *
     * This is for handling the teacher interaction with the grading interface
     * This should be suitable for most assignment types.
     *
600
601
     * @global object
     * @param string $mode Specifies the kind of teacher interaction taking place
moodler's avatar
moodler committed
602
603
     */
    function submissions($mode) {
604
605
606
607
        ///The main switch is changed to facilitate
        ///1) Batch fast grading
        ///2) Skip to the next one on the popup
        ///3) Save and Skip to the next one on the popup
608

609
        //make user global so we can use the id
610
        global $USER, $OUTPUT, $DB, $PAGE;
611

612
        $mailinfo = optional_param('mailinfo', null, PARAM_BOOL);
613

614
        if (optional_param('next', null, PARAM_BOOL)) {
615
616
            $mode='next';
        }
617
        if (optional_param('saveandnext', null, PARAM_BOOL)) {
618
619
620
            $mode='saveandnext';
        }

621
        if (is_null($mailinfo)) {
622
623
624
625
626
            if (optional_param('sesskey', null, PARAM_BOOL)) {
                set_user_preference('assignment_mailinfo', $mailinfo);
            } else {
                $mailinfo = get_user_preferences('assignment_mailinfo', 0);
            }
627
628
        } else {
            set_user_preference('assignment_mailinfo', $mailinfo);
629
        }
630

moodler's avatar
moodler committed
631
        switch ($mode) {
632
            case 'grade':                         // We are in a main window grading
moodler's avatar
moodler committed
633
                if ($submission = $this->process_feedback()) {
634
635
636
                    $this->display_submissions(get_string('changessaved'));
                } else {
                    $this->display_submissions();
moodler's avatar
moodler committed
637
638
                }
                break;
moodler's avatar
moodler committed
639

640
641
642
643
644
645
            case 'single':                        // We are in a main window displaying one submission
                if ($submission = $this->process_feedback()) {
                    $this->display_submissions(get_string('changessaved'));
                } else {
                    $this->display_submission();
                }
moodler's avatar
moodler committed
646
                break;
647

648
            case 'all':                          // Main window, display everything
moodler's avatar
moodler committed
649
650
                $this->display_submissions();
                break;
moodler's avatar
moodler committed
651

652
            case 'fastgrade':
moodler's avatar
moodler committed
653
                ///do the fast grading stuff  - this process should work for all 3 subclasses
654
                $grading    = false;
655
                $commenting = false;
656
                $col        = false;
657
658
                if (isset($_POST['submissioncomment'])) {
                    $col = 'submissioncomment';
659
660
661
                    $commenting = true;
                }
                if (isset($_POST['menu'])) {
662
                    $col = 'menu';
663
664
                    $grading = true;
                }
665
                if (!$col) {
666
                    //both submissioncomment and grade columns collapsed..
667
                    $this->display_submissions();
668
669
                    break;
                }
670

671
                foreach ($_POST[$col] as $id => $unusedvalue){
672
673

                    $id = (int)$id; //clean parameter name
674
675
676

                    $this->process_outcomes($id);

677
678
679
680
681
682
683
684
                    if (!$submission = $this->get_submission($id)) {
                        $submission = $this->prepare_new_submission($id);
                        $newsubmission = true;
                    } else {
                        $newsubmission = false;
                    }
                    unset($submission->data1);  // Don't need to update this.
                    unset($submission->data2);  // Don't need to update this.
685

686
                    //for fast grade, we need to check if any changes take place
687
688
689
690
                    $updatedb = false;

                    if ($grading) {
                        $grade = $_POST['menu'][$id];
691
692
                        $updatedb = $updatedb || ($submission->grade != $grade);
                        $submission->grade = $grade;
693
                    } else {
694
695
696
                        if (!$newsubmission) {
                            unset($submission->grade);  // Don't need to update this.
                        }
697
698
                    }
                    if ($commenting) {
699
                        $commentvalue = trim($_POST['submissioncomment'][$id]);
700
                        $updatedb = $updatedb || ($submission->submissioncomment != $commentvalue);
701
                        $submission->submissioncomment = $commentvalue;
702
                    } else {
703
                        unset($submission->submissioncomment);  // Don't need to update this.
704
705
                    }

706
                    $submission->teacher    = $USER->id;
707
708
709
710
                    if ($updatedb) {
                        $submission->mailed = (int)(!$mailinfo);
                    }

711
712
713
                    $submission->timemarked = time();

                    //if it is not an update, we don't change the last modified time etc.
714
                    //this will also not write into database if no submissioncomment and grade is entered.
715

716
                    if ($updatedb){
717
                        if ($newsubmission) {
718
719
720
                            if (!isset($submission->submissioncomment)) {
                                $submission->submissioncomment = '';
                            }
721
                            $sid = $DB->insert_record('assignment_submissions', $submission);
722
                            $submission->id = $sid;
723
                        } else {
724
                            $DB->update_record('assignment_submissions', $submission);
725
726
                        }

Petr Skoda's avatar
Petr Skoda committed
727
                        // trigger grade event
728
                        $this->update_grade($submission);
729

730
                        //add to log only if updating
731
                        add_to_log($this->course->id, 'assignment', 'update grades',
732
                                   'submissions.php?id='.$this->cm->id.'&user='.$submission->userid,
733
                                   $submission->userid, $this->cm->id);
734
                    }
735
736

                }
737

738
                $message = $OUTPUT->notification(get_string('changessaved'), 'notifysuccess');
739
740

                $this->display_submissions($message);
741
                break;
742
743


744
745
746
747
748
            case 'saveandnext':
                ///We are in pop up. save the current one and go to the next one.
                //first we save the current changes
                if ($submission = $this->process_feedback()) {
                    //print_heading(get_string('changessaved'));
749
                    //$extra_javascript = $this->update_main_listing($submission);
750
                }
751

752
753
754
755
756
757
758
759
760
761
            case 'next':
                /// We are currently in pop up, but we want to skip to next one without saving.
                ///    This turns out to be similar to a single case
                /// The URL used is for the next submission.
                $offset = required_param('offset', PARAM_INT);
                $nextid = required_param('nextid', PARAM_INT);
                $id = required_param('id', PARAM_INT);
                $offset = (int)$offset+1;
                //$this->display_submission($offset+1 , $nextid);
                redirect('submissions.php?id='.$id.'&userid='. $nextid . '&mode=single&offset='.$offset);
762
                break;
763

764
765
766
767
            case 'singlenosave':
                $this->display_submission();
                break;

768
769
            default:
                echo "something seriously is wrong!!";
770
                break;
771
        }
moodler's avatar
moodler committed
772
    }
773

774
    /**
775
776
777
778
779
780
     * Helper method updating the listing on the main script from popup using javascript
     *
     * @global object
     * @global object
     * @param $submission object The submission whose data is to be updated on the main page
     */
781
    function update_main_listing($submission) {
782
        global $SESSION, $CFG, $OUTPUT;
783

toyomoyo's avatar
toyomoyo committed
784
785
        $output = '';

786
        $perpage = get_user_preferences('assignment_perpage', 10);
787

788
        $quickgrade = get_user_preferences('assignment_quickgrade', 0);
789

790
        /// Run some Javascript to try and update the parent page
toyomoyo's avatar
toyomoyo committed
791
        $output .= '<script type="text/javascript">'."\n<!--\n";
792
        if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['submissioncomment'])) {
793
            if ($quickgrade){
794
                $output.= 'opener.document.getElementById("submissioncomment'.$submission->userid.'").value="'
795
                .trim($submission->submissioncomment).'";'."\n";
796
             } else {
toyomoyo's avatar
toyomoyo committed
797
                $output.= 'opener.document.getElementById("com'.$submission->userid.
798
                '").innerHTML="'.shorten_text(trim(strip_tags($submission->submissioncomment)), 15)."\";\n";
799
            }
800
        }
801
802
803
804

        if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['grade'])) {
            //echo optional_param('menuindex');
            if ($quickgrade){
805
806
                $output.= 'opener.document.getElementById("menumenu'.$submission->userid.
                '").selectedIndex="'.optional_param('menuindex', 0, PARAM_INT).'";'."\n";
807
            } else {
toyomoyo's avatar
toyomoyo committed
808
                $output.= 'opener.document.getElementById("g'.$submission->userid.'").innerHTML="'.
809
                $this->display_grade($submission->grade)."\";\n";
810
811
            }
        }
812
        //need to add student's assignments in there too.
813
814
        if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['timemodified']) &&
            $submission->timemodified) {
toyomoyo's avatar
toyomoyo committed
815
            $output.= 'opener.document.getElementById("ts'.$submission->userid.
816
                 '").innerHTML="'.addslashes_js($this->print_student_answer($submission->userid)).userdate($submission->timemodified)."\";\n";
817
        }
818

819
820
        if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['timemarked']) &&
            $submission->timemarked) {
toyomoyo's avatar
toyomoyo committed
821
            $output.= 'opener.document.getElementById("tt'.$submission->userid.
822
823
                 '").innerHTML="'.userdate($submission->timemarked)."\";\n";
        }
824

825
        if (empty($SESSION->flextable['mod-assignment-submissions']->collapse['status'])) {
toyomoyo's avatar
toyomoyo committed
826
            $output.= 'opener.document.getElementById("up'.$submission->userid.'").className="s1";';
827
            $buttontext = get_string('update');
828
829
830
            $url = new moodle_url('/mod/assignment/submissions.php', array(
                    'id' => $this->cm->id,
                    'userid' => $submission->userid,
831
                    'mode' => 'single',
832
                    'offset' => (optional_param('offset', '', PARAM_INT)-1)));
833
            $button = $OUTPUT->action_link($url, $buttontext, new popup_action('click', $url, 'grade'.$submission->userid, array('height' => 450, 'width' => 700)), array('ttile'=>$buttontext));
834

835
            $output .= 'opener.document.getElementById("up'.$submission->userid.'").innerHTML="'.addslashes_js($button).'";';