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