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