Compare commits

...

65 Commits

Author SHA1 Message Date
Dan Marsden d8586f8ec2 Merge pull request #83 from barrysspace/expired_self_enrolments_MDL26 10 years ago
Barry Oosthuizen 70b0bf3c0e Check if there is a manual enrolment with no expiry date 10 years ago
Dan Marsden 17b751bc0c bump to fix bad version upgrade - thanks to Eric for the report! 10 years ago
Dan Marsden a6eb675cc4 Merge pull request #62 from eeisenhart/MOODLE_24-26_STABLE 10 years ago
Eric Eisenhart 4cf1a21108 Fix upgrade process for studentscanmark field. 10 years ago
Dan Marsden efb51bef7e bump version for plugins db 10 years ago
Dan Marsden e6d35f1c8e Revert "convert to using $plugin instead of $module" 10 years ago
Dan Marsden 8ea4f05d8e Merge pull request #54 from drjosephbaxter/MOODLE_24-26_STABLE 10 years ago
Joseph Baxter 797040cdb3 CONTRIB-5286 added drop down to show all rows or the set limit 10 years ago
Dan Marsden 258abeba87 tidy up string a bit. 10 years ago
Dan Marsden 80ab9e8075 CONTRIB-5287 fix paging so that the currdate doesn't change. 10 years ago
Dan Marsden effd1acc96 Allow older backup files to be restored correctly. 11 years ago
Dan Marsden ea15c2f505 Merge pull request #44 from drjosephbaxter/MOODLE_24-26_STABLE 11 years ago
Neill Magill 8de6c3eba4 Merged in drjosephbaxter/moodle-mod_attendance/UoNChanges (pull request #8) 11 years ago
Joseph Baxter c6cb46c4f3 changed tag 11 years ago
Joseph Baxter cc95000198 new steps definitions 11 years ago
Joseph Baxter 846653b85a added test of file export 11 years ago
Joseph Baxter e3b48d2ba2 behat tests for uon functionality 11 years ago
Neill Magill 38d102c56c Merged in drjosephbaxter/moodle-mod_attendance/UoNChanges (pull request #6) 11 years ago
Joseph Baxter b9ed00d3a8 bug fix for community issue: reportdata session log offset non existant 11 years ago
Joseph Baxter 717208e0f8 rework of previous fix 11 years ago
Joseph Baxter c221a04459 bug fix for issue on community branch - no per page param for students 11 years ago
Joseph Baxter 39f47348ae code review: use same version as community 11 years ago
Joseph Baxter bc9a079d38 code review changes 11 years ago
Joseph Baxter b2e962afae removed unecessary line 11 years ago
Joseph Baxter 5b1f3b2390 get_filtered_sessions and get_user_statuses_stat as per community 11 years ago
Joseph Baxter ba1d8545bf fixes: log url and report column order 11 years ago
Joseph Baxter 750a15a38d rebase changes 11 years ago
Joseph Baxter d4fd1f4b4d fixing whitespce 11 years ago
Joseph Baxter 55856e6d4e code review change new line without whitespace 11 years ago
Joseph Baxter c3383a6d86 code review: removed new line 11 years ago
Joseph Baxter 48f4d81618 typo 11 years ago
Joseph Baxter 6dd38ca34f tidy up 11 years ago
Joseph Baxter 105f3598ba MOODLE-845 add department and institution 11 years ago
Joseph Baxter 127a72ed39 MOODLE-845 add idnumber to export 11 years ago
Joseph Baxter d217f7ed90 changes attforblock to attendance 11 years ago
Joseph Baxter 11660b2379 removed duplicate log word 11 years ago
Joseph Baxter e5a4dbb12c found log function in attforblock 11 years ago
Joseph Baxter 3272e7f45d low grade report fix 11 years ago
Joseph Baxter ba31d7ad83 fix for log page link 11 years ago
Joseph Baxter 91d19e10ea first round of fixes 11 years ago
Neill Magill c3ea7631ed UoN Changes to allow students to mark their own attendance on sessions that have been set to allow it. 11 years ago
Dan Marsden a7c20c31c9 remove double semi-colon 11 years ago
Nadav Kavalerchik 05ea479905 Display the number of users in the sessions report (take II) 11 years ago
Dan Marsden 6cbe540549 init sessionstat vars correctly 11 years ago
Dan Marsden ce9eb2a16f remove php warning from report page when no sessions exist 11 years ago
Neill Magill 24683d313d Merged in drjosephbaxter/moodle-mod_attendance/UoNChanges (pull request #2) 11 years ago
Joseph Baxter 89b1c5cf2a fixing whitespce 11 years ago
Joseph Baxter cdd1079f66 code review change new line without whitespace 11 years ago
Joseph Baxter a1e9d1ff60 code review: removed new line 11 years ago
Joseph Baxter aa12bb4f22 typo 11 years ago
Joseph Baxter 2de47f26ce tidy up 11 years ago
Joseph Baxter 8ddd624c6c MOODLE-845 add department and institution 11 years ago
Joseph Baxter 4be6603034 MOODLE-845 add idnumber to export 11 years ago
Neill Magill b0da107108 Merged in drjosephbaxter/moodle-mod_attendance/UoNChanges (pull request #1) 11 years ago
Joseph Baxter 5909afa1a4 changes attforblock to attendance 11 years ago
Joseph Baxter d39f0367f1 removed duplicate log word 11 years ago
Joseph Baxter 28bc551ab4 found log function in attforblock 11 years ago
Joseph Baxter 066ac50602 low grade report fix 11 years ago
Joseph Baxter db23bb526f fix for log page link 11 years ago
Joseph Baxter ee20e101bb first round of fixes 11 years ago
Dan Marsden 52d116dbb7 convert to using $plugin instead of $module 11 years ago
Dan Marsden 53c8be2acd bump version of stable release to include latest fixes 11 years ago
Dan Marsden 116c4d55ee CONTRIB-4864 prevent PHP warning when checking var 11 years ago
Neill Magill 5dc2534a87 UoN Changes to allow students to mark their own attendance on sessions that have been set to allow it. 11 years ago
  1. 4
      add_form.php
  2. 84
      attendance.php
  3. 4
      backup/moodle2/backup_attendance_activity_task.class.php
  4. 6
      backup/moodle2/restore_attendance_activity_task.class.php
  5. 1
      db/install.xml
  6. 12
      db/upgrade.php
  7. 17
      export.php
  8. 8
      export_form.php
  9. 13
      lang/en/attendance.php
  10. 136
      locallib.php
  11. 30
      renderables.php
  12. 81
      renderer.php
  13. 2
      report.php
  14. 6
      sessions.php
  15. 63
      student_attenance_form.php
  16. 2
      take.php
  17. 105
      tests/behat/attendance_mod.feature
  18. 116
      tests/behat/behat_mod_attendance.php
  19. 4
      version.php

4
add_form.php

@ -103,6 +103,10 @@ class mod_attendance_add_form extends moodleform {
$mform->addElement('checkbox', 'addmultiply', '', get_string('createmultiplesessions', 'attendance')); $mform->addElement('checkbox', 'addmultiply', '', get_string('createmultiplesessions', 'attendance'));
$mform->addHelpButton('addmultiply', 'createmultiplesessions', 'attendance'); $mform->addHelpButton('addmultiply', 'createmultiplesessions', 'attendance');
// Students can mark own attendance.
$mform->addElement('checkbox', 'studentscanmark', '', get_string('studentscanmark','attendance'));
$mform->addHelpButton('studentscanmark', 'studentscanmark', 'attendance');
$mform->addElement('date_time_selector', 'sessiondate', get_string('sessiondate', 'attendance')); $mform->addElement('date_time_selector', 'sessiondate', get_string('sessiondate', 'attendance'));
for ($i=0; $i<=23; $i++) { for ($i=0; $i<=23; $i++) {

84
attendance.php

@ -0,0 +1,84 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Prints attendance info for particular user
*
* @package mod
* @subpackage attendance
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(dirname(__FILE__).'/../../config.php');
require_once(dirname(__FILE__).'/locallib.php');
require_once(dirname(__FILE__).'/student_attenance_form.php');
$pageparams = new att_sessions_page_params();
// Check that the required parameters are present.
$id = required_param('sessid', PARAM_INT);
$attendance_session_id = required_param('sessid', PARAM_INT);
$attforsession = $DB->get_record('attendance_sessions', array('id' => $id), '*', MUST_EXIST);
$attendance = $DB->get_record('attendance', array('id' => $attforsession->attendanceid), '*', MUST_EXIST);
$cm = get_coursemodule_from_instance('attendance', $attendance->id, 0, false, MUST_EXIST);
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
// Require the user is logged in.
require_login($course, true, $cm);
$pageparams->sessionid = $id;
$att = new attendance($attendance, $cm, $course, $PAGE->context, $pageparams);
// Require that a session key is passed to this page.
require_sesskey();
// Create the form.
$mform = new mod_attendance_student_attendance_form(null,
array('course' => $course, 'cm' => $cm, 'modcontext' => $PAGE->context, 'session' => $attforsession, 'attendance' => $att));
if ($mform->is_cancelled()) {
// The user cancelled the form, so redirect them to the view page.
$url = new moodle_url('/mod/attendance/view.php', array('id' => $cm->id));
redirect($url);
} else if ($fromform = $mform->get_data()) {
if (!empty($fromform->status)) {
$success = $att->take_from_student($fromform);
$url = new moodle_url('/mod/attendance/view.php', array('id' => $cm->id));
if ($success) {
// Redirect back to the view page for the block.
redirect($url);
} else {
print_error ('attendance_already_submitted', 'mod_attendance', $url);
}
}
// The form did not validate correctly so we will set it to display the data they submitted.
$mform->set_data($fromform);
}
$PAGE->set_url($att->url_sessions());
$PAGE->set_title($course->shortname. ": ".$att->name);
$PAGE->set_heading($course->fullname);
$PAGE->set_cacheable(true);
$PAGE->navbar->add($att->name);
$output = $PAGE->get_renderer('mod_attendance');
echo $output->header();
$mform->display();
echo $output->footer();

4
backup/moodle2/backup_attendance_activity_task.class.php

@ -60,11 +60,11 @@ class backup_attendance_activity_task extends backup_activity_task {
// Link to attendance view by moduleid. // Link to attendance view by moduleid.
$search = "/(" . $base . "\/mod\/attendance\/view.php\?id\=)([0-9]+)/"; $search = "/(" . $base . "\/mod\/attendance\/view.php\?id\=)([0-9]+)/";
$content= preg_replace($search, '$@ATTFORBLOCKVIEWBYID*$2@$', $content); $content= preg_replace($search, '$@ATTENDANCEVIEWBYID*$2@$', $content);
// Link to attendance view by moduleid and studentid. // Link to attendance view by moduleid and studentid.
$search = "/(" . $base . "\/mod\/attendance\/view.php\?id\=)([0-9]+)\&studentid\=([0-9]+)/"; $search = "/(" . $base . "\/mod\/attendance\/view.php\?id\=)([0-9]+)\&studentid\=([0-9]+)/";
$content= preg_replace($search, '$@ATTFORBLOCKVIEWBYIDSTUD*$2*$3@$', $content); $content= preg_replace($search, '$@ATTENDANCEVIEWBYIDSTUD*$2*$3@$', $content);
return $content; return $content;
} }

6
backup/moodle2/restore_attendance_activity_task.class.php

@ -67,6 +67,12 @@ class restore_attendance_activity_task extends restore_activity_task {
static public function define_decode_rules() { static public function define_decode_rules() {
$rules = array(); $rules = array();
$rules[] = new restore_decode_rule('ATTENDANCEVIEWBYID',
'/mod/attendance/view.php?id=$1', 'course_module');
$rules[] = new restore_decode_rule('ATTENDANCEVIEWBYIDSTUD',
'/mod/attendance/view.php?id=$1&studentid=$2', array('course_module', 'user'));
// Older style backups using previous plugin name
$rules[] = new restore_decode_rule('ATTFORBLOCKVIEWBYID', $rules[] = new restore_decode_rule('ATTFORBLOCKVIEWBYID',
'/mod/attendance/view.php?id=$1', 'course_module'); '/mod/attendance/view.php?id=$1', 'course_module');
$rules[] = new restore_decode_rule('ATTFORBLOCKVIEWBYIDSTUD', $rules[] = new restore_decode_rule('ATTFORBLOCKVIEWBYIDSTUD',

1
db/install.xml

@ -30,6 +30,7 @@
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/> <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="description" TYPE="text" NOTNULL="true" SEQUENCE="false"/> <FIELD NAME="description" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="descriptionformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/> <FIELD NAME="descriptionformat" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="studentscanmark" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false"/>
</FIELDS> </FIELDS>
<KEYS> <KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for attendance_sessions"/> <KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for attendance_sessions"/>

12
db/upgrade.php

@ -73,5 +73,17 @@ function xmldb_attendance_upgrade($oldversion=0) {
upgrade_plugin_savepoint($result, 2013082902, 'mod', 'attendance'); upgrade_plugin_savepoint($result, 2013082902, 'mod', 'attendance');
} }
if ($oldversion < 2014022803) {
$table = new xmldb_table('attendance_sessions');
$field = new xmldb_field('studentscanmark');
$field->set_attributes(XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
upgrade_mod_savepoint($result, 2014022803, 'attendance');
}
return $result; return $result;
} }

17
export.php

@ -88,6 +88,14 @@ if ($mform->is_submitted()) {
if (isset($formdata->ident['uname'])) { if (isset($formdata->ident['uname'])) {
$data->tabhead[] = get_string('username'); $data->tabhead[] = get_string('username');
} }
$optional = array('idnumber', 'institution', 'department');
foreach ($optional as $opt) {
if (isset($formdata->ident[$opt])) {
$data->tabhead[] = get_string($opt);
}
}
$data->tabhead[] = get_string('lastname'); $data->tabhead[] = get_string('lastname');
$data->tabhead[] = get_string('firstname'); $data->tabhead[] = get_string('firstname');
$groupmode = groups_get_activity_groupmode($cm, $course); $groupmode = groups_get_activity_groupmode($cm, $course);
@ -95,7 +103,6 @@ if ($mform->is_submitted()) {
$data->tabhead[] = get_string('groups'); $data->tabhead[] = get_string('groups');
} }
if (count($reportdata->sessions) > 0) { if (count($reportdata->sessions) > 0) {
foreach ($reportdata->sessions as $sess) { foreach ($reportdata->sessions as $sess) {
$text = userdate($sess->sessdate, get_string('strftimedmyhm', 'attendance')); $text = userdate($sess->sessdate, get_string('strftimedmyhm', 'attendance'));
@ -122,6 +129,14 @@ if ($mform->is_submitted()) {
if (isset($formdata->ident['uname'])) { if (isset($formdata->ident['uname'])) {
$data->table[$i][] = $user->username; $data->table[$i][] = $user->username;
} }
$optional_row = array('idnumber', 'institution', 'department');
foreach ($optional_row as $opt) {
if (isset($formdata->ident[$opt])) {
$data->table[$i][] = $user->$opt;
}
}
$data->table[$i][] = $user->lastname; $data->table[$i][] = $user->lastname;
$data->table[$i][] = $user->firstname; $data->table[$i][] = $user->firstname;
if (!empty($groupmode)) { if (!empty($groupmode)) {

8
export_form.php

@ -62,8 +62,14 @@ class mod_attendance_export_form extends moodleform {
$ident = array(); $ident = array();
$ident[] =& $mform->createElement('checkbox', 'id', '', get_string('studentid', 'attendance')); $ident[] =& $mform->createElement('checkbox', 'id', '', get_string('studentid', 'attendance'));
$ident[] =& $mform->createElement('checkbox', 'uname', '', get_string('username')); $ident[] =& $mform->createElement('checkbox', 'uname', '', get_string('username'));
$optional = array('idnumber', 'institution', 'department');
foreach ($optional as $opt) {
$ident[] =& $mform->createElement('checkbox', $opt, '', get_string($opt));
$mform->setType($opt, PARAM_NOTAGS);
}
$mform->addGroup($ident, 'ident', get_string('identifyby', 'attendance'), array('<br />'), true); $mform->addGroup($ident, 'ident', get_string('identifyby', 'attendance'), array('<br />'), true);
$mform->setDefaults(array('ident[id]' => true, 'ident[uname]' => true)); $mform->setDefaults(array('ident[id]' => true, 'ident[uname]' => true));
$mform->setType('id', PARAM_INT); $mform->setType('id', PARAM_INT);

13
lang/en/attendance.php

@ -114,10 +114,9 @@ For example, if you have earned 8 of 10 points to date (80% attendance) and atte
$string['gridcolumns'] = 'Grid columns'; $string['gridcolumns'] = 'Grid columns';
$string['groupsession'] = 'Group'; $string['groupsession'] = 'Group';
$string['hiddensessions'] = 'Hidden sessions'; $string['hiddensessions'] = 'Hidden sessions';
$string['hiddensessions_help'] = ' $string['hiddensessions_help'] = 'Sessions are hidden if they are scheduled before the course start date.
Session hides if course\'s start date older than its date. Change start date of course and hidden sessions will be shown.
You can use this feature to hide older sessions instead delete. Remember than only visible sessions using in Gradebook.'; You can use this feature to hide older sessions instead of deleting them. Only visible sessions will appear in the Gradebook.';
$string['identifyby'] = 'Identify student by'; $string['identifyby'] = 'Identify student by';
$string['includeall'] = 'Select all sessions'; $string['includeall'] = 'Select all sessions';
$string['includenottaken'] = 'Include not taken sessions'; $string['includenottaken'] = 'Include not taken sessions';
@ -216,3 +215,11 @@ $string['viewmode'] = 'View mode';
$string['week'] = 'week(s)'; $string['week'] = 'week(s)';
$string['weeks'] = 'Weeks'; $string['weeks'] = 'Weeks';
$string['youcantdo'] = 'You can\'t do anything'; $string['youcantdo'] = 'You can\'t do anything';
// New strings.
$string['studentscanmark'] = 'Allow students to record own attendance';
$string['studentscanmark_help'] = 'If checked students will be able to change their own attendance status for the session.';
$string['set_by_student'] = 'Self-recorded';
$string['attendance_already_submitted'] = 'You may not self register attendance that has already been set.';
$string['lowgrade'] = 'Low grade';
$string['submitattendance'] = 'Submit attendance';
$string['attendancenotset'] = 'You must set your attendance';

136
locallib.php

@ -33,6 +33,7 @@ define('ATT_VIEW_WEEKS', 2);
define('ATT_VIEW_MONTHS', 3); define('ATT_VIEW_MONTHS', 3);
define('ATT_VIEW_ALLPAST', 4); define('ATT_VIEW_ALLPAST', 4);
define('ATT_VIEW_ALL', 5); define('ATT_VIEW_ALL', 5);
define('ATT_VIEW_NOTPRESENT', 6);
define('ATT_SORT_LASTNAME', 1); define('ATT_SORT_LASTNAME', 1);
define('ATT_SORT_FIRSTNAME', 2); define('ATT_SORT_FIRSTNAME', 2);
@ -701,6 +702,8 @@ class attendance {
if ($this->pageparams->startdate && $this->pageparams->enddate) { if ($this->pageparams->startdate && $this->pageparams->enddate) {
$where = "attendanceid = :aid AND sessdate >= :csdate AND sessdate >= :sdate AND sessdate < :edate"; $where = "attendanceid = :aid AND sessdate >= :csdate AND sessdate >= :sdate AND sessdate < :edate";
} else if ($this->pageparams->enddate) {
$where = "attendanceid = :aid AND sessdate >= :csdate AND sessdate < :edate";
} else { } else {
$where = "attendanceid = :aid AND sessdate >= :csdate"; $where = "attendanceid = :aid AND sessdate >= :csdate";
} }
@ -807,6 +810,7 @@ class attendance {
} }
$i++; $i++;
} }
add_to_log($this->course->id, 'attendance', 'sessions added', $this->url_manage(), add_to_log($this->course->id, 'attendance', 'sessions added', $this->url_manage(),
implode(',', $info_array), $this->cm->id); implode(',', $info_array), $this->cm->id);
} }
@ -833,6 +837,65 @@ class attendance {
add_to_log($this->course->id, 'attendance', 'session updated', $url, $info, $this->cm->id); add_to_log($this->course->id, 'attendance', 'session updated', $url, $info, $this->cm->id);
} }
/**
* Used to record attendance submitted by the student.
*
* @global type $DB
* @global type $USER
* @param type $mformdata
* @return boolean
*/
public function take_from_student($mformdata) {
global $DB, $USER;
$statuses = implode(',', array_keys( (array)$this->get_statuses() ));
$now = time();
$record = new stdClass();
$record->studentid = $USER->id;
$record->statusid = $mformdata->status;
$record->statusset = $statuses;
$record->remarks = get_string('set_by_student', 'mod_attendance');
$record->sessionid = $mformdata->sessid;
$record->timetaken = $now;
$record->takenby = $USER->id;
$dbsesslog = $this->get_session_log($mformdata->sessid);
if (array_key_exists($record->studentid, $dbsesslog)) {
// Already recorded do not save.
return false;
}
else {
$DB->insert_record('attendance_log', $record, false);
}
// Update the session to show that a register has been taken, or staff may overwrite records.
$rec = new object();
$rec->id = $mformdata->sessid;
$rec->lasttaken = $now;
$rec->lasttakenby = $USER->id;
$DB->update_record('attendance_sessions', $rec);
// Update the users grade.
$this->update_users_grade(array($USER->id));
/* create url for link in log screen
* need to set grouptype to 0 to allow take attendance page to be called
* from report/log page */
$params = array(
'sessionid' => $this->pageparams->sessionid,
'grouptype' => 0);
$url = $this->url_take($params);
$logurl = att_log_convert_url($url);
// Log the change.
add_to_log($this->course->id, 'attendance', 'taken by student', $logurl, '', $this->cm->id);
return true;
}
public function take_from_form_data($formdata) { public function take_from_form_data($formdata) {
global $DB, $USER; global $DB, $USER;
// TODO: WARNING - $formdata is unclean - comes from direct $_POST - ideally needs a rewrite but we do some cleaning below. // TODO: WARNING - $formdata is unclean - comes from direct $_POST - ideally needs a rewrite but we do some cleaning below.
@ -880,11 +943,16 @@ class attendance {
$this->update_users_grade(array_keys($sesslog)); $this->update_users_grade(array_keys($sesslog));
} }
// create url for link in log screen
$params = array( $params = array(
'sessionid' => $this->pageparams->sessionid, 'sessionid' => $this->pageparams->sessionid,
'grouptype' => $this->pageparams->grouptype); 'grouptype' => $this->pageparams->grouptype);
$url = $this->url_take($params); $url = $this->url_take($params);
add_to_log($this->course->id, 'attendance', 'taken', $url, '', $this->cm->id); $logurl = att_log_convert_url($url);
// Log the change.
add_to_log($this->course->id, 'attendance', 'taken', $logurl, '', $this->cm->id);
$group = 0; $group = 0;
if ($this->pageparams->grouptype != attendance::SESSION_COMMON) { if ($this->pageparams->grouptype != attendance::SESSION_COMMON) {
@ -916,12 +984,12 @@ class attendance {
global $DB, $CFG; global $DB, $CFG;
// Fields we need from the user table. // Fields we need from the user table.
$userfields = user_picture::fields('u', array('username')); $userfields = user_picture::fields('u', array('username' , 'idnumber' , 'institution' , 'department'));
if (isset($this->pageparams->sort) and ($this->pageparams->sort == ATT_SORT_FIRSTNAME)) { if (isset($this->pageparams->sort) and ($this->pageparams->sort == ATT_SORT_FIRSTNAME)) {
$orderby = "u.firstname ASC, u.lastname ASC"; $orderby = "u.firstname ASC, u.lastname ASC, u.idnumber ASC, u.institution ASC, u.department ASC";
} else { } else {
$orderby = "u.lastname ASC, u.firstname ASC"; $orderby = "u.lastname ASC, u.firstname ASC, u.idnumber ASC, u.institution ASC, u.department ASC";
} }
if ($page) { if ($page) {
@ -963,7 +1031,7 @@ class attendance {
// CONTRIB-4868 // CONTRIB-4868
$mintime = 'MIN(CASE WHEN (ue.timestart > :zerotime) THEN ue.timestart ELSE ue.timecreated END)'; $mintime = 'MIN(CASE WHEN (ue.timestart > :zerotime) THEN ue.timestart ELSE ue.timecreated END)';
$maxtime = 'MAX(ue.timeend)'; $maxtime = 'CASE WHEN MIN(ue.timeend) = 0 THEN 0 ELSE MAX(ue.timeend) END';
// CONTRIB-3549 // CONTRIB-3549
$sql = "SELECT ue.userid, ue.status, $sql = "SELECT ue.userid, ue.status,
@ -1073,7 +1141,7 @@ class attendance {
public function get_user_taken_sessions_count($userid) { public function get_user_taken_sessions_count($userid) {
if (!array_key_exists($userid, $this->usertakensesscount)) { if (!array_key_exists($userid, $this->usertakensesscount)) {
if ($this->pageparams->startdate && $this->pageparams->enddate) { 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); $this->usertakensesscount[$userid] = att_get_user_taken_sessions_count($this->id, $this->course->startdate, $userid, $this->cm, $this->pageparams->startdate, $this->pageparams->enddate);
} else { } else {
$this->usertakensesscount[$userid] = att_get_user_taken_sessions_count($this->id, $this->course->startdate, $userid, $this->cm); $this->usertakensesscount[$userid] = att_get_user_taken_sessions_count($this->id, $this->course->startdate, $userid, $this->cm);
@ -1082,13 +1150,36 @@ class attendance {
return $this->usertakensesscount[$userid]; return $this->usertakensesscount[$userid];
} }
public function get_user_statuses_stat($userid) { /**
*
* @global type $DB
* @param type $userid
* @param type $filters - An array things to filter by. For now only enddate is valid.
* @return type
*/
public function get_user_statuses_stat($userid, array $filters = null) {
global $DB; global $DB;
$params = array( $params = array(
'aid' => $this->id, 'aid' => $this->id,
'cstartdate' => $this->course->startdate, 'cstartdate' => $this->course->startdate,
'uid' => $userid); 'uid' => $userid);
$processed_filters = array();
// We test for any valid filters sent.
if (isset($filters['enddate'])) {
$processed_filters[] = 'ats.sessdate <= :enddate';
$params['enddate'] = $filters['enddate'];
}
// Make the filter array into a SQL string.
if (!empty($processed_filters)) {
$processed_filters = ' AND '.implode(' AND ', $processed_filters);
} else {
$processed_filters = '';
}
$period = ''; $period = '';
if (!empty($this->pageparams->startdate) && !empty($this->pageparams->enddate)) { if (!empty($this->pageparams->startdate) && !empty($this->pageparams->enddate)) {
$period = ' AND ats.sessdate >= :sdate AND ats.sessdate < :edate '; $period = ' AND ats.sessdate >= :sdate AND ats.sessdate < :edate ';
@ -1096,7 +1187,6 @@ class attendance {
$params['edate'] = $this->pageparams->enddate; $params['edate'] = $this->pageparams->enddate;
} }
if (!array_key_exists($userid, $this->userstatusesstat)) {
if ($this->get_group_mode()) { if ($this->get_group_mode()) {
$qry = "SELECT al.statusid, count(al.statusid) AS stcnt $qry = "SELECT al.statusid, count(al.statusid) AS stcnt
FROM {attendance_log} al FROM {attendance_log} al
@ -1105,7 +1195,7 @@ class attendance {
WHERE ats.attendanceid = :aid AND WHERE ats.attendanceid = :aid AND
ats.sessdate >= :cstartdate AND ats.sessdate >= :cstartdate AND
al.studentid = :uid AND al.studentid = :uid AND
(ats.groupid = 0 or gm.id is NOT NULL)".$period." (ats.groupid = 0 or gm.id is NOT NULL)".$period.$processed_filters."
GROUP BY al.statusid"; GROUP BY al.statusid";
} else { } else {
$qry = "SELECT al.statusid, count(al.statusid) AS stcnt $qry = "SELECT al.statusid, count(al.statusid) AS stcnt
@ -1114,20 +1204,30 @@ class attendance {
ON al.sessionid = ats.id ON al.sessionid = ats.id
WHERE ats.attendanceid = :aid AND WHERE ats.attendanceid = :aid AND
ats.sessdate >= :cstartdate AND ats.sessdate >= :cstartdate AND
al.studentid = :uid".$period." al.studentid = :uid".$period.$processed_filters."
GROUP BY al.statusid"; 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.
$this->userstatusesstat[$userid] = $DB->get_records_sql($qry, $params); $this->userstatusesstat[$userid] = $DB->get_records_sql($qry, $params);
} }
// Return the cached stats.
return $this->userstatusesstat[$userid]; return $this->userstatusesstat[$userid];
} }
public function get_user_grade($userid) { /**
return att_get_user_grade($this->get_user_statuses_stat($userid), $this->get_statuses()); *
* @param type $userid
* @param type $filters - An array things to filter by. For now only enddate is valid.
* @return type
*/
public function get_user_grade($userid, array $filters = null) {
return att_get_user_grade($this->get_user_statuses_stat($userid, $filters), $this->get_statuses());
} }
// For getting sessions count implemented simplest method - taken sessions. // For getting sessions count implemented simplest method - taken sessions.
@ -1215,7 +1315,7 @@ class attendance {
// It would be better as a UNION query butunfortunatly MS SQL does not seem to support doing a DISTINCT on a the description field. // 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'); $id = $DB->sql_concat(':value', 'ats.id');
if ($this->get_group_mode()) { if ($this->get_group_mode()) {
$sql = "SELECT $id, ats.id, ats.groupid, ats.sessdate, ats.duration, ats.description, al.statusid, al.remarks $sql = "SELECT $id, ats.id, ats.groupid, ats.sessdate, ats.duration, ats.description, al.statusid, al.remarks, ats.studentscanmark
FROM {attendance_sessions} ats FROM {attendance_sessions} ats
RIGHT JOIN {attendance_log} al RIGHT JOIN {attendance_log} al
ON ats.id = al.sessionid AND al.studentid = :uid ON ats.id = al.sessionid AND al.studentid = :uid
@ -1223,7 +1323,7 @@ class attendance {
WHERE $where AND (ats.groupid = 0 or gm.id is NOT NULL) WHERE $where AND (ats.groupid = 0 or gm.id is NOT NULL)
ORDER BY ats.sessdate ASC"; ORDER BY ats.sessdate ASC";
} else { } else {
$sql = "SELECT $id, ats.id, ats.groupid, ats.sessdate, ats.duration, ats.description, al.statusid, al.remarks $sql = "SELECT $id, ats.id, ats.groupid, ats.sessdate, ats.duration, ats.description, al.statusid, al.remarks, ats.studentscanmark
FROM {attendance_sessions} ats FROM {attendance_sessions} ats
RIGHT JOIN {attendance_log} al RIGHT JOIN {attendance_log} al
ON ats.id = al.sessionid AND al.studentid = :uid ON ats.id = al.sessionid AND al.studentid = :uid
@ -1253,7 +1353,7 @@ class attendance {
$where = "ats.attendanceid = :aid AND ats.sessdate >= :csdate AND ats.groupid $gsql"; $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 $sql = "SELECT $id, ats.id, ats.groupid, ats.sessdate, ats.duration, ats.description, al.statusid, al.remarks, ats.studentscanmark
FROM {attendance_sessions} ats FROM {attendance_sessions} ats
LEFT JOIN {attendance_log} al LEFT JOIN {attendance_log} al
ON ats.id = al.sessionid AND al.studentid = :uid ON ats.id = al.sessionid AND al.studentid = :uid
@ -1353,8 +1453,8 @@ class attendance {
add_to_log($this->course->id, 'attendance', 'status updated', $this->url_preferences(), add_to_log($this->course->id, 'attendance', 'status updated', $this->url_preferences(),
implode(' ', $updated), $this->cm->id); implode(' ', $updated), $this->cm->id);
} }
}
}
function att_get_statuses($attid, $onlyvisible=true) { function att_get_statuses($attid, $onlyvisible=true) {
global $DB; global $DB;

30
renderables.php

@ -109,19 +109,23 @@ class attendance_filter_controls implements renderable {
public $prevcur; public $prevcur;
public $nextcur; public $nextcur;
public $curdatetxt; public $curdatetxt;
public $reportcontrol;
private $urlpath; private $urlpath;
private $urlparams; private $urlparams;
private $att; private $att;
public function __construct(attendance $att) { public function __construct(attendance $att, $report = false) {
global $PAGE; global $PAGE;
$this->pageparams = $att->pageparams; $this->pageparams = $att->pageparams;
$this->cm = $att->cm; $this->cm = $att->cm;
// This is a report control only if $reports is true and the attendance block can be graded.
$this->reportcontrol = $report && ($att->grade > 0);
$this->curdate = $att->pageparams->curdate; $this->curdate = $att->pageparams->curdate;
$date = usergetdate($att->pageparams->curdate); $date = usergetdate($att->pageparams->curdate);
@ -456,6 +460,12 @@ class attendance_report_data implements renderable {
global $CFG; global $CFG;
$this->perm = $att->perm; $this->perm = $att->perm;
$currenttime = time();
if ($att->pageparams->view == ATT_VIEW_NOTPRESENT) {
$att->pageparams->enddate = $currenttime;
}
$this->pageparams = $att->pageparams; $this->pageparams = $att->pageparams;
$this->users = $att->get_users($att->pageparams->group, $att->pageparams->page); $this->users = $att->get_users($att->pageparams->group, $att->pageparams->page);
@ -473,7 +483,16 @@ class attendance_report_data implements renderable {
$this->decimalpoints = $CFG->grade_decimalpoints; $this->decimalpoints = $CFG->grade_decimalpoints;
} }
foreach ($this->users as $user) { $maxgrade = att_get_user_max_grade(count($this->sessions), $this->statuses);
foreach ($this->users as $key => $user) {
$grade = 0;
if ($this->gradable) {
$grade = $att->get_user_grade($user->id, array('enddate' => $currenttime));
$totalgrade = $att->get_user_grade($user->id);
}
if ($att->pageparams->view != ATT_VIEW_NOTPRESENT || $grade < $maxgrade) {
$this->usersgroups[$user->id] = groups_get_all_groups($att->course->id, $user->id); $this->usersgroups[$user->id] = groups_get_all_groups($att->course->id, $user->id);
$this->sessionslog[$user->id] = $att->get_user_filtered_sessions_log($user->id); $this->sessionslog[$user->id] = $att->get_user_filtered_sessions_log($user->id);
@ -481,8 +500,11 @@ class attendance_report_data implements renderable {
$this->usersstats[$user->id] = $att->get_user_statuses_stat($user->id); $this->usersstats[$user->id] = $att->get_user_statuses_stat($user->id);
if ($this->gradable) { if ($this->gradable) {
$this->grades[$user->id] = $att->get_user_grade($user->id); $this->grades[$user->id] = $totalgrade;
$this->maxgrades[$user->id] = $att->get_user_max_grade($user->id); $this->maxgrades[$user->id] = $att->get_user_max_grade($user->id);;
}
} else {
unset($this->users[$key]);
} }
} }

81
renderer.php

@ -104,20 +104,20 @@ class mod_attendance_renderer extends plugin_renderer_base {
} }
$totalusers = count_enrolled_users(context_module::instance($fcontrols->cm->id), 'mod/attendance:canbelisted', $group); $totalusers = count_enrolled_users(context_module::instance($fcontrols->cm->id), 'mod/attendance:canbelisted', $group);
$usersperpage = $fcontrols->pageparams->perpage;
if (empty($fcontrols->pageparams->page) || !$fcontrols->pageparams->page || !$totalusers || !$usersperpage) { if (empty($fcontrols->pageparams->page) || !$fcontrols->pageparams->page || !$totalusers || empty($fcontrols->pageparams->perpage)) {
return $paging_controls; return $paging_controls;
} }
$numberofpages = ceil($totalusers / $usersperpage); $numberofpages = ceil($totalusers / $fcontrols->pageparams->perpage);
if ($fcontrols->pageparams->page > 1) { if ($fcontrols->pageparams->page > 1) {
$paging_controls .= html_writer::link($fcontrols->url(array('curdate' => $fcontrols->nextcur, 'page' => $fcontrols->pageparams->page - 1)), $paging_controls .= html_writer::link($fcontrols->url(array('curdate' => $fcontrols->curdate, 'page' => $fcontrols->pageparams->page - 1)),
$this->output->larrow()); $this->output->larrow());
} }
$paging_controls .= html_writer::tag('span', "Page {$fcontrols->pageparams->page} of $numberofpages", array('class' => 'attbtn')); $paging_controls .= html_writer::tag('span', "Page {$fcontrols->pageparams->page} of $numberofpages", array('class' => 'attbtn'));
if ($fcontrols->pageparams->page < $numberofpages) { if ($fcontrols->pageparams->page < $numberofpages) {
$paging_controls .= html_writer::link($fcontrols->url(array('curdate' => $fcontrols->nextcur, 'page' => $fcontrols->pageparams->page + 1)), $paging_controls .= html_writer::link($fcontrols->url(array('curdate' => $fcontrols->curdate, 'page' => $fcontrols->pageparams->page + 1)),
$this->output->rarrow()); $this->output->rarrow());
} }
@ -173,6 +173,9 @@ class mod_attendance_renderer extends plugin_renderer_base {
protected function render_view_controls(attendance_filter_controls $fcontrols) { protected function render_view_controls(attendance_filter_controls $fcontrols) {
$views[ATT_VIEW_ALL] = get_string('all', 'attendance'); $views[ATT_VIEW_ALL] = get_string('all', 'attendance');
$views[ATT_VIEW_ALLPAST] = get_string('allpast', 'attendance'); $views[ATT_VIEW_ALLPAST] = get_string('allpast', 'attendance');
if ($fcontrols->reportcontrol) {
$views[ATT_VIEW_NOTPRESENT] = get_string('lowgrade', 'attendance');
}
$views[ATT_VIEW_MONTHS] = get_string('months', 'attendance'); $views[ATT_VIEW_MONTHS] = get_string('months', 'attendance');
$views[ATT_VIEW_WEEKS] = get_string('weeks', 'attendance'); $views[ATT_VIEW_WEEKS] = get_string('weeks', 'attendance');
$views[ATT_VIEW_DAYS] = get_string('days', 'attendance'); $views[ATT_VIEW_DAYS] = get_string('days', 'attendance');
@ -320,6 +323,9 @@ class mod_attendance_renderer extends plugin_renderer_base {
$table .= html_writer::tag('center', html_writer::empty_tag('input', $params)); $table .= html_writer::tag('center', html_writer::empty_tag('input', $params));
$table = html_writer::tag('form', $table, array('method' => 'post', 'action' => $takedata->url_path())); $table = html_writer::tag('form', $table, array('method' => 'post', 'action' => $takedata->url_path()));
foreach($takedata->statuses as $status) {
$sessionstats[$status->id] = 0;
}
// Calculate the sum of statuses for each user // Calculate the sum of statuses for each user
$sessionstats[] = array(); $sessionstats[] = array();
foreach ($takedata->sessionlog as $userlog) { foreach ($takedata->sessionlog as $userlog) {
@ -398,7 +404,8 @@ class mod_attendance_renderer extends plugin_renderer_base {
} }
$controls .= html_writer::tag('span', "Page {$takedata->pageparams->page} of $numberofpages", array('class' => 'attbtn')); $controls .= html_writer::tag('span', "Page {$takedata->pageparams->page} of $numberofpages", array('class' => 'attbtn'));
if ($takedata->pageparams->page < $numberofpages) { if ($takedata->pageparams->page < $numberofpages) {
$controls .= html_writer::link($takedata->url(array('page' => $takedata->pageparams->page + 1)), $this->output->rarrow()); $controls .= html_writer::link($takedata->url(array('page' => $takedata->pageparams->page + 1,
'perpage' => $takedata->pageparams->perpage)), $this->output->rarrow());
} }
} }
@ -418,6 +425,15 @@ class mod_attendance_renderer extends plugin_renderer_base {
$select->class = 'singleselect inline'; $select->class = 'singleselect inline';
$controls .= $this->output->render($select); $controls .= $this->output->render($select);
if ($takedata->pageparams->viewmode == att_take_page_params::SORTED_LIST) {
$options = array(
0 => get_string('donotusepaging', 'attendance'),
get_config('attendance', 'resultsperpage') => get_config('attendance', 'resultsperpage'));
$select = new single_select($takedata->url(), 'perpage', $options, $takedata->pageparams->perpage, null);
$select->class = 'singleselect inline';
$controls .= $this->output->render($select);
}
if ($takedata->pageparams->viewmode == att_take_page_params::SORTED_GRID) { if ($takedata->pageparams->viewmode == att_take_page_params::SORTED_GRID) {
$options = array (1 => '1 '.get_string('column', 'attendance'), '2 '.get_string('columns', 'attendance'), $options = array (1 => '1 '.get_string('column', 'attendance'), '2 '.get_string('columns', 'attendance'),
'3 '.get_string('columns', 'attendance'), '4 '.get_string('columns', 'attendance'), '3 '.get_string('columns', 'attendance'), '4 '.get_string('columns', 'attendance'),
@ -731,9 +747,18 @@ class mod_attendance_renderer extends plugin_renderer_base {
$cell->colspan = 2; $cell->colspan = 2;
$row->cells[] = $cell; $row->cells[] = $cell;
} else { } else {
if (!empty($sess->studentscanmark)) { // Student can mark their own attendance.
// URL to the page that lets the student modify their attendance.
$url = new moodle_url('/mod/attendance/attendance.php',
array('sessid' => $sess->id, 'sesskey' => sesskey()));
$cell = new html_table_cell(html_writer::link($url, get_string('submitattendance', 'attendance')));
$cell->colspan = 2;
$row->cells[] = $cell;
} else { // Student cannot mark their own attendace.
$row->cells[] = '?'; $row->cells[] = '?';
$row->cells[] = ''; $row->cells[] = '';
} }
}
$table->data[] = $row; $table->data[] = $row;
} }
@ -748,6 +773,14 @@ class mod_attendance_renderer extends plugin_renderer_base {
} }
protected function render_attendance_report_data(attendance_report_data $reportdata) { protected function render_attendance_report_data(attendance_report_data $reportdata) {
global $PAGE;
// Initilise Javascript used to (un)check all checkboxes.
$this->page->requires->js_init_call('M.mod_attendance.init_manage');
// Check if the user should be able to bulk send messages to other users on the course.
$bulkmessagecapability = has_capability('moodle/course:bulkmessaging', $PAGE->context);
$table = new html_table(); $table = new html_table();
$table->attributes['class'] = 'generaltable attwidth'; $table->attributes['class'] = 'generaltable attwidth';
@ -760,6 +793,7 @@ class mod_attendance_renderer extends plugin_renderer_base {
$table->head[] = $this->construct_fullname_head($reportdata); $table->head[] = $this->construct_fullname_head($reportdata);
$table->align[] = 'left'; $table->align[] = 'left';
$table->size[] = ''; $table->size[] = '';
$sessionstats = array();
foreach ($reportdata->sessions as $sess) { foreach ($reportdata->sessions as $sess) {
$sesstext = userdate($sess->sessdate, get_string('strftimedm', 'attendance')); $sesstext = userdate($sess->sessdate, get_string('strftimedm', 'attendance'));
@ -780,6 +814,7 @@ class mod_attendance_renderer extends plugin_renderer_base {
$table->head[] = $status->acronym; $table->head[] = $status->acronym;
$table->align[] = 'center'; $table->align[] = 'center';
$table->size[] = '1px'; $table->size[] = '1px';
$sessionstats[$status->id] = 0;
} }
if ($reportdata->gradable) { if ($reportdata->gradable) {
@ -794,6 +829,13 @@ class mod_attendance_renderer extends plugin_renderer_base {
$table->size[] = '200px'; $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'));
$table->align[] = 'center';
$table->size[] = '1px';
}
foreach ($reportdata->users as $user) { foreach ($reportdata->users as $user) {
$row = new html_table_row(); $row = new html_table_row();
@ -816,12 +858,17 @@ class mod_attendance_renderer extends plugin_renderer_base {
} }
if ($reportdata->sessionslog) { if ($reportdata->sessionslog) {
if (isset($reportdata->sessionslog[$user->id][$sess->id]->remarks)) { if (isset($sess) && isset($reportdata->sessionslog[$user->id][$sess->id]->remarks)) {
$row->cells[] = $reportdata->sessionslog[$user->id][$sess->id]->remarks; $row->cells[] = $reportdata->sessionslog[$user->id][$sess->id]->remarks;
} else { } else {
$row->cells[] = ''; $row->cells[] = '';
} }
} }
if ($bulkmessagecapability) { // Create the checkbox for bulk messaging.
$row->cells[] = html_writer::checkbox('user'.$user->id, 'on', false);
}
$table->data[] = $row; $table->data[] = $row;
} }
@ -830,12 +877,13 @@ class mod_attendance_renderer extends plugin_renderer_base {
$statrow->cells[] = ''; $statrow->cells[] = '';
$statrow->cells[] = get_string('summary'); $statrow->cells[] = get_string('summary');
foreach ($reportdata->sessions as $sess) { foreach ($reportdata->sessions as $sess) {
$sessionstats = array();
foreach ($reportdata->users as $user) { foreach ($reportdata->users as $user) {
foreach($reportdata->statuses as $status) { 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]++; if ($reportdata->sessionslog[$user->id][$sess->id]->statusid == $status->id) $sessionstats[$status->id]++;
} }
} }
}
$statsoutput = '<br/>'; $statsoutput = '<br/>';
foreach($reportdata->statuses as $status) { foreach($reportdata->statuses as $status) {
@ -846,7 +894,22 @@ class mod_attendance_renderer extends plugin_renderer_base {
} }
$table->data[] = $statrow; $table->data[] = $statrow;
return html_writer::table($table); 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).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).html_writer::tag('div', get_string('users').': '.count($reportdata->users));
}
} }
protected function render_attendance_preferences_data(attendance_preferences_data $prefdata) { protected function render_attendance_preferences_data(attendance_preferences_data $prefdata) {

2
report.php

@ -57,7 +57,7 @@ $PAGE->navbar->add(get_string('report', 'attendance'));
$output = $PAGE->get_renderer('mod_attendance'); $output = $PAGE->get_renderer('mod_attendance');
$tabs = new attendance_tabs($att, attendance_tabs::TAB_REPORT); $tabs = new attendance_tabs($att, attendance_tabs::TAB_REPORT);
$filtercontrols = new attendance_filter_controls($att); $filtercontrols = new attendance_filter_controls($att, true);
$reportdata = new attendance_report_data($att); $reportdata = new attendance_report_data($att);
add_to_log($course->id, 'attendance', 'report viewed', '/mod/attendance/report.php?id='.$id, '', $cm->id); add_to_log($course->id, 'attendance', 'report viewed', '/mod/attendance/report.php?id='.$id, '', $cm->id);

6
sessions.php

@ -220,6 +220,9 @@ function construct_sessions_data_for_add($formdata) {
$sess->description = $formdata->sdescription['text']; $sess->description = $formdata->sdescription['text'];
$sess->descriptionformat = $formdata->sdescription['format']; $sess->descriptionformat = $formdata->sdescription['format'];
$sess->timemodified = $now; $sess->timemodified = $now;
if (isset($formdata->studentscanmark)) { // Students will be able to mark their own attendance.
$sess->studentscanmark = 1;
}
fill_groupid($formdata, $sessions, $sess); fill_groupid($formdata, $sessions, $sess);
} }
@ -237,6 +240,9 @@ function construct_sessions_data_for_add($formdata) {
$sess->description = $formdata->sdescription['text']; $sess->description = $formdata->sdescription['text'];
$sess->descriptionformat = $formdata->sdescription['format']; $sess->descriptionformat = $formdata->sdescription['format'];
$sess->timemodified = $now; $sess->timemodified = $now;
if (isset($formdata->studentscanmark)) { // Students will be able to mark their own attendance.
$sess->studentscanmark = 1;
}
fill_groupid($formdata, $sessions, $sess); fill_groupid($formdata, $sessions, $sess);
} }

63
student_attenance_form.php

@ -0,0 +1,63 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
require_once($CFG->libdir.'/formslib.php');
class mod_attendance_student_attendance_form extends moodleform {
public function definition() {
global $CFG, $USER;
$mform =& $this->_form;
$course = $this->_customdata['course'];
$cm = $this->_customdata['cm'];
$modcontext = $this->_customdata['modcontext'];
$attforsession = $this->_customdata['session'];
$attblock = $this->_customdata['attendance'];
$statuses = $attblock->get_statuses();
$mform->addElement('hidden', 'sessid', null);
$mform->setType('sessid', PARAM_INT);
$mform->setConstant('sessid', $attforsession->id);
$mform->addElement('hidden', 'sesskey', null);
$mform->setType('sesskey', PARAM_INT);
$mform->setConstant('sesskey', sesskey());
// Set a title as the date and time of the session.
$sesstiontitle = userdate($attforsession->sessdate, get_string('strftimedate')).' '
.userdate($attforsession->sessdate, get_string('strftimehm', 'mod_attendance'));
$mform->addElement('header', 'session', $sesstiontitle);
// If a session description is set display it.
if (!empty($attforsession->description)) {
$mform->addElement('html', $attforsession->description);
}
// Create radio buttons for setting the attendance status.
$radioarray = array();
foreach ($statuses as $status) {
$radioarray[] =& $mform->createElement('radio', 'status', '', $status->description, $status->id, array());
}
// Add the radio buttons as a control with the user's name in front.
$mform->addGroup($radioarray, 'statusarray', $USER->firstname.' '.$USER->lastname.':', array(''), false);
$mform->addRule('statusarray', get_string('attendancenotset', 'attendance'), 'required', '', 'client', false, false);
$this->add_action_buttons();
}
}

2
take.php

@ -35,7 +35,7 @@ $pageparams->copyfrom = optional_param('copyfrom', null, PARAM_INT);
$pageparams->viewmode = optional_param('viewmode', null, PARAM_INT); $pageparams->viewmode = optional_param('viewmode', null, PARAM_INT);
$pageparams->gridcols = optional_param('gridcols', null, PARAM_INT); $pageparams->gridcols = optional_param('gridcols', null, PARAM_INT);
$pageparams->page = optional_param('page', 1, PARAM_INT); $pageparams->page = optional_param('page', 1, PARAM_INT);
$pageparams->perpage = get_config('attendance', 'resultsperpage'); $pageparams->perpage = optional_param('perpage', get_config('attendance', 'resultsperpage'), PARAM_INT);
$cm = get_coursemodule_from_id('attendance', $id, 0, false, MUST_EXIST); $cm = get_coursemodule_from_id('attendance', $id, 0, false, MUST_EXIST);
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);

105
tests/behat/attendance_mod.feature

@ -0,0 +1,105 @@
@mod @uon @mod_attendance
Feature: Teachers and Students can record session attendance
In order to record session attendance
As a student
I need to be able to mark my own attendance to a session
And as a teacher
I need to be able to mark any students attendance to a session
In order to report on session attendance
As a teacher
I need to be able to export session attendance and run reports
In order to contact students with poor attendance
As a teacher
I need the ability to message a group of students with low attendance
Background:
Given the following "courses" exist:
| fullname | shortname | summary | category |
| Course 1 | C101 | Prove the attendance activity works | 0 |
And the following "users" exist:
| username | firstname | lastname | email | idnumber | department | institution |
| student1 | Sam | Student | student1@asd.com | 1234 | computer science | University of Nottingham |
| teacher1 | Teacher | One | teacher1@asd.com | 5678 | computer science | University of Nottingham |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C101 | student |
| teacher1 | C101 | editingteacher |
And I log in as "teacher1"
And I follow "Course 1"
And I turn editing mode on
And I add a "Attendance" to section "1"
And I press "Save and display"
And I log out
Scenario: Students can mark their own attendance
When I log in as "teacher1"
And I follow "Course 1"
And I follow "Attendance"
And I follow "Add"
And I check "Allow students to record own attendance"
And I set the following fields to these values:
| id_sessiondate_hour | 23 |
And I click on "id_submitbutton" "button"
And I follow "Continue"
And I log out
When I log in as "student1"
And I follow "Course 1"
And I follow "Attendance"
And I follow "Submit attendance"
And I check "Present"
And I press "Save changes"
Then I should see "Self-recorded"
And I log out
When I log in as "teacher1"
And I follow "Course 1"
And I expand "Reports" node
And I follow "Logs"
And I click on "Get these logs" "button"
Then "attendance taken by student" "link" should exist
Scenario: Teachers can view low grade report and send a message
When I log in as "teacher1"
And I follow "Course 1"
And I follow "Attendance"
And I follow "Add"
And I set the following fields to these values:
| id_sessiondate_hour | 01 |
And I click on "id_submitbutton" "button"
And I follow "Continue"
And I follow "Report"
And I follow "Low grade"
And I check "user3"
And I click on "Send a message" "button"
Then I should see "Message body"
And I should see "student1@asd.com"
And I expand "Reports" node
And I follow "Logs"
And I click on "Get these logs" "button"
Then "attendance report viewed" "link" should exist
# Dependency - selenium running with firefox profile with auto saving of txt files to $CFG->behat_download.
@javascript @_file_download
Scenario: Export report includes id number, department and institution
When I log in as "teacher1"
And I follow "Course 1"
And I follow "Attendance"
And I follow "Add"
And I set the following fields to these values:
| id_sessiondate_hour | 01 |
And I click on "id_submitbutton" "button"
And I follow "Continue"
And I follow "Export"
Then the "id_ident_idnumber" checkbox should not be checked
And the "id_ident_institution" checkbox should not be checked
And the "id_ident_department" checkbox should not be checked
And I check "id_ident_idnumber"
And I check "id_ident_institution"
And I check "id_ident_department"
And I set the following fields to these values:
| format | Download in text format |
And I click on "OK" "button"
Then attendance export file is ok
And I should see "ID number" as "1234" in the file
And I should see "Department" as "computer science" in the file
And I should see "Institution" as "University of Nottingham" in the file

116
tests/behat/behat_mod_attendance.php

@ -0,0 +1,116 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
require_once(__DIR__ . '/../../../../lib/behat/behat_base.php');
use Behat\Mink\Exception\ExpectationException as ExpectationException,
Behat\Behat\Exception\PendingException as PendingException;
/**
* Attendance steps definitions.
*
* @package mod
* @subpackage attendance
* @category test
* @copyright 2014 University of Nottingham
* @author Joseph Baxter (joseph.baxter@nottingham.ac.uk)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class behat_mod_attendance extends behat_base {
protected $file_contents;
/**
* @Then /^attendance export file is ok$/
*/
public function attendance_export_file_is_ok() {
global $CFG;
$check = true;
// Location selenium will download to.
$dir = $CFG->behat_download;
$files = scandir($dir, 1);
$filename = $files[0];
$file = fopen($dir . $filename, "r");
$count = 0;
$header = null;
// The file is tab seperated but not exactly a tsv.
while (($row = fgetcsv($file, 0, "\t")) !== FALSE) {
// Ignore unwanted information at the start of the file.
if ($count < 3) {
$count++;
continue;
}
if (!$header) {
$header = $row;
} else {
$this->file_contents = array_combine($header, $row);
}
$count++;
}
fclose($file);
unlink($dir . $filename);
// Check if data rows exist.
if ($count < 2) {
$check = false;
}
if ($check) {
return true;
} else {
throw new ExpectationException('Attendance export file not ok', $this->getSession());
}
}
/**
* @Given /^I should see "([^"]*)" as "([^"]*)" in the file$/
*/
public function i_should_see_as_in_the_file($field, $value) {
foreach ($this->file_contents as $array_field => $array_value) {
if ($field == $array_field) {
if ($value == $array_value) {
return true;
} else {
throw new PendingException();
}
}
}
}
}

4
version.php

@ -22,9 +22,9 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/ */
$module->version = 2014022800; $module->version = 2014022803;
$module->requires = 2013040500; $module->requires = 2013040500;
$module->release = '2.6.0'; $module->release = '2.6.2';
$module->maturity = MATURITY_STABLE; $module->maturity = MATURITY_STABLE;
$module->cron = 0; $module->cron = 0;
$module->component = 'mod_attendance'; $module->component = 'mod_attendance';

Loading…
Cancel
Save