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