diff --git a/add_form.php b/add_form.php index 9877980..a9550a3 100644 --- a/add_form.php +++ b/add_form.php @@ -78,9 +78,9 @@ class mod_attendance_add_form extends moodleform { } if ($groupmode == SEPARATEGROUPS or $groupmode == VISIBLEGROUPS) { if ($groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $modcontext)) { - $groups = groups_get_all_groups ($course->id, $USER->id); + $groups = groups_get_all_groups ($course->id, $USER->id, $cm->groupingid); } else { - $groups = groups_get_all_groups($course->id); + $groups = groups_get_all_groups($course->id, 0, $cm->groupingid); } if ($groups) { $selectgroups = array(); @@ -162,9 +162,19 @@ class mod_attendance_add_form extends moodleform { public function validation($data, $files) { $errors = parent::validation($data, $files); + if (!empty($data['addmultiply']) && $data['sessiondate'] != 0 && $data['sessionenddate'] != 0 && $data['sessionenddate'] < $data['sessiondate']) { + $errors['sessionenddate'] = get_string('invalidsessionenddate', 'attendance'); + } + if ($data['sessiontype'] == attendance::SESSION_GROUP and empty($data['groups'])) { $errors['groups'] = get_string('errorgroupsnotselected', 'attendance'); } + + $addmulti = isset($data['addmultiply'])? (int)$data['addmultiply'] : 0; + if (($addmulti != 0) && (!array_key_exists('sdays',$data) || empty($data['sdays']))) { + $data['sdays']= array(); + $errors['sdays'] = get_string('required', 'attendance'); + } return $errors; } diff --git a/db/upgrade.php b/db/upgrade.php index 2642874..579f80f 100644 --- a/db/upgrade.php +++ b/db/upgrade.php @@ -32,6 +32,8 @@ function xmldb_attendance_upgrade($oldversion=0) { global $CFG, $THEME, $DB; $dbman = $DB->get_manager(); // Loads ddl manager and xmldb classes. + $result = true; + if ($oldversion < 2013082901) { $table = new xmldb_table('attendance_sessions'); @@ -41,9 +43,47 @@ function xmldb_attendance_upgrade($oldversion=0) { $dbman->add_field($table, $field); } - upgrade_mod_savepoint(true, 2013082901, 'attendance'); + upgrade_mod_savepoint($result, 2013082901, 'attendance'); + } + + if ($oldversion < 2013082902) { + // Replace values that reference old module "attforblock" to "attendance". + $sql = "UPDATE {grade_items} + SET itemmodule = 'attendance' + WHERE itemmodule = 'attforblock'"; + + $DB->execute($sql); + + $sql = "UPDATE {grade_items_history} + SET itemmodule = 'attendance' + WHERE itemmodule = 'attforblock'"; + + $DB->execute($sql); + + /* + * The user's custom capabilities need to be preserved due to the module renaming. + * Capabilities with a modifierid = 0 value are installed by default. + * Only update the user's custom capabilities where modifierid is not zero. + */ + $sql = $DB->sql_like('capability', '?').' AND modifierid <> 0'; + $rs = $DB->get_recordset_select('role_capabilities', $sql, array('%mod/attforblock%')); + foreach ($rs as $cap) { + $renamedcapability = str_replace('mod/attforblock', 'mod/attendance', $cap->capability); + $exists = $DB->record_exists('role_capabilities', array('roleid' => $cap->roleid, 'capability' => $renamedcapability)); + if (!$exists) { + $DB->update_record('role_capabilities', array('id' => $cap->id, 'capability' => $renamedcapability)); + } + } + + // Delete old role capabilities. + $sql = $DB->sql_like('capability', '?'); + $DB->delete_records_select('role_capabilities', $sql, array('%mod/attforblock%')); + + // Delete old capabilities. + $DB->delete_records_select('capabilities', 'component = ?', array('mod_attforblock')); + + upgrade_plugin_savepoint($result, 2013082902, 'mod', 'attendance'); } - // UPGRADES from attforblock are only supported for sites that are running attforblock version 2012120700. return $result; } diff --git a/export.php b/export.php index 995e937..9b6fb99 100644 --- a/export.php +++ b/export.php @@ -55,6 +55,7 @@ if ($mform->is_submitted()) { $pageparams = new att_page_with_filter_controls(); $pageparams->init($cm); + $pageparams->page = 0; $pageparams->group = $formdata->group; $pageparams->set_current_sesstype($formdata->group ? $formdata->group : att_page_with_filter_controls::SESSTYPE_ALL); if (isset($formdata->includeallsessions)) { @@ -97,6 +98,10 @@ if ($mform->is_submitted()) { $data->tabhead[] = get_string('lastname'); $data->tabhead[] = get_string('firstname'); + $groupmode = groups_get_activity_groupmode($cm, $course); + if (!empty($groupmode)) { + $data->tabhead[] = get_string('groups'); + } if (count($reportdata->sessions) > 0) { foreach ($reportdata->sessions as $sess) { @@ -104,6 +109,9 @@ if ($mform->is_submitted()) { $text .= ' '; $text .= $sess->groupid ? $reportdata->groups[$sess->groupid]->name : get_string('commonsession', 'attendance'); $data->tabhead[] = $text; + if (isset($formdata->includeremarks)) { + $data->tabhead[] = get_string('remark', 'attendance', $text); + } } } else { print_error('sessionsnotfound', 'attendance', $att->url_manage()); @@ -131,8 +139,17 @@ if ($mform->is_submitted()) { $data->table[$i][] = $user->lastname; $data->table[$i][] = $user->firstname; + if (!empty($groupmode)) { + $grouptext = ''; + $groupsraw = groups_get_all_groups($course->id, $user->id, 0, 'g.name'); + $groups = array(); + foreach ($groupsraw as $group) { + $groups[] = $group->name;; + } + $data->table[$i][] = implode(', ', $groups); + } $cellsgenerator = new user_sessions_cells_text_generator($reportdata, $user); - $data->table[$i] = array_merge($data->table[$i], $cellsgenerator->get_cells()); + $data->table[$i] = array_merge($data->table[$i], $cellsgenerator->get_cells(isset($formdata->includeremarks))); if ($reportdata->gradable) { $data->table[$i][] = $reportdata->grades[$user->id].' / '.$reportdata->maxgrades[$user->id]; } diff --git a/export_form.php b/export_form.php index ef33010..766e863 100644 --- a/export_form.php +++ b/export_form.php @@ -48,7 +48,7 @@ class mod_attendance_export_form extends moodleform { $mform->addElement('header', 'general', get_string('export', 'quiz')); - $groupmode=groups_get_activity_groupmode($cm); + $groupmode=groups_get_activity_groupmode($cm, $course); $groups = groups_get_activity_allowed_groups($cm, $USER->id); if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $modcontext)) { $grouplist[0] = get_string('allparticipants'); @@ -78,6 +78,7 @@ class mod_attendance_export_form extends moodleform { $mform->addElement('checkbox', 'includeallsessions', get_string('includeall', 'attendance'), get_string('yes')); $mform->setDefault('includeallsessions', true); $mform->addElement('checkbox', 'includenottaken', get_string('includenottaken', 'attendance'), get_string('yes')); + $mform->addElement('checkbox', 'includeremarks', get_string('includeremarks', 'attendance'), get_string('yes')); $mform->addElement('date_selector', 'sessionstartdate', get_string('startofperiod', 'attendance')); $mform->setDefault('sessionstartdate', $course->startdate); $mform->disabledIf('sessionstartdate', 'includeallsessions', 'checked'); diff --git a/index.php b/index.php index dcb421c..f699052 100644 --- a/index.php +++ b/index.php @@ -29,8 +29,11 @@ $id = required_param('id', PARAM_INT); $course = $DB->get_record('course', array('id' => $id), '*', MUST_EXIST); require_login($course); +$PAGE->set_url('/mod/attendance/index.php', array('id' => $id)); + // TODO: check if this is correct behaviour - other modules list all the instances of the module in the course. -if ($att = array_pop(get_all_instances_in_course('attendance', $course, null, true))) { +if ($att = get_all_instances_in_course('attendance', $course, null, true)) { + $att = array_pop($att); redirect("view.php?id=$att->coursemodule"); } else { print_error('notfound', 'attendance'); diff --git a/lang/en/attendance.php b/lang/en/attendance.php index 8138358..ee35575 100755 --- a/lang/en/attendance.php +++ b/lang/en/attendance.php @@ -96,6 +96,7 @@ $string['displaymode'] = 'Display mode'; $string['downloadexcel'] = 'Download in Excel format'; $string['downloadooo'] = 'Download in OpenOffice format'; $string['downloadtext'] = 'Download in text format'; +$string['donotusepaging'] = 'Do not use paging'; $string['duration'] = 'Duration'; $string['editsession'] = 'Edit Session'; $string['endtime'] = 'Session end time'; @@ -120,7 +121,9 @@ You can use this feature to hide older sessions instead delete. Remember than on $string['identifyby'] = 'Identify student by'; $string['includeall'] = 'Select all sessions'; $string['includenottaken'] = 'Include not taken sessions'; +$string['includeremarks'] = 'Include remarks'; $string['indetail'] = 'In detail...'; +$string['invalidsessionenddate'] = 'The session end date can not be earlier than the session start date'; $string['jumpto'] = 'Jump to'; $string['modulename'] = 'Attendance'; $string['modulename_help'] = 'The attendance activity module enables a teacher to take attendance during class and students to view their own attendance record. @@ -130,6 +133,7 @@ The teacher can create multiple sessions and can mark the attendance status as " Reports are available for the entire class or individual students.'; $string['modulenameplural'] = 'Attendances'; $string['months'] = 'Months'; +$string['moreattendance'] = 'Attendance has been successfully taken for this page'; $string['myvariables'] = 'My Variables'; $string['newdate'] = 'New date'; $string['newduration'] = 'New duration'; @@ -150,11 +154,15 @@ $string['olddate'] = 'Old date'; $string['period'] = 'Frequency'; $string['pluginname'] = 'Attendance'; $string['pluginadministration'] = 'Attendance administration'; +$string['remark'] = 'Remark for: {a}'; $string['remarks'] = 'Remarks'; $string['report'] = 'Report'; +$string['required'] = 'Required*'; $string['resetdescription'] = 'Remember that deleting attendance data will erase information from database. You can just hide older sessions having changed start date of course!'; $string['resetstatuses'] = 'Reset statuses to default'; $string['restoredefaults'] = 'Restore defaults'; +$string['resultsperpage'] = 'Results per page'; +$string['resultsperpage_desc'] = 'Number of students displayed on a page'; $string['save'] = 'Save attendance'; $string['session'] = 'Session'; $string['session_help'] = 'Session'; diff --git a/lib.php b/lib.php index 32d65e5..134288b 100644 --- a/lib.php +++ b/lib.php @@ -35,14 +35,10 @@ function attendance_supports($feature) { return true; case FEATURE_GROUPS: return true; - // Artem Andreev: AFAIK it's not tested - // we need implement filtration of groups list by grouping. case FEATURE_GROUPINGS: - return false; - // Artem Andreev: AFAIK it's not tested - // harder "All courses" report. + return true; case FEATURE_GROUPMEMBERSONLY: - return false; + return true; case FEATURE_MOD_INTRO: return false; case FEATURE_BACKUP_MOODLE2: @@ -58,12 +54,13 @@ function attendance_supports($feature) { function att_add_default_statuses($attid) { global $DB; - $statuses = $DB->get_records('attendance_statuses', array('attendanceid'=> 0), 'id'); + $statuses = $DB->get_recordset('attendance_statuses', array('attendanceid'=> 0), 'id'); foreach ($statuses as $st) { $rec = $st; $rec->attendanceid = $attid; $DB->insert_record('attendance_statuses', $rec); } + $statuses->close(); } function attendance_add_instance($attendance) { @@ -217,7 +214,6 @@ function attendance_reset_userdata($data) { */ function attendance_user_outline($course, $user, $mod, $attendance) { global $CFG; - require_once(dirname(__FILE__).'/locallib.php'); require_once($CFG->libdir.'/gradelib.php'); @@ -233,9 +229,9 @@ function attendance_user_outline($course, $user, $mod, $attendance) { if (has_capability('mod/attendance:canbelisted', $mod->context, $user->id)) { $statuses = att_get_statuses($attendance->id); $grade = att_get_user_grade(att_get_user_statuses_stat($attendance->id, $course->startdate, - $user->id), $statuses); + $user->id, $mod), $statuses); $maxgrade = att_get_user_max_grade(att_get_user_taken_sessions_count($attendance->id, $course->startdate, - $user->id), $statuses); + $user->id, $mod), $statuses); $result->info = $grade.' / '.$maxgrade; } @@ -254,7 +250,7 @@ function attendance_user_complete($course, $user, $mod, $attendance) { require_once($CFG->libdir.'/gradelib.php'); if (has_capability('mod/attendance:canbelisted', $mod->context, $user->id)) { - echo construct_full_user_stat_html_table($attendance, $course, $user); + echo construct_full_user_stat_html_table($attendance, $course, $user, $mod); } } function attendance_print_recent_activity($course, $isteacher, $timestart) { diff --git a/locallib.php b/locallib.php index c2b257c..f30c292 100644 --- a/locallib.php +++ b/locallib.php @@ -330,9 +330,8 @@ class att_page_with_filter_controls { if ($groupmode == VISIBLEGROUPS or has_capability('moodle/site:accessallgroups', $PAGE->context)) { $this->sessgroupslist[self::SESSTYPE_ALL] = get_string('all', 'attendance'); } - if ($groupmode == VISIBLEGROUPS) { - $this->sessgroupslist[self::SESSTYPE_COMMON] = get_string('commonsessions', 'attendance'); - } + // Show Common groups always + $this->sessgroupslist[self::SESSTYPE_COMMON] = get_string('commonsessions', 'attendance'); foreach ($allowedgroups as $group) { $this->sessgroupslist[$group->id] = format_string($group->name); } @@ -601,7 +600,7 @@ class attendance { public function get_group_mode() { if (is_null($this->groupmode)) { - $this->groupmode = groups_get_activity_groupmode($this->cm); + $this->groupmode = groups_get_activity_groupmode($this->cm, $this->course); } return $this->groupmode; } @@ -812,7 +811,8 @@ class attendance { $i++; } - $this->log('sessions added', $this->url_manage(), implode(', ', $info_array)); + add_to_log($this->course->id, 'attendance', 'sessions added', $this->url_manage(), + implode(',', $info_array), $this->cm->id); } public function update_session_from_form_data($formdata, $sessionid) { @@ -834,7 +834,7 @@ class attendance { $url = $this->url_sessions(array('sessionid' => $sessionid, 'action' => att_sessions_page_params::ACTION_UPDATE)); $info = construct_session_full_date_time($sess->sessdate, $sess->duration); - $this->log('session updated', $url, $info); + add_to_log($this->course->id, 'attendance', 'session updated', $url, $info, $this->cm->id); } /** @@ -888,10 +888,11 @@ class attendance { 'grouptype' => 0); $url = $this->url_take($params); - + $logurl = att_log_convert_url($url); + // Log the change. - $this->log('taken by student', $url, $USER->firstname.' '.$USER->lastname); - + add_to_log($this->course->id, 'attendance', 'taken by student', $logurl, '', $this->cm->id); + return true; } @@ -948,9 +949,30 @@ class attendance { 'grouptype' => $this->pageparams->grouptype); $url = $this->url_take($params); - + $logurl = att_log_convert_url($url); + // Log the change. - $this->log('taken', $url, $USER->firstname.' '.$USER->lastname); + add_to_log($this->course->id, 'attendance', 'taken', $logurl, '', $this->cm->id); + + $group = 0; + if ($this->pageparams->grouptype != attendance::SESSION_COMMON) { + $group = $this->pageparams->grouptype; + } else { + if ($this->pageparams->group) { + $group = $this->pageparams->group; + } + } + + $totalusers = count_enrolled_users(context_module::instance($this->cm->id), 'mod/attendance:canbelisted', $group); + $usersperpage = $this->pageparams->perpage; + + if (!empty($this->pageparams->page) && $this->pageparams->page && $totalusers && $usersperpage) { + $numberofpages = ceil($totalusers / $usersperpage); + if ($this->pageparams->page < $numberofpages) { + $params['page'] = $this->pageparams->page + 1; + redirect($this->url_take($params), get_string('moreattendance', 'attendance')); + } + } redirect($this->url_manage(), get_string('attendancesuccess', 'attendance')); } @@ -958,11 +980,11 @@ class attendance { /** * MDL-27591 made this method obsolete. */ - public function get_users($groupid = 0) { - global $DB; + public function get_users($groupid = 0, $page = 1) { + global $DB, $CFG; // Fields we need from the user table. - $userfields = user_picture::fields('u').',u.username,u.idnumber,u.institution,u.department'; + $userfields = user_picture::fields('u', array('username' , 'idnumber' , 'institution' , 'department')); if (isset($this->pageparams->sort) and ($this->pageparams->sort == ATT_SORT_FIRSTNAME)) { $orderby = "u.firstname ASC, u.lastname ASC, u.idnumber ASC, u.institution ASC, u.department ASC"; @@ -970,27 +992,64 @@ class attendance { $orderby = "u.lastname ASC, u.firstname ASC, u.idnumber ASC, u.institution ASC, u.department ASC"; } - $users = get_enrolled_users($this->context, 'mod/attendance:canbelisted', $groupid, $userfields, $orderby); + if ($page) { + $usersperpage = $this->pageparams->perpage; + if (!empty($CFG->enablegroupmembersonly) and $this->cm->groupmembersonly) { + $startusers = ($page - 1) * $usersperpage; + if ($groupid == 0) { + $groups = array_keys(groups_get_all_groups($this->cm->course, 0, $this->cm->groupingid, 'g.id')); + } else { + $groups = $groupid; + } + $users = get_users_by_capability($this->context, 'mod/attendance:canbelisted', + $userfields.',u.id, u.firstname, u.lastname, u.email', + $orderby, $startusers, $usersperpage, $groups, + '', false, true); + } else { + $startusers = ($page - 1) * $usersperpage; + $users = get_enrolled_users($this->context, 'mod/attendance:canbelisted', $groupid, $userfields, $orderby, $startusers, $usersperpage); + } + } else { + if (!empty($CFG->enablegroupmembersonly) and $this->cm->groupmembersonly) { + if ($groupid == 0) { + $groups = array_keys(groups_get_all_groups($this->cm->course, 0, $this->cm->groupingid, 'g.id')); + } else { + $groups = $groupid; + } + $users = get_users_by_capability($this->context, 'mod/attendance:canbelisted', + $userfields.',u.id, u.firstname, u.lastname, u.email', + $orderby, '', '', $groups, + '', false, true); + } else { + $users = get_enrolled_users($this->context, 'mod/attendance:canbelisted', $groupid, $userfields, $orderby); + } + } // Add a flag to each user indicating whether their enrolment is active. if (!empty($users)) { - list($usql, $uparams) = $DB->get_in_or_equal(array_keys($users), SQL_PARAMS_NAMED, 'usid0'); + list($sql, $params) = $DB->get_in_or_equal(array_keys($users), SQL_PARAMS_NAMED, 'usid0'); - // CONTRIB-3549. - $sql = "SELECT ue.userid, ue.status, ue.timestart, ue.timeend + // CONTRIB-4868 + $mintime = 'MIN(CASE WHEN (ue.timestart > :zerotime) THEN ue.timestart ELSE ue.timecreated END)'; + $maxtime = 'MAX(ue.timeend)'; + + // CONTRIB-3549 + $sql = "SELECT ue.userid, ue.status, + $mintime AS mintime, + $maxtime AS maxtime FROM {user_enrolments} ue JOIN {enrol} e ON e.id = ue.enrolid - WHERE ue.userid $usql + WHERE ue.userid $sql AND e.status = :estatus AND e.courseid = :courseid - GROUP BY ue.userid, ue.status, ue.timestart, ue.timeend"; - $params = array_merge($uparams, array('estatus'=>ENROL_INSTANCE_ENABLED, 'courseid'=>$this->course->id)); - $enrolmentsparams = $DB->get_records_sql($sql, $params); + GROUP BY ue.userid, ue.status"; + $params += array('zerotime'=>0, 'estatus'=>ENROL_INSTANCE_ENABLED, 'courseid'=>$this->course->id); + $enrolments = $DB->get_records_sql($sql, $params); foreach ($users as $user) { - $users[$user->id]->enrolmentstatus = $enrolmentsparams[$user->id]->status; - $users[$user->id]->enrolmentstart = $enrolmentsparams[$user->id]->timestart; - $users[$user->id]->enrolmentend = $enrolmentsparams[$user->id]->timeend; + $users[$user->id]->enrolmentstatus = $enrolments[$user->id]->status; + $users[$user->id]->enrolmentstart = $enrolments[$user->id]->mintime; + $users[$user->id]->enrolmentend = $enrolments[$user->id]->maxtime; } } @@ -1002,19 +1061,25 @@ class attendance { $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST); - $sql = "SELECT ue.userid, ue.status, ue.timestart, ue.timeend + // CONTRIB-4868 + $mintime = 'MIN(CASE WHEN (ue.timestart > :zerotime) THEN ue.timestart ELSE ue.timecreated END)'; + $maxtime = 'MAX(ue.timeend)'; + + $sql = "SELECT ue.userid, ue.status, + $mintime AS mintime, + $maxtime AS maxtime FROM {user_enrolments} ue JOIN {enrol} e ON e.id = ue.enrolid WHERE ue.userid = :uid AND e.status = :estatus AND e.courseid = :courseid - GROUP BY ue.userid, ue.status, ue.timestart, ue.timeend"; - $params = array('uid' => $userid, 'estatus'=>ENROL_INSTANCE_ENABLED, 'courseid'=>$this->course->id); - $enrolmentsparams = $DB->get_record_sql($sql, $params); + GROUP BY ue.userid, ue.status"; + $params = array('zerotime'=>0, 'uid'=>$userid, 'estatus'=>ENROL_INSTANCE_ENABLED, 'courseid'=>$this->course->id); + $enrolments = $DB->get_record_sql($sql, $params); - $user->enrolmentstatus = $enrolmentsparams->status; - $user->enrolmentstart = $enrolmentsparams->timestart; - $user->enrolmentend = $enrolmentsparams->timeend; + $user->enrolmentstatus = $enrolments->status; + $user->enrolmentstart = $enrolments->mintime; + $user->enrolmentend = $enrolments->maxtime; return $user; } @@ -1076,7 +1141,11 @@ class attendance { public function get_user_taken_sessions_count($userid) { if (!array_key_exists($userid, $this->usertakensesscount)) { - $this->usertakensesscount[$userid] = att_get_user_taken_sessions_count($this->id, $this->course->startdate, $userid); + if (!empty($this->pageparams->startdate) && !empty($this->pageparams->enddate)) { + $this->usertakensesscount[$userid] = att_get_user_taken_sessions_count($this->id, $this->course->startdate, $userid, $this->cm, $this->pageparams->startdate, $this->pageparams->enddate); + } else { + $this->usertakensesscount[$userid] = att_get_user_taken_sessions_count($this->id, $this->course->startdate, $userid, $this->cm); + } } return $this->usertakensesscount[$userid]; } @@ -1090,14 +1159,13 @@ class attendance { */ public function get_user_statuses_stat($userid, array $filters = null) { global $DB; - - // Need to start setting the parameters here for the filters to work. $params = array( - 'aid' => $this->id, - 'cstartdate' => $this->course->startdate, - 'uid' => $userid); + 'aid' => $this->id, + 'cstartdate' => $this->course->startdate, + 'uid' => $userid); $processed_filters = array(); + // We test for any valid filters sent. if (isset($filters['enddate'])) { $processed_filters[] = 'ats.sessdate <= :enddate'; @@ -1106,22 +1174,42 @@ class attendance { // Make the filter array into a SQL string. if (!empty($processed_filters)) { - $processed_filters = 'AND '.implode(' AND ', $processed_filters); + $processed_filters = ' AND '.implode(' AND ', $processed_filters); } else { $processed_filters = ''; } - $qry = "SELECT al.statusid, count(al.statusid) AS stcnt - FROM {attendance_log} al - JOIN {attendance_sessions} ats - ON al.sessionid = ats.id - WHERE ats.attendanceid = :aid AND - ats.sessdate >= :cstartdate AND - al.studentid = :uid - $processed_filters - GROUP BY al.statusid"; - - if ($filters !== null) { // We do not want to cache, or use a cached version of the results when a filter is set. + + $period = ''; + if (!empty($this->pageparams->startdate) && !empty($this->pageparams->enddate)) { + $period = ' AND ats.sessdate >= :sdate AND ats.sessdate < :edate '; + $params['sdate'] = $this->pageparams->startdate; + $params['edate'] = $this->pageparams->enddate; + } + + if ($this->get_group_mode()) { + $qry = "SELECT al.statusid, count(al.statusid) AS stcnt + FROM {attendance_log} al + JOIN {attendance_sessions} ats ON al.sessionid = ats.id + LEFT JOIN {groups_members} gm ON gm.userid = al.studentid AND gm.groupid = ats.groupid + WHERE ats.attendanceid = :aid AND + ats.sessdate >= :cstartdate AND + al.studentid = :uid AND + (ats.groupid = 0 or gm.id is NOT NULL)".$period.$processed_filters." + GROUP BY al.statusid"; + } else { + $qry = "SELECT al.statusid, count(al.statusid) AS stcnt + FROM {attendance_log} al + JOIN {attendance_sessions} ats + ON al.sessionid = ats.id + WHERE ats.attendanceid = :aid AND + ats.sessdate >= :cstartdate AND + al.studentid = :uid".$period.$processed_filters." + GROUP BY al.statusid"; + } + + // We do not want to cache, or use a cached version of the results when a filter is set. + if ($filters !== null) { return $DB->get_records_sql($qry, $params); } else if (!array_key_exists($userid, $this->userstatusesstat)) { // Not filtered so if we do not already have them do the query. @@ -1176,20 +1264,36 @@ class attendance { } else { $where = "ats.attendanceid = :aid AND ats.sessdate >= :csdate"; } + if ($this->get_group_mode()) { + $sql = "SELECT ats.id, ats.sessdate, ats.groupid, al.statusid, al.remarks + FROM {attendance_sessions} ats + JOIN {attendance_log} al ON ats.id = al.sessionid AND al.studentid = :uid + LEFT JOIN {groups_members} gm ON gm.userid = al.studentid AND gm.groupid = ats.groupid + WHERE $where AND (ats.groupid = 0 or gm.id is NOT NULL) + ORDER BY ats.sessdate ASC"; - $sql = "SELECT ats.id, ats.sessdate, ats.groupid, al.statusid + $params = array( + 'uid' => $userid, + 'aid' => $this->id, + 'csdate' => $this->course->startdate, + 'sdate' => $this->pageparams->startdate, + 'edate' => $this->pageparams->enddate); + + } else { + $sql = "SELECT ats.id, ats.sessdate, ats.groupid, al.statusid, al.remarks FROM {attendance_sessions} ats JOIN {attendance_log} al ON ats.id = al.sessionid AND al.studentid = :uid WHERE $where ORDER BY ats.sessdate ASC"; - $params = array( + $params = array( 'uid' => $userid, 'aid' => $this->id, 'csdate' => $this->course->startdate, 'sdate' => $this->pageparams->startdate, 'edate' => $this->pageparams->enddate); + } $sessions = $DB->get_records_sql($sql, $params); return $sessions; @@ -1197,35 +1301,35 @@ class attendance { public function get_user_filtered_sessions_log_extended($userid) { global $DB; - // All taked sessions (including previous groups). - $groups = array_keys(groups_get_all_groups($this->course->id, $userid)); - $groups[] = 0; - list($gsql, $gparams) = $DB->get_in_or_equal($groups, SQL_PARAMS_NAMED, 'gid0'); - if ($this->pageparams->startdate && $this->pageparams->enddate) { $where = "ats.attendanceid = :aid AND ats.sessdate >= :csdate AND ats.sessdate >= :sdate AND ats.sessdate < :edate"; - $where2 = "ats.attendanceid = :aid2 AND ats.sessdate >= :csdate2 AND - ats.sessdate >= :sdate2 AND ats.sessdate < :edate2 AND ats.groupid $gsql"; } else { $where = "ats.attendanceid = :aid AND ats.sessdate >= :csdate"; - $where2 = "ats.attendanceid = :aid2 AND ats.sessdate >= :csdate2 AND ats.groupid $gsql"; } - $sql = "SELECT ats.id, ats.groupid, ats.sessdate, ats.duration, ats.description, al.statusid, al.remarks, ats.studentscanmark + // We need to add this concatination so that moodle will use it as the array index that is a string. + // If the array's index is a number it will not merge entries. + // It would be better as a UNION query butunfortunatly MS SQL does not seem to support doing a DISTINCT on a the description field. + $id = $DB->sql_concat(':value', 'ats.id'); + if ($this->get_group_mode()) { + $sql = "SELECT $id, ats.id, ats.groupid, ats.sessdate, ats.duration, ats.description, al.statusid, al.remarks, ats.studentscanmark FROM {attendance_sessions} ats - RIGHT JOIN {attendance_log} al + RIGHT JOIN {attendance_log} al ON ats.id = al.sessionid AND al.studentid = :uid - WHERE $where - UNION - SELECT ats.id, ats.groupid, ats.sessdate, ats.duration, ats.description, al.statusid, al.remarks, ats.studentscanmark + LEFT JOIN {groups_members} gm ON gm.userid = al.studentid AND gm.groupid = ats.groupid + WHERE $where AND (ats.groupid = 0 or gm.id is NOT NULL) + ORDER BY ats.sessdate ASC"; + } else { + $sql = "SELECT $id, ats.id, ats.groupid, ats.sessdate, ats.duration, ats.description, al.statusid, al.remarks, ats.studentscanmark FROM {attendance_sessions} ats - LEFT JOIN {attendance_log} al - ON ats.id = al.sessionid AND al.studentid = :uid2 - WHERE $where2 - ORDER BY sessdate ASC"; + RIGHT JOIN {attendance_log} al + ON ats.id = al.sessionid AND al.studentid = :uid + WHERE $where + ORDER BY ats.sessdate ASC"; + } $params = array( 'uid' => $userid, @@ -1233,14 +1337,32 @@ class attendance { 'csdate' => $this->course->startdate, 'sdate' => $this->pageparams->startdate, 'edate' => $this->pageparams->enddate, - 'uid2' => $userid, - 'aid2' => $this->id, - 'csdate2' => $this->course->startdate, - 'sdate2' => $this->pageparams->startdate, - 'edate2' => $this->pageparams->enddate); - $params = array_merge($params, $gparams); + 'value' => 'c'); $sessions = $DB->get_records_sql($sql, $params); + // All sessions for current groups. + + $groups = array_keys(groups_get_all_groups($this->course->id, $userid)); + $groups[] = 0; + list($gsql, $gparams) = $DB->get_in_or_equal($groups, SQL_PARAMS_NAMED, 'gid0'); + + if ($this->pageparams->startdate && $this->pageparams->enddate) { + $where = "ats.attendanceid = :aid AND ats.sessdate >= :csdate AND + ats.sessdate >= :sdate AND ats.sessdate < :edate AND ats.groupid $gsql"; + } else { + $where = "ats.attendanceid = :aid AND ats.sessdate >= :csdate AND ats.groupid $gsql"; + } + + $sql = "SELECT $id, ats.id, ats.groupid, ats.sessdate, ats.duration, ats.description, al.statusid, al.remarks, ats.studentscanmark + FROM {attendance_sessions} ats + LEFT JOIN {attendance_log} al + ON ats.id = al.sessionid AND al.studentid = :uid + WHERE $where + ORDER BY ats.sessdate ASC"; + + $params = array_merge($params, $gparams); + $sessions = array_merge($sessions, $DB->get_records_sql($sql, $params)); + foreach ($sessions as $sess) { if (empty($sess->description)) { $sess->description = get_string('nodescription', 'attendance'); @@ -1259,21 +1381,23 @@ class attendance { list($sql, $params) = $DB->get_in_or_equal($sessionsids); $DB->delete_records_select('attendance_log', "sessionid $sql", $params); $DB->delete_records_list('attendance_sessions', 'id', $sessionsids); - $this->log('sessions deleted', null, get_string('sessionsids', 'attendance').implode(', ', $sessionsids)); + add_to_log($this->course->id, 'attendance', 'sessions deleted', $this->url_manage(), + get_string('sessionsids', 'attendance').implode(', ', $sessionsids), $this->cm->id); } public function update_sessions_duration($sessionsids, $duration) { global $DB; $now = time(); - $sessions = $DB->get_records_list('attendance_sessions', 'id', $sessionsids); + $sessions = $DB->get_recordset_list('attendance_sessions', 'id', $sessionsids); foreach ($sessions as $sess) { $sess->duration = $duration; $sess->timemodified = $now; $DB->update_record('attendance_sessions', $sess); } - - $this->log('sessions duration updated', $this->url_manage(), get_string('sessionsids', 'attendance').implode(', ', $sessionsids)); + $sessions->close(); + add_to_log($this->course->id, 'attendance', 'sessions duration updated', $this->url_manage(), + get_string('sessionsids', 'attendance').implode(', ', $sessionsids), $this->cm->id); } public function remove_status($statusid) { @@ -1294,7 +1418,8 @@ class attendance { $rec->grade = $grade; $DB->insert_record('attendance_statuses', $rec); - $this->log('status added', $this->url_preferences(), $acronym.': '.$description.' ('.$grade.')'); + add_to_log($this->course->id, 'attendance', 'status added', $this->url_preferences(), + $acronym.': '.$description.' ('.$grade.')', $this->cm->id); } else { print_error('cantaddstatus', 'attendance', $this->url_preferences()); } @@ -1325,11 +1450,12 @@ class attendance { } $DB->update_record('attendance_statuses', $status); - $this->log('status updated', $this->url_preferences(), implode(' ', $updated)); + add_to_log($this->course->id, 'attendance', 'status updated', $this->url_preferences(), + implode(' ', $updated), $this->cm->id); } + } - function att_get_statuses($attid, $onlyvisible=true) { global $DB; @@ -1344,28 +1470,56 @@ function att_get_statuses($attid, $onlyvisible=true) { return $statuses; } -function att_get_user_taken_sessions_count($attid, $coursestartdate, $userid) { - global $DB; - - $qry = "SELECT count(*) as cnt +function att_get_user_taken_sessions_count($attid, $coursestartdate, $userid, $coursemodule, $startdate = '', $enddate = '') { + global $DB, $COURSE; + $groupmode = groups_get_activity_groupmode($coursemodule, $COURSE); + if (!empty($groupmode)) { + $qry = "SELECT count(*) as cnt + FROM {attendance_log} al + JOIN {attendance_sessions} ats ON al.sessionid = ats.id + LEFT JOIN {groups_members} gm ON gm.userid = al.studentid AND gm.groupid = ats.groupid + WHERE ats.attendanceid = :aid AND + ats.sessdate >= :cstartdate AND + al.studentid = :uid AND + (ats.groupid = 0 or gm.id is NOT NULL)"; + } else { + $qry = "SELECT count(*) as cnt FROM {attendance_log} al JOIN {attendance_sessions} ats ON al.sessionid = ats.id WHERE ats.attendanceid = :aid AND ats.sessdate >= :cstartdate AND al.studentid = :uid"; + } $params = array( - 'aid' => $attid, - 'cstartdate' => $coursestartdate, - 'uid' => $userid); + 'aid' => $attid, + 'cstartdate' => $coursestartdate, + 'uid' => $userid); + + if (!empty($startdate) && !empty($enddate)) { + $qry .= ' AND sessdate >= :sdate AND sessdate < :edate '; + $params['sdate'] = $startdate; + $params['edate'] = $enddate; + } return $DB->count_records_sql($qry, $params); } -function att_get_user_statuses_stat($attid, $coursestartdate, $userid) { - global $DB; - - $qry = "SELECT al.statusid, count(al.statusid) AS stcnt +function att_get_user_statuses_stat($attid, $coursestartdate, $userid, $coursemodule) { + global $DB, $COURSE; + $groupmode = groups_get_activity_groupmode($coursemodule, $COURSE); + if (!empty($groupmode)) { + $qry = "SELECT al.statusid, count(al.statusid) AS stcnt + FROM {attendance_log} al + JOIN {attendance_sessions} ats ON al.sessionid = ats.id + LEFT JOIN {groups_members} gm ON gm.userid = al.studentid AND gm.groupid = ats.groupid + WHERE ats.attendanceid = :aid AND + ats.sessdate >= :cstartdate AND + al.studentid = :uid AND + (ats.groupid = 0 or gm.id is NOT NULL) + GROUP BY al.statusid"; + } else { + $qry = "SELECT al.statusid, count(al.statusid) AS stcnt FROM {attendance_log} al JOIN {attendance_sessions} ats ON al.sessionid = ats.id @@ -1373,6 +1527,7 @@ function att_get_user_statuses_stat($attid, $coursestartdate, $userid) { ats.sessdate >= :cstartdate AND al.studentid = :uid GROUP BY al.statusid"; + } $params = array( 'aid' => $attid, 'cstartdate' => $coursestartdate, @@ -1429,7 +1584,7 @@ function att_get_gradebook_maxgrade($attid) { return $DB->get_field('attendance', 'grade', array('id' => $attid)); } -function att_update_all_users_grades($attid, $course, $context) { +function att_update_all_users_grades($attid, $course, $context, $coursemodule) { $grades = array(); $userids = array_keys(get_enrolled_users($context, 'mod/attendance:canbelisted', 0, 'u.id')); @@ -1439,8 +1594,8 @@ function att_update_all_users_grades($attid, $course, $context) { foreach ($userids as $userid) { $grade = new stdClass; $grade->userid = $userid; - $userstatusesstat = att_get_user_statuses_stat($attid, $course->startdate, $userid); - $usertakensesscount = att_get_user_taken_sessions_count($attid, $course->startdate, $userid); + $userstatusesstat = att_get_user_statuses_stat($attid, $course->startdate, $userid, $coursemodule); + $usertakensesscount = att_get_user_taken_sessions_count($attid, $course->startdate, $userid, $coursemodule); $usergrade = att_get_user_grade($userstatusesstat, $statuses); $usermaxgrade = att_get_user_max_grade($usertakensesscount, $statuses); $grade->rawgrade = att_calc_user_grade_fraction($usergrade, $usermaxgrade) * $gradebook_maxgrade; @@ -1471,6 +1626,14 @@ function att_log_convert_url(moodle_url $fullurl) { function attforblock_upgrade() { global $DB, $CFG; $module = $DB->get_record('modules', array('name' => 'attforblock')); + + // Deal with Moodle versions above 2013092001.02, where version is in config + $versioninmodtable = true; + if (!isset($module->version)) { + $versioninmodtable = false; + $module->version = get_config('mod_attforblock', 'version'); + } + if ($module->version <= '2011061800') { print_error("noupgradefromthisversion", 'attendance'); } @@ -1489,12 +1652,49 @@ function attforblock_upgrade() { } // Now convert module record. $module->name = 'attendance'; + if (!$versioninmodtable) { + set_config('version', $module->version, 'mod_attendance'); + unset($module->version); + } $DB->update_record('modules', $module); + // Now convert grade items to 'attendance' + $sql = "UPDATE {grade_items} + SET itemmodule = ? + WHERE itemmodule = ?"; + $DB->execute($sql, array('attendance', 'attforblock')); + + $sql = "UPDATE {grade_items_history} + SET itemmodule = 'attendance' + WHERE itemmodule = 'attforblock'"; + $DB->execute($sql); + + /* + * The user's custom capabilities need to be preserved due to the module renaming. + * Capabilities with a modifierid = 0 value are installed by default. + * Only update the user's custom capabilities where modifierid is not zero. + */ + $sql = $DB->sql_like('capability', '?').' AND modifierid <> 0'; + $rs = $DB->get_recordset_select('role_capabilities', $sql, array('%mod/attforblock%')); + foreach ($rs as $cap) { + $renamedcapability = str_replace('mod/attforblock', 'mod/attendance', $cap->capability); + $exists = $DB->record_exists('role_capabilities', array('roleid' => $cap->roleid, 'capability' => $renamedcapability)); + if (!$exists) { + $DB->update_record('role_capabilities', array('id' => $cap->id, 'capability' => $renamedcapability)); + } + } + + // Delete old role capabilities. + $sql = $DB->sql_like('capability', '?'); + $DB->delete_records_select('role_capabilities', $sql, array('%mod/attforblock%')); + + // Delete old capabilities. + $DB->delete_records_select('capabilities', 'component = ?', array('mod_attforblock')); + // Clear cache for courses with attendances. $attendances = $DB->get_recordset('attendance', array(), '', 'course'); foreach ($attendances as $attendance) { rebuild_course_cache($attendance->course, true); } $attendances->close(); -} \ No newline at end of file +} diff --git a/manage.php b/manage.php index 03a394c..0099d5e 100644 --- a/manage.php +++ b/manage.php @@ -31,6 +31,7 @@ $id = required_param('id', PARAM_INT); $from = optional_param('from', null, PARAM_ALPHANUMEXT); $pageparams->view = optional_param('view', null, PARAM_INT); $pageparams->curdate = optional_param('curdate', null, PARAM_INT); +$pageparams->perpage = get_config('attendance', 'resultsperpage'); $cm = get_coursemodule_from_id('attendance', $id, 0, false, MUST_EXIST); $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); diff --git a/preferences.php b/preferences.php index b597958..8597fdd 100644 --- a/preferences.php +++ b/preferences.php @@ -93,7 +93,9 @@ switch ($att->pageparams->action) { foreach ($acronym as $id => $v) { $att->update_status($id, $acronym[$id], $description[$id], $grade[$id], null); } - att_update_all_users_grades($att->id, $att->course, $att->context); + if ($att->grade > 0) { + att_update_all_users_grades($att->id, $att->course, $att->context, $cm); + } break; } diff --git a/renderables.php b/renderables.php index d62ede4..75c5324 100644 --- a/renderables.php +++ b/renderables.php @@ -269,9 +269,9 @@ class attendance_take_data implements renderable { public function __construct(attendance $att) { if ($att->pageparams->grouptype) { - $this->users = $att->get_users($att->pageparams->grouptype); + $this->users = $att->get_users($att->pageparams->grouptype, $att->pageparams->page); } else { - $this->users = $att->get_users($att->pageparams->group); + $this->users = $att->get_users($att->pageparams->group, $att->pageparams->page); } $this->pageparams = $att->pageparams; @@ -389,8 +389,8 @@ class attendance_user_data implements renderable { $this->maxgrade = array(); foreach ($this->coursesatts as $ca) { $statuses = att_get_statuses($ca->attid); - $user_taken_sessions_count = att_get_user_taken_sessions_count($ca->attid, $ca->coursestartdate, $userid); - $user_statuses_stat = att_get_user_statuses_stat($ca->attid, $ca->coursestartdate, $userid); + $user_taken_sessions_count = att_get_user_taken_sessions_count($ca->attid, $ca->coursestartdate, $userid, $att->cm); + $user_statuses_stat = att_get_user_statuses_stat($ca->attid, $ca->coursestartdate, $userid, $att->cm); $this->statuses[$ca->attid] = $statuses; @@ -468,7 +468,7 @@ class attendance_report_data implements renderable { $this->pageparams = $att->pageparams; - $this->users = $att->get_users($att->pageparams->group); + $this->users = $att->get_users($att->pageparams->group, $att->pageparams->page); $this->groups = groups_get_all_groups($att->course->id); diff --git a/renderer.php b/renderer.php index 7d06d88..9f43f0d 100644 --- a/renderer.php +++ b/renderer.php @@ -57,12 +57,14 @@ class mod_attendance_renderer extends plugin_renderer_base { $filtertable = new html_table(); $filtertable->attributes['class'] = ' '; $filtertable->width = '100%'; - $filtertable->align = array('left', 'center', 'right'); + $filtertable->align = array('left', 'center', 'right', 'right'); $filtertable->data[0][] = $this->render_sess_group_selector($fcontrols); $filtertable->data[0][] = $this->render_curdate_controls($fcontrols); + $filtertable->data[0][] = $this->render_paging_controls($fcontrols); + $filtertable->data[0][] = $this->render_view_controls($fcontrols); $o = html_writer::table($filtertable); @@ -91,6 +93,37 @@ class mod_attendance_renderer extends plugin_renderer_base { return ''; } + protected function render_paging_controls(attendance_filter_controls $fcontrols) { + global $CFG; + + $paging_controls = ''; + + $group = 0; + if (!empty($fcontrols->pageparams->group)) { + $group = $fcontrols->pageparams->group; + } + + $totalusers = count_enrolled_users(context_module::instance($fcontrols->cm->id), 'mod/attendance:canbelisted', $group); + + if (empty($fcontrols->pageparams->page) || !$fcontrols->pageparams->page || !$totalusers || empty($fcontrols->pageparams->perpage)) { + return $paging_controls; + } + + $numberofpages = ceil($totalusers / $fcontrols->pageparams->perpage); + + if ($fcontrols->pageparams->page > 1) { + $paging_controls .= html_writer::link($fcontrols->url(array('curdate' => $fcontrols->nextcur, 'page' => $fcontrols->pageparams->page - 1)), + $this->output->larrow()); + } + $paging_controls .= html_writer::tag('span', "Page {$fcontrols->pageparams->page} of $numberofpages", array('class' => 'attbtn')); + if ($fcontrols->pageparams->page < $numberofpages) { + $paging_controls .= html_writer::link($fcontrols->url(array('curdate' => $fcontrols->nextcur, 'page' => $fcontrols->pageparams->page + 1)), + $this->output->rarrow()); + } + + return $paging_controls ; + } + protected function render_curdate_controls(attendance_filter_controls $fcontrols) { global $CFG; @@ -283,14 +316,30 @@ class mod_attendance_renderer extends plugin_renderer_base { } else { $table = $this->render_attendance_take_grid($takedata); } - $table .= html_writer::input_hidden_params($takedata->url(array('sesskey' => sesskey()))); + $table .= html_writer::input_hidden_params($takedata->url(array('sesskey' => sesskey(), 'page' => $takedata->pageparams->page))); $params = array( 'type' => 'submit', 'value' => get_string('save', 'attendance')); $table .= html_writer::tag('center', html_writer::empty_tag('input', $params)); $table = html_writer::tag('form', $table, array('method' => 'post', 'action' => $takedata->url_path())); - return $controls.$table; + foreach($takedata->statuses as $status) { + $sessionstats[$status->id] = 0; + } + // Calculate the sum of statuses for each user + $sessionstats[] = array(); + foreach ($takedata->sessionlog as $userlog) { + foreach($takedata->statuses as $status) { + if ($userlog->statusid == $status->id) $sessionstats[$status->id]++; + } + } + + $statsoutput = '
'; + foreach($takedata->statuses as $status) { + $statsoutput .= "$status->description = ".$sessionstats[$status->id]."
"; + } + + return $controls.$table.$statsoutput; } protected function render_attendance_take_controls(attendance_take_data $takedata) { @@ -318,7 +367,47 @@ class mod_attendance_renderer extends plugin_renderer_base { } private function construct_take_controls(attendance_take_data $takedata) { + GLOBAL $CFG; + $controls = ''; + + $group = 0; + if ($takedata->pageparams->grouptype != attendance::SESSION_COMMON) { + $group = $takedata->pageparams->grouptype; + } else { + if ($takedata->pageparams->group) { + $group = $takedata->pageparams->group; + } + } + + if (!empty($CFG->enablegroupmembersonly) and $takedata->cm->groupmembersonly) { + if ($group == 0) { + $groups = array_keys(groups_get_all_groups($takedata->cm->course, 0, $takedata->cm->groupingid, 'g.id')); + } else { + $groups = $group; + } + $users = get_users_by_capability(context_module::instance($takedata->cm->id), 'mod/attendance:canbelisted', + 'u.id, u.firstname, u.lastname, u.email', + '', '', '', $groups, + '', false, true); + $totalusers = count($users); + } else { + $totalusers = count_enrolled_users(context_module::instance($takedata->cm->id), 'mod/attendance:canbelisted', $group); + } + $usersperpage = $takedata->pageparams->perpage; + if (!empty($takedata->pageparams->page) && $takedata->pageparams->page && $totalusers && $usersperpage) { + $controls .= html_writer::empty_tag('br'); + $numberofpages = ceil($totalusers / $usersperpage); + + if ($takedata->pageparams->page > 1) { + $controls .= html_writer::link($takedata->url(array('page' => $takedata->pageparams->page - 1)), $this->output->larrow()); + } + $controls .= html_writer::tag('span', "Page {$takedata->pageparams->page} of $numberofpages", array('class' => 'attbtn')); + if ($takedata->pageparams->page < $numberofpages) { + $controls .= html_writer::link($takedata->url(array('page' => $takedata->pageparams->page + 1)), $this->output->rarrow()); + } + } + if ($takedata->pageparams->grouptype == attendance::SESSION_COMMON and ($takedata->groupmode == VISIBLEGROUPS or ($takedata->groupmode and $takedata->perm->can_access_all_groups()))) { @@ -530,7 +619,8 @@ class mod_attendance_renderer extends plugin_renderer_base { } $params = array( 'type' => 'text', - 'name' => 'remarks'.$user->id); + 'name' => 'remarks'.$user->id, + 'maxlength' => 255); if (array_key_exists($user->id, $takedata->sessionlog)) { $params['value'] = $takedata->sessionlog[$user->id]->remarks; } @@ -619,8 +709,8 @@ class mod_attendance_renderer extends plugin_renderer_base { get_string('status', 'attendance'), get_string('remarks', 'attendance') ); - $table->align = array('', '', '', 'left', 'left', 'center', 'left'); - $table->size = array('1px', '1px', '1px', '1px', '*', '1px', '1px'); + $table->align = array('', '', '', 'left', 'left', 'center', 'left', 'center'); + $table->size = array('1px', '1px', '1px', '1px', '*', '1px', '1px', '*'); $i = 0; foreach ($userdata->sessionslog as $sess) { @@ -693,6 +783,7 @@ class mod_attendance_renderer extends plugin_renderer_base { $table->head[] = $this->construct_fullname_head($reportdata); $table->align[] = 'left'; $table->size[] = ''; + $sessionstats = array(); foreach ($reportdata->sessions as $sess) { $sesstext = userdate($sess->sessdate, get_string('strftimedm', 'attendance')); @@ -713,6 +804,7 @@ class mod_attendance_renderer extends plugin_renderer_base { $table->head[] = $status->acronym; $table->align[] = 'center'; $table->size[] = '1px'; + $sessionstats[$status->id] = 0; } if ($reportdata->gradable) { @@ -721,6 +813,12 @@ class mod_attendance_renderer extends plugin_renderer_base { $table->size[] = '1px'; } + if ($reportdata->sessionslog) { + $table->head[] = get_string('remarks', 'attendance'); + $table->align[] = 'center'; + $table->size[] = '200px'; + } + if ($bulkmessagecapability) { // Display the table header for bulk messaging. // The checkbox must have an id of cb_selector so that the JavaScript will pick it up. $table->head[] = html_writer::checkbox('cb_selector', 0, false, '', array('id' => 'cb_selector')); @@ -749,28 +847,59 @@ class mod_attendance_renderer extends plugin_renderer_base { $row->cells[] = $reportdata->grades[$user->id].' / '.$reportdata->maxgrades[$user->id]; } + if ($reportdata->sessionslog) { + if (isset($sess) && isset($reportdata->sessionslog[$user->id][$sess->id]->remarks)) { + $row->cells[] = $reportdata->sessionslog[$user->id][$sess->id]->remarks; + } else { + $row->cells[] = ''; + } + } + if ($bulkmessagecapability) { // Create the checkbox for bulk messaging. $row->cells[] = html_writer::checkbox('user'.$user->id, 'on', false); } - + $table->data[] = $row; } + // Calculate the sum of statuses for each user + $statrow = new html_table_row(); + $statrow->cells[] = ''; + $statrow->cells[] = get_string('summary'); + foreach ($reportdata->sessions as $sess) { + foreach ($reportdata->users as $user) { + foreach($reportdata->statuses as $status) { + if (!empty($reportdata->sessionslog[$user->id][$sess->id])) { + if ($reportdata->sessionslog[$user->id][$sess->id]->statusid == $status->id) $sessionstats[$status->id]++; + } + } + } + + $statsoutput = '
'; + foreach($reportdata->statuses as $status) { + $statsoutput .= "$status->description:".$sessionstats[$status->id]."
"; + } + $statrow->cells[] = $statsoutput; + + } + $table->data[] = $statrow; + if ($bulkmessagecapability) { // Require that the user can bulk message users. // Display check boxes that will allow the user to send a message to the students that have been checked. $output = html_writer::empty_tag('input', array('name' => 'sesskey', 'type' => 'hidden', 'value' => sesskey())); $output .= html_writer::empty_tag('input', array('name' => 'formaction', 'type' => 'hidden', 'value' => 'messageselect.php')); $output .= html_writer::empty_tag('input', array('name' => 'id', 'type' => 'hidden', 'value' => $GLOBALS['COURSE']->id)); $output .= html_writer::empty_tag('input', array('name' => 'returnto', 'type' => 'hidden', 'value' => s(me()))); - $output .= html_writer::table($table); + $output .= html_writer::table($table).html_writer::tag('div', get_string('users').': '.count($reportdata->users));; $output .= html_writer::tag('div', html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('messageselectadd'))), array('class' => 'buttons')); $url = new moodle_url('/user/action_redir.php'); return html_writer::tag('form', $output, array('action' => $url->out(), 'method' => 'post')); } else { - return html_writer::table($table); + return html_writer::table($table).html_writer::tag('div', get_string('users').': '.count($reportdata->users)); } + } protected function render_attendance_preferences_data(attendance_preferences_data $prefdata) { diff --git a/renderhelpers.php b/renderhelpers.php index e25bfb0..15ab178 100644 --- a/renderhelpers.php +++ b/renderhelpers.php @@ -43,7 +43,7 @@ class user_sessions_cells_generator { $this->user = $user; } - public function get_cells() { + public function get_cells($remarks = false) { $this->init_cells(); foreach ($this->reportdata->sessions as $sess) { if (array_key_exists($sess->id, $this->reportdata->sessionslog[$this->user->id])) { @@ -53,6 +53,9 @@ class user_sessions_cells_generator { } else { $this->construct_hidden_status_cell($this->reportdata->allstatuses[$statusid]->acronym); } + if ($remarks) { + $this->construct_remarks_cell($this->reportdata->sessionslog[$this->user->id][$sess->id]->remarks); + } } else { if ($this->user->enrolmentstart > $sess->sessdate) { $starttext = get_string('enrolmentstart', 'attendance', userdate($this->user->enrolmentstart, '%d.%m.%Y')); @@ -71,6 +74,9 @@ class user_sessions_cells_generator { $this->construct_not_existing_for_user_session_cell(''); } } + if ($remarks) { + $this->construct_remarks_cell(''); + } } } $this->finalize_cells(); @@ -97,6 +103,10 @@ class user_sessions_cells_generator { protected function construct_not_taken_cell($text) { $this->cells[] = $text; } + + protected function construct_remarks_cell($text) { + $this->cells[] = $text; + } protected function construct_not_existing_for_user_session_cell($text) { $this->cells[] = $text; @@ -150,6 +160,11 @@ class user_sessions_cells_html_generator extends user_sessions_cells_generator { $this->close_open_cell_if_needed(); $this->cells[] = $text; } + + protected function construct_remarks_cell($text) { + $this->close_open_cell_if_needed(); + $this->cells[] = $text; + } protected function construct_not_existing_for_user_session_cell($text) { $this->close_open_cell_if_needed(); @@ -239,17 +254,17 @@ function construct_user_data_stat($stat, $statuses, $gradable, $grade, $maxgrade return html_writer::table($stattable); } -function construct_full_user_stat_html_table($attendance, $course, $user) { +function construct_full_user_stat_html_table($attendance, $course, $user, $coursemodule) { global $CFG; $gradeable = $attendance->grade > 0; $statuses = att_get_statuses($attendance->id); - $userstatusesstat = att_get_user_statuses_stat($attendance->id, $course->startdate, $user->id); - $stat['completed'] = att_get_user_taken_sessions_count($attendance->id, $course->startdate, $user->id); + $userstatusesstat = att_get_user_statuses_stat($attendance->id, $course->startdate, $user->id, $coursemodule); + $stat['completed'] = att_get_user_taken_sessions_count($attendance->id, $course->startdate, $user->id, $coursemodule); $stat['statuses'] = $userstatusesstat; if ($gradeable) { $grade = att_get_user_grade($userstatusesstat, $statuses); $maxgrade = att_get_user_max_grade(att_get_user_taken_sessions_count($attendance->id, $course->startdate, - $user->id), $statuses); + $user->id, $coursemodule), $statuses); if (!$decimalpoints = grade_get_setting($course->id, 'decimalpoints')) { $decimalpoints = $CFG->grade_decimalpoints; } diff --git a/report.php b/report.php index addb4f6..b9d37eb 100644 --- a/report.php +++ b/report.php @@ -33,6 +33,8 @@ $pageparams->view = optional_param('view', null, PARAM_INT); $pageparams->curdate = optional_param('curdate', null, PARAM_INT); $pageparams->group = optional_param('group', null, PARAM_INT); $pageparams->sort = optional_param('sort', null, PARAM_INT); +$pageparams->page = optional_param('page', 1, PARAM_INT); +$pageparams->perpage = get_config('attendance', 'resultsperpage'); $cm = get_coursemodule_from_id('attendance', $id, 0, false, MUST_EXIST); $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); diff --git a/sessions.php b/sessions.php index ea44026..fda84fe 100644 --- a/sessions.php +++ b/sessions.php @@ -85,7 +85,9 @@ switch ($att->pageparams->action) { if (isset($confirm) && confirm_sesskey()) { $att->delete_sessions(array($sessionid)); - att_update_all_users_grades($att->id, $att->course, $att->context); + if ($att->grade > 0) { + att_update_all_users_grades($att->id, $att->course, $att->context, $cm); + } redirect($att->url_manage(), get_string('sessiondeleted', 'attendance')); } @@ -112,7 +114,9 @@ switch ($att->pageparams->action) { $sessionsids = explode('_', $sessionsids); $att->delete_sessions($sessionsids); - att_update_all_users_grades($att->id, $att->course, $att->context); + if ($att->grade > 0) { + att_update_all_users_grades($att->id, $att->course, $att->context, $cm); + } redirect($att->url_manage(), get_string('sessiondeleted', 'attendance')); } $sessid = required_param('sessid', PARAM_SEQUENCE); diff --git a/settings.php b/settings.php new file mode 100644 index 0000000..66c5805 --- /dev/null +++ b/settings.php @@ -0,0 +1,44 @@ +. + +/** + * Attendance plugin settings + * + * @package mod_attendance + * @copyright 2013 Netspot, Tim Lock. + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +if ($ADMIN->fulltree) { + require_once(dirname(__FILE__).'/lib.php'); + + // Paging options. + $options = array( + 0 => get_string('donotusepaging', 'attendance'), + 25 => 25, + 50 => 50, + 75 => 75, + 100 => 100, + 250 => 250, + 500 => 500, + 1000 => 1000, + ); + + $settings->add(new admin_setting_configselect('attendance/resultsperpage', + get_string('resultsperpage', 'attendance'), get_string('resultsperpage_desc', 'attendance'), 25, $options)); +} diff --git a/take.php b/take.php index d7c7ac0..4452927 100644 --- a/take.php +++ b/take.php @@ -34,6 +34,8 @@ $pageparams->sort = optional_param('sort', null, PARAM_INT); $pageparams->copyfrom = optional_param('copyfrom', null, PARAM_INT); $pageparams->viewmode = optional_param('viewmode', null, PARAM_INT); $pageparams->gridcols = optional_param('gridcols', null, PARAM_INT); +$pageparams->page = optional_param('page', 1, PARAM_INT); +$pageparams->perpage = get_config('attendance', 'resultsperpage'); $cm = get_coursemodule_from_id('attendance', $id, 0, false, MUST_EXIST); $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); diff --git a/version.php b/version.php index d36b123..ae31eea 100644 --- a/version.php +++ b/version.php @@ -22,12 +22,12 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -$module->version = 2013082901; -$module->requires = 2013040500; -$module->release = '2.5.1'; -$module->maturity = MATURITY_STABLE; -$module->cron = 0; -$module->component = 'mod_attendance'; +$plugin->version = 2014022801; +$plugin->requires = 2013040500; +$plugin->release = '2.6.1'; +$plugin->maturity = MATURITY_STABLE; +$plugin->cron = 0; +$plugin->component = 'mod_attendance'; // Nasty upgrade code to check if need to upgrade from attforblock. // TODO: remove this asap. diff --git a/view.php b/view.php index 19e288d..51e7eb4 100644 --- a/view.php +++ b/view.php @@ -63,7 +63,15 @@ $PAGE->navbar->add(get_string('attendancereport', 'attendance')); $output = $PAGE->get_renderer('mod_attendance'); -$userid = (isset($pageparams->studentid) && ($att->perm->can_manage() || $att->perm->can_take() || $att->perm->can_change())) ? $pageparams->studentid : $USER->id; +if (isset($pageparams->studentid) && $USER->id != $pageparams->studentid) { + // Only users with proper permissions should be able to see any user's individual report. + require_capability('mod/attendance:viewreports', $PAGE->context); + $userid = $pageparams->studentid; +} else { + // A valid request to see another users report has not been sent, show the user's own. + $userid = $USER->id; +} + $userdata = new attendance_user_data($att, $userid); echo $output->header();