Merge branch 'MDL-34794_M23' of git://github.com/raymondAntonio/moodle into MOODLE_23...
[moodle.git] / mod / assign / lib.php
CommitLineData
bbd0e548
DW
1<?PHP
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * This file contains the moodle hooks for the assign module. It delegates most functions to the assignment class.
19 *
20 * @package mod_assign
21 * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24defined('MOODLE_INTERNAL') || die();
25
26/**
27 * Adds an assignment instance
28 *
29 * This is done by calling the add_instance() method of the assignment type class
30 * @param stdClass $data
31 * @param mod_assign_mod_form $form
32 * @return int The instance id of the new assignment
33 */
34function assign_add_instance(stdClass $data, mod_assign_mod_form $form) {
35 global $CFG;
36 require_once($CFG->dirroot . '/mod/assign/locallib.php');
37
38 $assignment = new assign(context_module::instance($data->coursemodule), null, null);
39 return $assignment->add_instance($data, true);
40}
41
42/**
43 * delete an assignment instance
44 * @param int $id
45 * @return bool
46 */
47function assign_delete_instance($id) {
48 global $CFG;
49 require_once($CFG->dirroot . '/mod/assign/locallib.php');
50 $cm = get_coursemodule_from_instance('assign', $id, 0, false, MUST_EXIST);
51 $context = context_module::instance($cm->id);
52
53 $assignment = new assign($context, null, null);
54 return $assignment->delete_instance();
55}
56
10839ace
RW
57/**
58 * This function is used by the reset_course_userdata function in moodlelib.
59 * This function will remove all assignment submissions and feedbacks in the database
60 * and clean up any related data.
61 * @param $data the data submitted from the reset course.
62 * @return array status array
63 */
64function assign_reset_userdata($data) {
65 global $CFG, $DB;
66 require_once($CFG->dirroot . '/mod/assign/locallib.php');
67
68 $status = array();
69 $params = array('courseid'=>$data->courseid);
70 $sql = "SELECT a.id FROM {assign} a WHERE a.course=:courseid";
71 $course = $DB->get_record('course', array('id'=> $data->courseid), '*', MUST_EXIST);
72 if ($assigns = $DB->get_records_sql($sql,$params)) {
73 foreach ($assigns as $assign) {
74 $cm = get_coursemodule_from_instance('assign', $assign->id, $data->courseid, false, MUST_EXIST);
75 $context = context_module::instance($cm->id);
76 $assignment = new assign($context, $cm, $course);
77 $status = array_merge($status, $assignment->reset_userdata($data));
78 }
79 }
80 return $status;
81}
82
83/**
84 * Removes all grades from gradebook
85 *
86 * @param int $courseid The ID of the course to reset
87 * @param string $type Optional type of assignment to limit the reset to a particular assignment type
88 */
89function assign_reset_gradebook($courseid, $type='') {
90 global $CFG, $DB;
91
92 $params = array('moduletype'=>'assign','courseid'=>$courseid);
93 $sql = 'SELECT a.*, cm.idnumber as cmidnumber, a.course as courseid
94 FROM {assign} a, {course_modules} cm, {modules} m
95 WHERE m.name=:moduletype AND m.id=cm.module AND cm.instance=a.id AND a.course=:courseid';
96
97 if ($assignments = $DB->get_records_sql($sql,$params)) {
98 foreach ($assignments as $assignment) {
99 assign_grade_item_update($assignment, 'reset');
100 }
101 }
102}
103
104/**
105 * Implementation of the function for printing the form elements that control
106 * whether the course reset functionality affects the assignment.
107 * @param $mform form passed by reference
108 */
109function assign_reset_course_form_definition(&$mform) {
110 $mform->addElement('header', 'assignheader', get_string('modulenameplural', 'assign'));
111 $mform->addElement('advcheckbox', 'reset_assign_submissions', get_string('deleteallsubmissions','assign'));
112}
113
114/**
115 * Course reset form defaults.
116 * @param object $course
117 * @return array
118 */
119function assign_reset_course_form_defaults($course) {
120 return array('reset_assign_submissions'=>1);
121}
122
bbd0e548
DW
123/**
124 * Update an assignment instance
125 *
126 * This is done by calling the update_instance() method of the assignment type class
127 * @param stdClass $data
128 * @param mod_assign_mod_form $form
129 * @return object
130 */
131function assign_update_instance(stdClass $data, mod_assign_mod_form $form) {
132 global $CFG;
133 require_once($CFG->dirroot . '/mod/assign/locallib.php');
134 $context = context_module::instance($data->coursemodule);
135 $assignment = new assign($context, null, null);
136 return $assignment->update_instance($data);
137}
138
139/**
140 * Return the list if Moodle features this module supports
141 *
142 * @param string $feature FEATURE_xx constant for requested feature
143 * @return mixed True if module supports feature, null if doesn't know
144 */
145function assign_supports($feature) {
146 switch($feature) {
147 case FEATURE_GROUPS: return true;
148 case FEATURE_GROUPINGS: return true;
149 case FEATURE_GROUPMEMBERSONLY: return true;
150 case FEATURE_MOD_INTRO: return true;
151 case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
152 case FEATURE_GRADE_HAS_GRADE: return true;
153 case FEATURE_GRADE_OUTCOMES: return true;
154 case FEATURE_BACKUP_MOODLE2: return true;
155 case FEATURE_SHOW_DESCRIPTION: return true;
156 case FEATURE_ADVANCED_GRADING: return true;
157
158 default: return null;
159 }
160}
161
162/**
163 * Lists all gradable areas for the advanced grading methods gramework
164 *
165 * @return array('string'=>'string') An array with area names as keys and descriptions as values
166 */
167function assign_grading_areas_list() {
168 return array('submissions'=>get_string('submissions', 'assign'));
169}
170
171
172/**
173 * extend an assigment navigation settings
174 *
175 * @param settings_navigation $settings
176 * @param navigation_node $navref
177 * @return void
178 */
179function assign_extend_settings_navigation(settings_navigation $settings, navigation_node $navref) {
180 global $PAGE;
181
182 $cm = $PAGE->cm;
183 if (!$cm) {
184 return;
185 }
186
187 $context = $cm->context;
188 $course = $PAGE->course;
189
190
191 if (!$course) {
192 return;
193 }
194
195
196 // Link to gradebook
197 if (has_capability('gradereport/grader:view', $cm->context) && has_capability('moodle/grade:viewall', $cm->context)) {
198 $link = new moodle_url('/grade/report/grader/index.php', array('id' => $course->id));
199 $node = $navref->add(get_string('viewgradebook', 'assign'), $link, navigation_node::TYPE_SETTING);
200 }
201
202 // Link to download all submissions
203 if (has_capability('mod/assign:grade', $context)) {
204 $link = new moodle_url('/mod/assign/view.php', array('id' => $cm->id,'action'=>'grading'));
205 $node = $navref->add(get_string('viewgrading', 'assign'), $link, navigation_node::TYPE_SETTING);
206
207 $link = new moodle_url('/mod/assign/view.php', array('id' => $cm->id,'action'=>'downloadall'));
208 $node = $navref->add(get_string('downloadall', 'assign'), $link, navigation_node::TYPE_SETTING);
209 }
210
211}
212
213
214/**
215 * Add a get_coursemodule_info function in case any assignment type wants to add 'extra' information
216 * for the course (see resource).
217 *
218 * Given a course_module object, this function returns any "extra" information that may be needed
219 * when printing this activity in a course listing. See get_array_of_activities() in course/lib.php.
220 *
221 * @param stdClass $coursemodule The coursemodule object (record).
222 * @return cached_cm_info An object on information that the courses will know about (most noticeably, an icon).
223 */
224function assign_get_coursemodule_info($coursemodule) {
225 global $CFG, $DB;
226
227 if (! $assignment = $DB->get_record('assign', array('id'=>$coursemodule->instance),
228 'id, name, alwaysshowdescription, allowsubmissionsfromdate, intro, introformat')) {
229 return false;
230 }
231
232 $result = new cached_cm_info();
233 $result->name = $assignment->name;
234 if ($coursemodule->showdescription) {
235 if ($assignment->alwaysshowdescription || time() > $assignment->allowsubmissionsfromdate) {
236 // Convert intro to html. Do not filter cached version, filters run at display time.
237 $result->content = format_module_intro('assign', $assignment, $coursemodule->id, false);
238 }
239 }
240 return $result;
241}
242
243
244/**
245 * Return a list of page types
246 * @param string $pagetype current page type
247 * @param stdClass $parentcontext Block's parent context
248 * @param stdClass $currentcontext Current context of block
249 */
250function assign_page_type_list($pagetype, $parentcontext, $currentcontext) {
251 $module_pagetype = array(
252 'mod-assign-*' => get_string('page-mod-assign-x', 'assign'),
253 'mod-assign-view' => get_string('page-mod-assign-view', 'assign'),
254 );
255 return $module_pagetype;
256}
257
258/**
259 * Print an overview of all assignments
260 * for the courses.
261 *
262 * @param mixed $courses The list of courses to print the overview for
263 * @param array $htmlarray The array of html to return
264 */
265function assign_print_overview($courses, &$htmlarray) {
266 global $USER, $CFG, $DB;
267
268 if (empty($courses) || !is_array($courses) || count($courses) == 0) {
269 return array();
270 }
271
272 if (!$assignments = get_all_instances_in_courses('assign',$courses)) {
273 return;
274 }
275
276 $assignmentids = array();
277
278 // Do assignment_base::isopen() here without loading the whole thing for speed
279 foreach ($assignments as $key => $assignment) {
280 $time = time();
5c57df4c 281 $isopen = false;
bbd0e548 282 if ($assignment->duedate) {
383639a5 283 $isopen = $assignment->allowsubmissionsfromdate <= $time;
bbd0e548 284 if ($assignment->preventlatesubmissions) {
94303631 285 $isopen = ($isopen && $time <= $assignment->duedate);
bbd0e548
DW
286 }
287 }
94303631 288 if ($isopen) {
bbd0e548
DW
289 $assignmentids[] = $assignment->id;
290 }
291 }
292
293 if (empty($assignmentids)){
294 // no assignments to look at - we're done
295 return true;
296 }
297
298 $strduedate = get_string('duedate', 'assign');
299 $strduedateno = get_string('duedateno', 'assign');
300 $strgraded = get_string('graded', 'assign');
301 $strnotgradedyet = get_string('notgradedyet', 'assign');
302 $strnotsubmittedyet = get_string('notsubmittedyet', 'assign');
303 $strsubmitted = get_string('submitted', 'assign');
304 $strassignment = get_string('modulename', 'assign');
305 $strreviewed = get_string('reviewed','assign');
306
307
308 // NOTE: we do all possible database work here *outside* of the loop to ensure this scales
309 //
310 list($sqlassignmentids, $assignmentidparams) = $DB->get_in_or_equal($assignmentids);
311
312 // build up and array of unmarked submissions indexed by assignment id/ userid
313 // for use where the user has grading rights on assignment
314 $rs = $DB->get_recordset_sql("SELECT s.assignment as assignment, s.userid as userid, s.id as id, s.status as status, g.timemodified as timegraded
315 FROM {assign_submission} s LEFT JOIN {assign_grades} g ON s.userid = g.userid and s.assignment = g.assignment
316 WHERE g.timemodified = 0 OR s.timemodified > g.timemodified
317 AND s.assignment $sqlassignmentids", $assignmentidparams);
318
319 $unmarkedsubmissions = array();
320 foreach ($rs as $rd) {
321 $unmarkedsubmissions[$rd->assignment][$rd->userid] = $rd->id;
322 }
323 $rs->close();
324
325
326 // get all user submissions, indexed by assignment id
cfe32be8 327 $mysubmissions = $DB->get_records_sql("SELECT a.id AS assignment, a.nosubmissions AS nosubmissions, g.timemodified AS timemarked, g.grader AS grader, g.grade AS grade, s.status AS status
bbd0e548
DW
328 FROM {assign} a LEFT JOIN {assign_grades} g ON g.assignment = a.id AND g.userid = ? LEFT JOIN {assign_submission} s ON s.assignment = a.id AND s.userid = ?
329 AND a.id $sqlassignmentids", array_merge(array($USER->id, $USER->id), $assignmentidparams));
330
331 foreach ($assignments as $assignment) {
94303631
DW
332 // Do not show assignments that are not open
333 if (!in_array($assignment->id, $assignmentids)) {
334 continue;
335 }
bbd0e548
DW
336 $str = '<div class="assign overview"><div class="name">'.$strassignment. ': '.
337 '<a '.($assignment->visible ? '':' class="dimmed"').
338 'title="'.$strassignment.'" href="'.$CFG->wwwroot.
339 '/mod/assign/view.php?id='.$assignment->coursemodule.'">'.
340 format_string($assignment->name).'</a></div>';
341 if ($assignment->duedate) {
342 $str .= '<div class="info">'.$strduedate.': '.userdate($assignment->duedate).'</div>';
343 } else {
344 $str .= '<div class="info">'.$strduedateno.'</div>';
345 }
346 $context = context_module::instance($assignment->coursemodule);
347 if (has_capability('mod/assign:grade', $context)) {
348
349 // count how many people can submit
350 $submissions = 0; // init
351 if ($students = get_enrolled_users($context, 'mod/assign:view', 0, 'u.id')) {
352 foreach ($students as $student) {
353 if (isset($unmarkedsubmissions[$assignment->id][$student->id])) {
354 $submissions++;
355 }
356 }
357 }
358
359 if ($submissions) {
360 $link = new moodle_url('/mod/assign/view.php', array('id'=>$assignment->coursemodule, 'action'=>'grading'));
361 $str .= '<div class="details"><a href="'.$link.'">'.get_string('submissionsnotgraded', 'assign', $submissions).'</a></div>';
362 }
363 } if (has_capability('mod/assign:submit', $context)) {
364 $str .= '<div class="details">';
365 $str .= get_string('mysubmission', 'assign');
366 $submission = $mysubmissions[$assignment->id];
cfe32be8 367 if ($submission->nosubmissions) {
bbd0e548
DW
368 $str .= get_string('offline', 'assign');
369 } else if(!$submission->status || $submission->status == 'draft'){
370 $str .= $strnotsubmittedyet;
371 }else {
372 $str .= get_string('submissionstatus_' . $submission->status, 'assign');
373 }
374 if (!$submission->grade || $submission->grade < 0) {
375 $str .= ', ' . get_string('notgraded', 'assign');
376 } else {
377 $str .= ', ' . get_string('graded', 'assign');
378 }
379 $str .= '</div>';
380 }
381 $str .= '</div>';
382 if (empty($htmlarray[$assignment->course]['assign'])) {
383 $htmlarray[$assignment->course]['assign'] = $str;
384 } else {
385 $htmlarray[$assignment->course]['assign'] .= $str;
386 }
387 }
388}
389
390/**
391 * Print recent activity from all assignments in a given course
392 *
393 * This is used by the recent activity block
394 * @param mixed $course the course to print activity for
395 * @param bool $viewfullnames boolean to determine whether to show full names or not
9682626e 396 * @param int $timestart the time the rendering started
bbd0e548
DW
397 */
398function assign_print_recent_activity($course, $viewfullnames, $timestart) {
399 global $CFG, $USER, $DB, $OUTPUT;
400
401 // do not use log table if possible, it may be huge
402
403 if (!$submissions = $DB->get_records_sql("SELECT asb.id, asb.timemodified, cm.id AS cmid, asb.userid,
404 u.firstname, u.lastname, u.email, u.picture
405 FROM {assign_submission} asb
406 JOIN {assign} a ON a.id = asb.assignment
407 JOIN {course_modules} cm ON cm.instance = a.id
408 JOIN {modules} md ON md.id = cm.module
409 JOIN {user} u ON u.id = asb.userid
410 WHERE asb.timemodified > ? AND
411 a.course = ? AND
412 md.name = 'assign'
413 ORDER BY asb.timemodified ASC", array($timestart, $course->id))) {
414 return false;
415 }
416
417 $modinfo = get_fast_modinfo($course); // no need pass this by reference as the return object already being cached
418 $show = array();
419 $grader = array();
420
cfc81f03
DW
421 $showrecentsubmissions = get_config('mod_assign', 'showrecentsubmissions');
422
bbd0e548
DW
423 foreach($submissions as $submission) {
424 if (!array_key_exists($submission->cmid, $modinfo->get_cms())) {
425 continue;
426 }
427 $cm = $modinfo->get_cm($submission->cmid);
428 if (!$cm->uservisible) {
429 continue;
430 }
431 if ($submission->userid == $USER->id) {
432 $show[] = $submission;
433 continue;
434 }
435
436 $context = context_module::instance($submission->cmid);
437 // the act of sumbitting of assignment may be considered private - only graders will see it if specified
cfc81f03 438 if (empty($showrecentsubmissions)) {
bbd0e548
DW
439 if (!array_key_exists($cm->id, $grader)) {
440 $grader[$cm->id] = has_capability('moodle/grade:viewall',$context);
441 }
442 if (!$grader[$cm->id]) {
443 continue;
444 }
445 }
446
447 $groupmode = groups_get_activity_groupmode($cm, $course);
448
449 if ($groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)) {
450 if (isguestuser()) {
451 // shortcut - guest user does not belong into any group
452 continue;
453 }
454
455 if (is_null($modinfo->get_groups())) {
456 $modinfo->groups = groups_get_user_groups($course->id); // load all my groups and cache it in modinfo
457 }
458
459 // this will be slow - show only users that share group with me in this cm
460 if (empty($modinfo->groups[$cm->id])) {
461 continue;
462 }
463 $usersgroups = groups_get_all_groups($course->id, $submission->userid, $cm->groupingid);
464 if (is_array($usersgroups)) {
465 $usersgroups = array_keys($usersgroups);
466 $intersect = array_intersect($usersgroups, $modinfo->groups[$cm->id]);
467 if (empty($intersect)) {
468 continue;
469 }
470 }
471 }
472 $show[] = $submission;
473 }
474
475 if (empty($show)) {
476 return false;
477 }
478
479 echo $OUTPUT->heading(get_string('newsubmissions', 'assign').':', 3);
480
481 foreach ($show as $submission) {
482 $cm = $modinfo->get_cm($submission->cmid);
483 $link = $CFG->wwwroot.'/mod/assign/view.php?id='.$cm->id;
484 print_recent_activity_note($submission->timemodified, $submission, $cm->name, $link, false, $viewfullnames);
485 }
486
487 return true;
488}
489
490/**
491 * Returns all assignments since a given time
c06b2127 492 *
bbd0e548
DW
493 * @param array $activities The activity information is returned in this array
494 * @param int $index The current index in the activities array
495 * @param int $timestart The earliest activity to show
496 * @param int $courseid Limit the search to this course
497 * @param int $cmid The course module id
498 * @param int $userid Optional user id
499 * @param int $groupid Optional group id
500 * @return void
501 */
502function assign_get_recent_mod_activity(&$activities, &$index, $timestart, $courseid, $cmid, $userid=0, $groupid=0) {
503 global $CFG, $COURSE, $USER, $DB;
504
505 if ($COURSE->id == $courseid) {
506 $course = $COURSE;
507 } else {
508 $course = $DB->get_record('course', array('id'=>$courseid));
509 }
510
511 $modinfo = get_fast_modinfo($course); // no need pass this by reference as the return object already being cached
512
513 $cm = $modinfo->get_cm($cmid);
514 $params = array();
515 if ($userid) {
516 $userselect = "AND u.id = :userid";
517 $params['userid'] = $userid;
518 } else {
519 $userselect = "";
520 }
521
522 if ($groupid) {
523 $groupselect = "AND gm.groupid = :groupid";
524 $groupjoin = "JOIN {groups_members} gm ON gm.userid=u.id";
525 $params['groupid'] = $groupid;
526 } else {
527 $groupselect = "";
528 $groupjoin = "";
529 }
530
531 $params['cminstance'] = $cm->instance;
532 $params['timestart'] = $timestart;
533
534 $userfields = user_picture::fields('u', null, 'userid');
535
536 if (!$submissions = $DB->get_records_sql("SELECT asb.id, asb.timemodified,
537 $userfields
538 FROM {assign_submission} asb
539 JOIN {assign} a ON a.id = asb.assignment
540 JOIN {user} u ON u.id = asb.userid
541 $groupjoin
542 WHERE asb.timemodified > :timestart AND a.id = :cminstance
543 $userselect $groupselect
544 ORDER BY asb.timemodified ASC", $params)) {
545 return;
546 }
547
548 $groupmode = groups_get_activity_groupmode($cm, $course);
549 $cm_context = context_module::instance($cm->id);
550 $grader = has_capability('moodle/grade:viewall', $cm_context);
551 $accessallgroups = has_capability('moodle/site:accessallgroups', $cm_context);
552 $viewfullnames = has_capability('moodle/site:viewfullnames', $cm_context);
553
554 if (is_null($modinfo->get_groups())) {
555 $modinfo->groups = groups_get_user_groups($course->id); // load all my groups and cache it in modinfo
556 }
557
cfc81f03 558 $showrecentsubmissions = get_config('mod_assign', 'showrecentsubmissions');
bbd0e548
DW
559 $show = array();
560 $usersgroups = groups_get_all_groups($course->id, $USER->id, $cm->groupingid);
561 if (is_array($usersgroups)) {
562 $usersgroups = array_keys($usersgroups);
563 }
564 foreach($submissions as $submission) {
565 if ($submission->userid == $USER->id) {
566 $show[] = $submission;
567 continue;
568 }
569 // the act of submitting of assignment may be considered private - only graders will see it if specified
cfc81f03 570 if (empty($showrecentsubmissions)) {
bbd0e548
DW
571 if (!$grader) {
572 continue;
573 }
574 }
575
576 if ($groupmode == SEPARATEGROUPS and !$accessallgroups) {
577 if (isguestuser()) {
578 // shortcut - guest user does not belong into any group
579 continue;
580 }
581
582 // this will be slow - show only users that share group with me in this cm
583 if (empty($modinfo->groups[$cm->id])) {
584 continue;
585 }
586 if (is_array($usersgroups)) {
587 $intersect = array_intersect($usersgroups, $modinfo->groups[$cm->id]);
588 if (empty($intersect)) {
589 continue;
590 }
591 }
592 }
593 $show[] = $submission;
594 }
595
596 if (empty($show)) {
597 return;
598 }
599
600 if ($grader) {
601 require_once($CFG->libdir.'/gradelib.php');
602 $userids = array();
603 foreach ($show as $id=>$submission) {
604 $userids[] = $submission->userid;
605
606 }
607 $grades = grade_get_grades($courseid, 'mod', 'assign', $cm->instance, $userids);
608 }
609
610 $aname = format_string($cm->name,true);
611 foreach ($show as $submission) {
612 $activity = new stdClass();
613
614 $activity->type = 'assign';
615 $activity->cmid = $cm->id;
616 $activity->name = $aname;
617 $activity->sectionnum = $cm->sectionnum;
618 $activity->timestamp = $submission->timemodified;
619 $activity->user = new stdClass();
620 if ($grader) {
621 $activity->grade = $grades->items[0]->grades[$submission->userid]->str_long_grade;
622 }
623
624 $userfields = explode(',', user_picture::fields());
625 foreach ($userfields as $userfield) {
626 if ($userfield == 'id') {
627 $activity->user->{$userfield} = $submission->userid; // aliased in SQL above
628 } else {
629 $activity->user->{$userfield} = $submission->{$userfield};
630 }
631 }
632 $activity->user->fullname = fullname($submission, $viewfullnames);
633
634 $activities[$index++] = $activity;
635 }
636
637 return;
638}
639
640/**
641 * Print recent activity from all assignments in a given course
642 *
643 * This is used by course/recent.php
644 * @param stdClass $activity
645 * @param int $courseid
646 * @param bool $detail
647 * @param array $modnames
648 */
649function assign_print_recent_mod_activity($activity, $courseid, $detail, $modnames) {
650 global $CFG, $OUTPUT;
651
652 echo '<table border="0" cellpadding="3" cellspacing="0" class="assignment-recent">';
653
654 echo "<tr><td class=\"userpicture\" valign=\"top\">";
655 echo $OUTPUT->user_picture($activity->user);
656 echo "</td><td>";
657
658 if ($detail) {
659 $modname = $modnames[$activity->type];
660 echo '<div class="title">';
661 echo "<img src=\"" . $OUTPUT->pix_url('icon', 'assign') . "\" ".
662 "class=\"icon\" alt=\"$modname\">";
663 echo "<a href=\"$CFG->wwwroot/mod/assign/view.php?id={$activity->cmid}\">{$activity->name}</a>";
664 echo '</div>';
665 }
666
667 if (isset($activity->grade)) {
668 echo '<div class="grade">';
669 echo get_string('grade').': ';
670 echo $activity->grade;
671 echo '</div>';
672 }
673
674 echo '<div class="user">';
675 echo "<a href=\"$CFG->wwwroot/user/view.php?id={$activity->user->id}&amp;course=$courseid\">"
676 ."{$activity->user->fullname}</a> - ".userdate($activity->timestamp);
677 echo '</div>';
678
679 echo "</td></tr></table>";
680}
681
682/**
683 * Checks if a scale is being used by an assignment
684 *
685 * This is used by the backup code to decide whether to back up a scale
9682626e 686 * @param int $assignmentid
bbd0e548
DW
687 * @param int $scaleid
688 * @return boolean True if the scale is used by the assignment
689 */
690function assign_scale_used($assignmentid, $scaleid) {
691 global $DB;
692
693 $return = false;
694 $rec = $DB->get_record('assign', array('id'=>$assignmentid,'grade'=>-$scaleid));
695
696 if (!empty($rec) && !empty($scaleid)) {
697 $return = true;
698 }
699
700 return $return;
701}
702
703/**
704 * Checks if scale is being used by any instance of assignment
705 *
706 * This is used to find out if scale used anywhere
9682626e 707 * @param int $scaleid
bbd0e548
DW
708 * @return boolean True if the scale is used by any assignment
709 */
710function assign_scale_used_anywhere($scaleid) {
711 global $DB;
712
713 if ($scaleid and $DB->record_exists('assign', array('grade'=>-$scaleid))) {
714 return true;
715 } else {
716 return false;
717 }
718}
719
720/**
721 * function to list the actions that correspond to a view of this module
722 * This is used by the participation report
723 * @return array
724 */
725function assign_get_view_actions() {
726 return array('view submission', 'view feedback');
727}
728
729/**
730 * function to list the actions that correspond to a post of this module
731 * This is used by the participation report
732 * @return array
733 */
734function assign_get_post_actions() {
735 return array('upload', 'submit', 'submit for grading');
736}
737
738/**
739 * Call cron on the assign module
740 */
741function assign_cron() {
742 global $CFG;
743
744 require_once($CFG->dirroot . '/mod/assign/locallib.php');
75f87a57
DW
745 assign::cron();
746
bbd0e548
DW
747 $plugins = get_plugin_list('assignsubmission');
748
749 foreach ($plugins as $name => $plugin) {
750 $disabled = get_config('assignsubmission_' . $name, 'disabled');
751 if (!$disabled) {
752 $class = 'assign_submission_' . $name;
753 require_once($CFG->dirroot . '/mod/assign/submission/' . $name . '/locallib.php');
754 $class::cron();
755 }
756 }
757 $plugins = get_plugin_list('assignfeedback');
758
759 foreach ($plugins as $name => $plugin) {
760 $disabled = get_config('assignfeedback_' . $name, 'disabled');
761 if (!$disabled) {
762 $class = 'assign_feedback_' . $name;
763 require_once($CFG->dirroot . '/mod/assign/feedback/' . $name . '/locallib.php');
764 $class::cron();
765 }
766 }
767}
768
769/**
770 * Returns all other capabilities used by this module.
771 * @return array Array of capability strings
772 */
773function assign_get_extra_capabilities() {
774 return array('gradereport/grader:view', 'moodle/grade:viewall', 'moodle/site:viewfullnames', 'moodle/site:config');
775}
776
777/**
778 * Create grade item for given assignment
779 *
780 * @param stdClass $assign record with extra cmidnumber
781 * @param array $grades optional array/object of grade(s); 'reset' means reset grades in gradebook
782 * @return int 0 if ok, error code otherwise
783 */
784function assign_grade_item_update($assign, $grades=NULL) {
785 global $CFG;
786 require_once($CFG->libdir.'/gradelib.php');
787
788 if (!isset($assign->courseid)) {
789 $assign->courseid = $assign->course;
790 }
791
792 $params = array('itemname'=>$assign->name, 'idnumber'=>$assign->cmidnumber);
793
794 if ($assign->grade > 0) {
795 $params['gradetype'] = GRADE_TYPE_VALUE;
796 $params['grademax'] = $assign->grade;
797 $params['grademin'] = 0;
798
799 } else if ($assign->grade < 0) {
800 $params['gradetype'] = GRADE_TYPE_SCALE;
801 $params['scaleid'] = -$assign->grade;
802
803 } else {
804 $params['gradetype'] = GRADE_TYPE_TEXT; // allow text comments only
805 }
806
807 if ($grades === 'reset') {
808 $params['reset'] = true;
809 $grades = NULL;
810 }
811
812 return grade_update('mod/assign', $assign->courseid, 'mod', 'assign', $assign->id, 0, $grades, $params);
813}
814
815/**
816 * Return grade for given user or all users.
817 *
818 * @param stdClass $assign record of assign with an additional cmidnumber
819 * @param int $userid optional user id, 0 means all users
820 * @return array array of grades, false if none
821 */
822function assign_get_user_grades($assign, $userid=0) {
823 global $CFG;
824 require_once($CFG->dirroot . '/mod/assign/locallib.php');
825
b865c07b
RW
826 $cm = get_coursemodule_from_instance('assign', $assign->id, 0, false, MUST_EXIST);
827 $context = context_module::instance($cm->id);
828 $assignment = new assign($context, null, null);
b11808c7 829 $assignment->set_instance($assign);
bbd0e548
DW
830 return $assignment->get_user_grades_for_gradebook($userid);
831}
832
833/**
834 * Update activity grades
835 *
836 * @param stdClass $assign database record
837 * @param int $userid specific user only, 0 means all
838 * @param bool $nullifnone - not used
839 */
840function assign_update_grades($assign, $userid=0, $nullifnone=true) {
841 global $CFG;
842 require_once($CFG->libdir.'/gradelib.php');
843
844 if ($assign->grade == 0) {
845 assign_grade_item_update($assign);
846
847 } else if ($grades = assign_get_user_grades($assign, $userid)) {
848 foreach($grades as $k=>$v) {
849 if ($v->rawgrade == -1) {
850 $grades[$k]->rawgrade = null;
851 }
852 }
853 assign_grade_item_update($assign, $grades);
854
855 } else {
856 assign_grade_item_update($assign);
857 }
858}
859
860/**
861 * List the file areas that can be browsed
862 *
863 * @param stdClass $course
864 * @param stdClass $cm
865 * @param stdClass $context
866 * @return array
867 */
6b8b0b2e 868function assign_get_file_areas($course, $cm, $context) {
bbd0e548
DW
869 global $CFG;
870 require_once($CFG->dirroot . '/mod/assign/locallib.php');
871 $areas = array();
872
873 $assignment = new assign($context, $cm, $course);
874 foreach ($assignment->get_submission_plugins() as $plugin) {
875 if ($plugin->is_visible()) {
876 $pluginareas = $plugin->get_file_areas();
877
878 if ($pluginareas) {
879 $areas = array_merge($areas, $pluginareas);
880 }
881 }
882 }
883 foreach ($assignment->get_feedback_plugins() as $plugin) {
884 if ($plugin->is_visible()) {
885 $pluginareas = $plugin->get_file_areas();
886
887 if ($pluginareas) {
888 $areas = array_merge($areas, $pluginareas);
889 }
890 }
891 }
892
893 return $areas;
894}
895
896/**
897 * File browsing support for assign module.
898 *
899 * @param file_browser $browser
900 * @param object $areas
901 * @param object $course
902 * @param object $cm
903 * @param object $context
904 * @param string $filearea
905 * @param int $itemid
906 * @param string $filepath
907 * @param string $filename
908 * @return object file_info instance or null if not found
909 */
6b8b0b2e 910function assign_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
bbd0e548
DW
911 global $CFG;
912 require_once($CFG->dirroot . '/mod/assign/locallib.php');
913
914 if ($context->contextlevel != CONTEXT_MODULE) {
915 return null;
916 }
917
918 $fs = get_file_storage();
919 $filepath = is_null($filepath) ? '/' : $filepath;
920 $filename = is_null($filename) ? '.' : $filename;
921
922 // need to find the plugin this belongs to
923 $assignment = new assign($context, $cm, $course);
924 $pluginowner = null;
925 foreach ($assignment->get_submission_plugins() as $plugin) {
926 if ($plugin->is_visible()) {
927 $pluginareas = $plugin->get_file_areas();
928
929 if (array_key_exists($filearea, $pluginareas)) {
930 $pluginowner = $plugin;
931 break;
932 }
933 }
934 }
935 if (!$pluginowner) {
936 foreach ($assignment->get_feedback_plugins() as $plugin) {
937 if ($plugin->is_visible()) {
938 $pluginareas = $plugin->get_file_areas();
939
940 if (array_key_exists($filearea, $pluginareas)) {
941 $pluginowner = $plugin;
942 break;
943 }
944 }
945 }
946 }
947
948 if (!$pluginowner) {
949 return null;
950 }
951
952 $result = $pluginowner->get_file_info($browser, $filearea, $itemid, $filepath, $filename);
953 return $result;
954}
955
956/**
957 * Prints the complete info about a user's interaction with an assignment
958 *
959 * @param stdClass $course
960 * @param stdClass $user
961 * @param stdClass $coursemodule
962 * @param stdClass $assign the database assign record
963 *
964 * This prints the submission summary and feedback summary for this student
965 */
966function assign_user_complete($course, $user, $coursemodule, $assign) {
967 global $CFG;
968 require_once($CFG->dirroot . '/mod/assign/locallib.php');
969 $context = context_module::instance($coursemodule->id);
970
971 $assignment = new assign($context, $coursemodule, $course);
972
973 echo $assignment->view_student_summary($user, false);
974}
975
976/**
977 * Print the grade information for the assignment for this user
9682626e 978 *
bbd0e548
DW
979 * @param stdClass $course
980 * @param stdClass $user
981 * @param stdClass $coursemodule
982 * @param stdClass $assignment
983 */
984function assign_user_outline($course, $user, $coursemodule, $assignment) {
985 global $CFG;
986 require_once($CFG->libdir.'/gradelib.php');
987 require_once($CFG->dirroot.'/grade/grading/lib.php');
988
989 $gradinginfo = grade_get_grades($course->id,
990 'mod',
991 'assign',
992 $assignment->id,
993 $user->id);
994
995 $gradingitem = $gradinginfo->items[0];
996 $gradebookgrade = $gradingitem->grades[$user->id];
997
998 if (!$gradebookgrade) {
999 return null;
1000 }
1001 $result = new stdClass();
1002 $result->info = get_string('outlinegrade', 'assign', $gradebookgrade->grade);
1003 $result->time = $gradebookgrade->dategraded;
1004
1005 return $result;
1006}