Browse Source

Allow temporary users to be created and have their attendance taken

MOODLE_28_STABLE
Davo Smith 10 years ago
parent
commit
16c883c711
  1. 15
      db/access.php
  2. 17
      db/install.xml
  3. 36
      db/upgrade.php
  4. 55
      lang/en/attendance.php
  5. 113
      locallib.php
  6. BIN
      pix/ghost.png
  7. 5
      renderables.php
  8. 33
      renderer.php
  9. 68
      temp_form.php
  10. 115
      tempedit.php
  11. 71
      tempedit_form.php
  12. 104
      tempmerge.php
  13. 40
      tempmerge_form.php
  14. 127
      tempusers.php
  15. 112
      tests/behat/extra_features.feature
  16. 2
      version.php

15
db/access.php

@ -117,5 +117,18 @@ $capabilities = array(
'archetypes' => array( 'archetypes' => array(
'student' => CAP_ALLOW 'student' => CAP_ALLOW
) )
) ),
// Allow teachers to manage temporary users.
'mod/attendance:managetemporaryusers' => array(
'riskbitmask' => RISK_DATALOSS,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
); );

17
db/install.xml

@ -80,5 +80,22 @@
<INDEX NAME="deleted" UNIQUE="false" FIELDS="deleted"/> <INDEX NAME="deleted" UNIQUE="false" FIELDS="deleted"/>
</INDEXES> </INDEXES>
</TABLE> </TABLE>
<TABLE NAME="attendance_tempusers" COMMENT="Stores temporary users details">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="studentid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="student id"/>
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="course id"/>
<FIELD NAME="fullname" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false" COMMENT="temp user fullname"/>
<FIELD NAME="email" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false" COMMENT="temporary user email"/>
<FIELD NAME="created" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="unix timestamp for temp user creation"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="courseid" UNIQUE="false" FIELDS="courseid"/>
<INDEX NAME="studentid" UNIQUE="true" FIELDS="studentid"/>
</INDEXES>
</TABLE>
</TABLES> </TABLES>
</XMLDB> </XMLDB>

36
db/upgrade.php

@ -85,5 +85,41 @@ function xmldb_attendance_upgrade($oldversion=0) {
upgrade_plugin_savepoint($result, 2014112001, 'mod', 'attendance'); upgrade_plugin_savepoint($result, 2014112001, 'mod', 'attendance');
} }
if ($oldversion < 2015040501) {
// Define table attendance_tempusers to be created.
$table = new xmldb_table('attendance_tempusers');
// Adding fields to table attendance_tempusers.
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
$table->add_field('studentid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
$table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
$table->add_field('fullname', XMLDB_TYPE_CHAR, '100', null, null, null, null);
$table->add_field('email', XMLDB_TYPE_CHAR, '100', null, null, null, null);
$table->add_field('created', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
// Adding keys to table attendance_tempusers.
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
// Conditionally launch create table for attendance_tempusers.
if (!$dbman->table_exists($table)) {
$dbman->create_table($table);
}
// Conditionally launch add index courseid.
$index = new xmldb_index('courseid', XMLDB_INDEX_NOTUNIQUE, array('courseid'));
if (!$dbman->index_exists($table, $index)) {
$dbman->add_index($table, $index);
}
// Conditionally launch add index studentid.
$index = new xmldb_index('studentid', XMLDB_INDEX_UNIQUE, array('studentid'));
if (!$dbman->index_exists($table, $index)) {
$dbman->add_index($table, $index);
}
// Attendance savepoint reached.
upgrade_mod_savepoint(true, 2015040501, 'attendance');
}
return $result; return $result;
} }

55
lang/en/attendance.php

@ -24,6 +24,7 @@
$string['attendance:addinstance'] = 'Add a new attendance activity'; $string['attendance:addinstance'] = 'Add a new attendance activity';
$string['Aacronym'] = 'A'; $string['Aacronym'] = 'A';
$string['adduser'] = 'Add user';
$string['Afull'] = 'Absent'; $string['Afull'] = 'Absent';
$string['Eacronym'] = 'E'; $string['Eacronym'] = 'E';
$string['Efull'] = 'Excused'; $string['Efull'] = 'Excused';
@ -51,6 +52,7 @@ $string['attendance:changepreferences'] = 'Changing Preferences';
$string['attendance:changeattendances'] = 'Changing Attendances'; $string['attendance:changeattendances'] = 'Changing Attendances';
$string['attendance:export'] = 'Export Reports'; $string['attendance:export'] = 'Export Reports';
$string['attendance:manageattendances'] = 'Manage Attendances'; $string['attendance:manageattendances'] = 'Manage Attendances';
$string['attendance:managetemporaryusers'] = 'Manage temporary users';
$string['attendance:takeattendances'] = 'Taking Attendances'; $string['attendance:takeattendances'] = 'Taking Attendances';
$string['attendance:view'] = 'Viewing Attendances'; $string['attendance:view'] = 'Viewing Attendances';
$string['attendance:viewreports'] = 'Viewing Reports'; $string['attendance:viewreports'] = 'Viewing Reports';
@ -69,6 +71,7 @@ $string['column'] = 'column';
$string['columns'] = 'columns'; $string['columns'] = 'columns';
$string['commonsession'] = 'Common'; $string['commonsession'] = 'Common';
$string['commonsessions'] = 'Common'; $string['commonsessions'] = 'Common';
$string['confirmdeleteuser'] = 'Are you sure you want to delete user \'{$a->fullname}\' ({$a->email})?<br/>All of their attendance records will be permanently deleted.';
$string['countofselected'] = 'Count of selected'; $string['countofselected'] = 'Count of selected';
$string['copyfrom'] = 'Copy attendance data from'; $string['copyfrom'] = 'Copy attendance data from';
$string['createmultiplesessions'] = 'Create multiple sessions'; $string['createmultiplesessions'] = 'Create multiple sessions';
@ -88,6 +91,7 @@ $string['deletelogs'] = 'Delete attendance data';
$string['deleteselected'] = 'Delete selected'; $string['deleteselected'] = 'Delete selected';
$string['deletesession'] = 'Delete session'; $string['deletesession'] = 'Delete session';
$string['deletesessions'] = 'Delete all sessions'; $string['deletesessions'] = 'Delete all sessions';
$string['deleteuser'] = 'Delete user';
$string['deletingsession'] = 'Deleting session for the course'; $string['deletingsession'] = 'Deleting session for the course';
$string['deletingstatus'] = 'Deleting status for the course'; $string['deletingstatus'] = 'Deleting status for the course';
$string['description'] = 'Description'; $string['description'] = 'Description';
@ -99,6 +103,7 @@ $string['downloadtext'] = 'Download in text format';
$string['donotusepaging'] = 'Do not use paging'; $string['donotusepaging'] = 'Do not use paging';
$string['duration'] = 'Duration'; $string['duration'] = 'Duration';
$string['editsession'] = 'Edit Session'; $string['editsession'] = 'Edit Session';
$string['edituser'] = 'Edit user';
$string['endtime'] = 'Session end time'; $string['endtime'] = 'Session end time';
$string['endofperiod'] = 'End of period'; $string['endofperiod'] = 'End of period';
$string['enrolmentend'] = 'User enrolment ends {$a}'; $string['enrolmentend'] = 'User enrolment ends {$a}';
@ -125,6 +130,7 @@ $string['indetail'] = 'In detail...';
$string['invalidsessionenddate'] = 'The session end date can not be earlier than the session start date'; $string['invalidsessionenddate'] = 'The session end date can not be earlier than the session start date';
$string['invalidaction'] = 'You must select an action'; $string['invalidaction'] = 'You must select an action';
$string['jumpto'] = 'Jump to'; $string['jumpto'] = 'Jump to';
$string['mergeuser'] = 'Merge user';
$string['modulename'] = 'Attendance'; $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. $string['modulename_help'] = 'The attendance activity module enables a teacher to take attendance during class and students to view their own attendance record.
@ -151,6 +157,7 @@ $string['nosessionsselected'] = 'No sessions selected';
$string['notfound'] = 'Attendance activity not found in this course!'; $string['notfound'] = 'Attendance activity not found in this course!';
$string['noupgradefromthisversion'] = 'The Attendance module cannot upgrade from the version of attforblock you have installed. - please delete attforblock or upgrade it to the latest version before isntalling the new attendance module'; $string['noupgradefromthisversion'] = 'The Attendance module cannot upgrade from the version of attforblock you have installed. - please delete attforblock or upgrade it to the latest version before isntalling the new attendance module';
$string['olddate'] = 'Old date'; $string['olddate'] = 'Old date';
$string['participant'] = 'Participant';
$string['period'] = 'Frequency'; $string['period'] = 'Frequency';
$string['pluginname'] = 'Attendance'; $string['pluginname'] = 'Attendance';
$string['pluginadministration'] = 'Attendance administration'; $string['pluginadministration'] = 'Attendance administration';
@ -158,6 +165,41 @@ $string['remark'] = 'Remark for: {$a}';
$string['remarks'] = 'Remarks'; $string['remarks'] = 'Remarks';
$string['report'] = 'Report'; $string['report'] = 'Report';
$string['required'] = 'Required*'; $string['required'] = 'Required*';
$string['requiredentries'] = ' Temporary records overwrite participant attendance records';
$string['requiredentry'] = ' Temporary user merge help guide';
$string['requiredentry_help'] = '<p align="center"><b>Attendance</b></p>
<p align="left"><strong>Merge Accounts</strong></p>
<p align="left">
<table border="2" cellpadding="4">
<tr>
<th>Moodle User</th>
<th>Temporary User</th>
<th>Action</th>
</tr>
<tr>
<td>Attendance data</td>
<td>Attendance data</td>
<td>Temporary user will override Moodle user</td>
</tr>
<tr>
<td>No attendance data</td>
<td>Attendance data</td>
<td>Temporary user attendance will be transfered to Moodle user</td>
</tr>
<tr>
<td>Attendance data</td>
<td>No attendance data</td>
<td>Temporary user will be deleted</td>
</tr>
<tr>
<td>No attendance data</td>
<td>No attendance data</td>
<td>Temporary user will be deleted</td>
</tr>
</table>
</p>
<p align="left"><strong>Temporay user will be deleted in all cases after merge action</strong></p>';
$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['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['resetstatuses'] = 'Reset statuses to default';
$string['restoredefaults'] = 'Restore defaults'; $string['restoredefaults'] = 'Restore defaults';
@ -206,9 +248,22 @@ $string['strftimehm'] = '%H:%M'; // Line added to allow display of time.
$string['strftimeshortdate'] = '%d.%m.%Y'; $string['strftimeshortdate'] = '%d.%m.%Y';
$string['studentid'] = 'Student ID'; $string['studentid'] = 'Student ID';
$string['takeattendance'] = 'Take attendance'; $string['takeattendance'] = 'Take attendance';
$string['tempaddform'] = 'Add temporary user';
$string['tempexists'] = 'There is already a temporary user with this email address';
$string['tempusers'] = 'Temporary users';
$string['thiscourse'] = 'This course'; $string['thiscourse'] = 'This course';
$string['tablerenamefailed'] = 'Rename of old attforblock table to attendance failed'; $string['tablerenamefailed'] = 'Rename of old attforblock table to attendance failed';
$string['tactions'] = 'Action';
$string['tcreated'] = 'Created';
$string['temptable'] = 'List of temporary users';
$string['tempuser'] = 'Temporary user';
$string['tempusersedit'] = 'Edit temporary user';
$string['tempuserslist'] = 'Temporary users';
$string['tempusermerge'] = 'Merge temporary user';
$string['tuseremail'] = 'Email';
$string['tusername'] = 'Full name';
$string['update'] = 'Update'; $string['update'] = 'Update';
$string['userexists'] = 'There is already a real user with this email address';
$string['variable'] = 'variable'; $string['variable'] = 'variable';
$string['variablesupdated'] = 'Variables successfully updated'; $string['variablesupdated'] = 'Variables successfully updated';
$string['versionforprinting'] = 'version for printing'; $string['versionforprinting'] = 'version for printing';

113
locallib.php

@ -44,6 +44,7 @@ class attendance_permissions {
private $cantake; private $cantake;
private $canchange; private $canchange;
private $canmanage; private $canmanage;
private $canmanagetemp; // Can manage temporary users.
private $canchangepreferences; private $canchangepreferences;
private $canexport; private $canexport;
private $canbelisted; private $canbelisted;
@ -123,6 +124,18 @@ class attendance_permissions {
require_capability('mod/attendance:manageattendances', $this->context); require_capability('mod/attendance:manageattendances', $this->context);
} }
// Check to see if the user can manage temporary users.
public function can_managetemp() {
if (is_null($this->canmanagetemp)) {
$this->canmanagetemp = has_capability('mod/attendance:managetemporaryusers', $this->context);
}
return $this->canmanagetemp;
}
public function require_managetemp_capability() {
require_capability('mod/attendance:managetemporaryusers', $this->context);
}
public function can_change_preferences() { public function can_change_preferences() {
if (is_null($this->canchangepreferences)) { if (is_null($this->canchangepreferences)) {
$this->canchangepreferences = has_capability('mod/attendance:changepreferences', $this->context); $this->canchangepreferences = has_capability('mod/attendance:changepreferences', $this->context);
@ -588,7 +601,7 @@ class attendance {
$this->cm = $cm; $this->cm = $cm;
$this->course = $course; $this->course = $course;
if (is_null($context)) { if (is_null($context)) {
$this->context = context_module::instance_by_id($this->cm->id); $this->context = context_module::instance($this->cm->id);
} else { } else {
$this->context = $context; $this->context = $context;
} }
@ -738,6 +751,42 @@ class attendance {
return new moodle_url('/mod/attendance/manage.php', $params); return new moodle_url('/mod/attendance/manage.php', $params);
} }
/**
* @param array $params optional
* @return moodle_url of tempusers.php for attendance instance
*/
public function url_managetemp($params=array()) {
$params = array_merge(array('id' => $this->cm->id), $params);
return new moodle_url('/mod/attendance/tempusers.php', $params);
}
/**
* @param array $params optional
* @return moodle_url of tempdelete.php for attendance instance
*/
public function url_tempdelete($params=array()) {
$params = array_merge(array('id' => $this->cm->id, 'action' => 'delete'), $params);
return new moodle_url('/mod/attendance/tempedit.php', $params);
}
/**
* @param array $params optional
* @return moodle_url of tempedit.php for attendance instance
*/
public function url_tempedit($params=array()) {
$params = array_merge(array('id' => $this->cm->id), $params);
return new moodle_url('/mod/attendance/tempedit.php', $params);
}
/**
* @param array $params optional
* @return moodle_url of tempedit.php for attendance instance
*/
public function url_tempmerge($params=array()) {
$params = array_merge(array('id' => $this->cm->id), $params);
return new moodle_url('/mod/attendance/tempmerge.php', $params);
}
/** /**
* @return moodle_url of sessions.php for attendance instance * @return moodle_url of sessions.php for attendance instance
*/ */
@ -1058,17 +1107,53 @@ class attendance {
$users[$user->id]->enrolmentstatus = $enrolments[$user->id]->status; $users[$user->id]->enrolmentstatus = $enrolments[$user->id]->status;
$users[$user->id]->enrolmentstart = $enrolments[$user->id]->mintime; $users[$user->id]->enrolmentstart = $enrolments[$user->id]->mintime;
$users[$user->id]->enrolmentend = $enrolments[$user->id]->maxtime; $users[$user->id]->enrolmentend = $enrolments[$user->id]->maxtime;
$users[$user->id]->type = 'standard'; // Mark as a standard (not a temporary) user.
} }
} }
// Add the 'temporary' users to this list.
$tempusers = $DB->get_records('attendance_tempusers', array('courseid' => $this->course->id));
foreach ($tempusers as $tempuser) {
$users[] = self::tempuser_to_user($tempuser);
}
return $users; return $users;
} }
// Convert a tempuser record into a user object.
protected static function tempuser_to_user($tempuser) {
$ret = (object)array(
'id' => $tempuser->studentid,
'firstname' => $tempuser->fullname,
'email' => $tempuser->email,
'username' => '',
'enrolmentstatus' => 0,
'enrolmentstart' => 0,
'enrolmentend' => 0,
'picture' => 0,
'type' => 'temporary',
);
foreach (get_all_user_name_fields() as $namefield) {
if (!isset($ret->$namefield)) {
$ret->$namefield = '';
}
}
return $ret;
}
public function get_user($userid) { public function get_user($userid) {
global $DB; global $DB;
$user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST); $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST);
// Look for 'temporary' users and return their details from the attendance_tempusers table.
if ($user->idnumber == 'tempghost') {
$tempuser = $DB->get_record('attendance_tempusers', array('studentid' => $userid), '*', MUST_EXIST);
return self::tempuser_to_user($tempuser);
}
$user->type = 'standard';
// 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 = 'MAX(ue.timeend)';
@ -1516,8 +1601,34 @@ class attendance {
$event->trigger(); $event->trigger();
} }
/**
* Check if the email address is already in use by either another temporary user,
* or a real user.
*
* @param string $email the address to check for
* @param int $tempuserid optional the ID of the temporary user (to avoid matching against themself)
* @return null|string the error message to display, null if there is no error
*/
public static function check_existing_email($email, $tempuserid = 0) {
global $DB;
if (empty($email)) {
return null; // Fine to create temporary users without an email address.
}
if ($tempuser = $DB->get_record('attendance_tempusers', array('email' => $email), 'id')) {
if ($tempuser->id != $tempuserid) {
return get_string('tempexists', 'attendance');
}
}
if ($DB->record_exists('user', array('email' => $email))) {
return get_string('userexists', 'attendance');
}
return null;
}
} }
function att_get_statuses($attid, $onlyvisible=true) { function att_get_statuses($attid, $onlyvisible=true) {
global $DB; global $DB;

BIN
pix/ghost.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

5
renderables.php

@ -42,6 +42,7 @@ class attendance_tabs implements renderable {
const TAB_REPORT = 3; const TAB_REPORT = 3;
const TAB_EXPORT = 4; const TAB_EXPORT = 4;
const TAB_PREFERENCES = 5; const TAB_PREFERENCES = 5;
const TAB_TEMPORARYUSERS = 6; // Tab for managing temporary users.
public $currenttab; public $currenttab;
@ -92,6 +93,10 @@ class attendance_tabs implements renderable {
$toprow[] = new tabobject(self::TAB_PREFERENCES, $this->att->url_preferences()->out(), $toprow[] = new tabobject(self::TAB_PREFERENCES, $this->att->url_preferences()->out(),
get_string('settings', 'attendance')); get_string('settings', 'attendance'));
} }
if ($this->att->perm->can_managetemp()) {
$toprow[] = new tabobject(self::TAB_TEMPORARYUSERS, $this->att->url_managetemp()->out(),
get_string('tempusers', 'attendance'));
}
return array($toprow); return array($toprow);
} }

33
renderer.php

@ -495,7 +495,7 @@ class mod_attendance_renderer extends plugin_renderer_base {
$row = new html_table_row(); $row = new html_table_row();
$row->cells[] = $i; $row->cells[] = $i;
$fullname = html_writer::link($takedata->url_view(array('studentid' => $user->id)), fullname($user)); $fullname = html_writer::link($takedata->url_view(array('studentid' => $user->id)), fullname($user));
$fullname = $this->output->user_picture($user).$fullname; $fullname = $this->user_picture($user).$fullname; // Show different picture if it is a temporary user.
$ucdata = $this->construct_take_user_controls($takedata, $user); $ucdata = $this->construct_take_user_controls($takedata, $user);
if (array_key_exists('warning', $ucdata)) { if (array_key_exists('warning', $ucdata)) {
@ -540,7 +540,7 @@ class mod_attendance_renderer extends plugin_renderer_base {
$i = 0; $i = 0;
$row = new html_table_row(); $row = new html_table_row();
foreach ($takedata->users as $user) { foreach ($takedata->users as $user) {
$celltext = $this->output->user_picture($user, array('size' => 100)); $celltext = $this->user_picture($user, array('size' => 100)); // Show different picture if it is a temporary user.
$celltext .= html_writer::empty_tag('br'); $celltext .= html_writer::empty_tag('br');
$fullname = html_writer::link($takedata->url_view(array('studentid' => $user->id)), fullname($user)); $fullname = html_writer::link($takedata->url_view(array('studentid' => $user->id)), fullname($user));
$celltext .= html_writer::tag('span', $fullname, array('class' => 'fullname')); $celltext .= html_writer::tag('span', $fullname, array('class' => 'fullname'));
@ -656,7 +656,7 @@ class mod_attendance_renderer extends plugin_renderer_base {
$table->attributes['class'] = 'userinfobox'; $table->attributes['class'] = 'userinfobox';
$table->colclasses = array('left side', ''); $table->colclasses = array('left side', '');
$table->data[0][] = $this->output->user_picture($userdata->user, array('size' => 100)); $table->data[0][] = $this->user_picture($userdata->user, array('size' => 100)); // Show different picture if it is a temporary user.
$table->data[0][] = $this->construct_user_data($userdata); $table->data[0][] = $this->construct_user_data($userdata);
$o .= html_writer::table($table); $o .= html_writer::table($table);
@ -671,9 +671,12 @@ class mod_attendance_renderer extends plugin_renderer_base {
$userdata->url()->out(true, array('mode' => att_view_page_params::MODE_THIS_COURSE)), $userdata->url()->out(true, array('mode' => att_view_page_params::MODE_THIS_COURSE)),
get_string('thiscourse', 'attendance')); get_string('thiscourse', 'attendance'));
$tabs[] = new tabobject(att_view_page_params::MODE_ALL_COURSES, // Skip the 'all courses' tab for 'temporary' users.
$userdata->url()->out(true, array('mode' => att_view_page_params::MODE_ALL_COURSES)), if ($userdata->user->type == 'standard') {
get_string('allcourses', 'attendance')); $tabs[] = new tabobject(att_view_page_params::MODE_ALL_COURSES,
$userdata->url()->out(true, array('mode' => att_view_page_params::MODE_ALL_COURSES)),
get_string('allcourses', 'attendance'));
}
return print_tabs(array($tabs), $userdata->pageparams->mode, null, null, true); return print_tabs(array($tabs), $userdata->pageparams->mode, null, null, true);
} }
@ -842,7 +845,7 @@ class mod_attendance_renderer extends plugin_renderer_base {
foreach ($reportdata->users as $user) { foreach ($reportdata->users as $user) {
$row = new html_table_row(); $row = new html_table_row();
$row->cells[] = $this->output->user_picture($user); $row->cells[] = $this->user_picture($user); // Show different picture if it is a temporary user.
$row->cells[] = html_writer::link($reportdata->url_view(array('studentid' => $user->id)), fullname($user)); $row->cells[] = html_writer::link($reportdata->url_view(array('studentid' => $user->id)), fullname($user));
$cellsgenerator = new user_sessions_cells_html_generator($reportdata, $user); $cellsgenerator = new user_sessions_cells_html_generator($reportdata, $user);
$row->cells = array_merge($row->cells, $cellsgenerator->get_cells()); $row->cells = array_merge($row->cells, $cellsgenerator->get_cells());
@ -1006,4 +1009,20 @@ class mod_attendance_renderer extends plugin_renderer_base {
return html_writer::empty_tag('input', $attributes); return html_writer::empty_tag('input', $attributes);
} }
// Show different picture if it is a temporary user.
protected function user_picture($user, array $opts = null) {
if ($user->type == 'temporary') {
$attrib = array(
'width' => '35',
'height' => '35',
'class' => 'userpicture defaultuserpic',
);
if (isset($opts['size'])) {
$attrib['width'] = $attrib['height'] = $opts['size'];
}
return $this->output->pix_icon('ghost', '', 'mod_attendance', $attrib);
}
return $this->output->user_picture($user, $opts);
}
} }

68
temp_form.php

@ -0,0 +1,68 @@
<?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/>.
/**
* Form for creating temporary users.
*
* @package mod_attendance
* @copyright 2013 Davo Smith, Synergy Learning
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir.'/formslib.php');
class temp_form extends moodleform {
function definition() {
$mform = $this->_form;
$mform->addElement('hidden', 'id', 0);
$mform->setType('id', PARAM_INT);
$mform->addElement('header', 'attheader', get_string('tempaddform', 'attendance'));
$mform->addElement('text', 'tname', get_string('tusername', 'attendance'));
$mform->addRule('tname', 'Required', 'required', null, 'client');
$mform->setType('tname', PARAM_TEXT);
$mform->addElement('text', 'temail', get_string('tuseremail', 'attendance'));
$mform->addRule('temail', 'Email', 'email', null, 'client');
$mform->addRule('temail', '', 'callback', null, 'server');
$mform->setType('temail', PARAM_EMAIL);
$mform->addElement('submit', 'submitbutton', get_string('adduser', 'attendance'));
$mform->closeHeaderBefore('submit');
}
function definition_after_data() {
$mform = $this->_form;
$mform->applyFilter('tname', 'trim');
}
function validation($data, $files) {
$errors = parent::validation($data, $files);
if ($err = attendance::check_existing_email($data['temail'])) {
$errors['temail'] = $err;
}
return $errors;
}
}

115
tempedit.php

@ -0,0 +1,115 @@
<?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/>.
/**
* Attendance tempedit
*
* @package mod_attendance
* @copyright 2013 Davo Smith, Synergy Learning
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(dirname(__FILE__).'/../../config.php');
global $CFG, $DB, $PAGE, $OUTPUT;
require_once($CFG->dirroot.'/mod/attendance/locallib.php');
require_once($CFG->dirroot.'/mod/attendance/tempedit_form.php');
$id = required_param('id', PARAM_INT);
$userid = required_param('userid', PARAM_INT);
$action = optional_param('action', null, PARAM_ALPHA);
$cm = get_coursemodule_from_id('attendance', $id, 0, false, MUST_EXIST);
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
$att = $DB->get_record('attendance', array('id' => $cm->instance), '*', MUST_EXIST);
$tempuser = $DB->get_record('attendance_tempusers', array('id' => $userid), '*', MUST_EXIST);
$att = new attendance($att, $cm, $course);
$params = array('userid' => $tempuser->id);
if ($action) {
$params['action'] = $action;
}
$PAGE->set_url($att->url_tempedit($params));
require_login($course, true, $cm);
$att->perm->require_managetemp_capability();
$PAGE->set_title($course->shortname.": ".$att->name.' - '.get_string('tempusersedit', 'attendance'));
$PAGE->set_heading($course->fullname);
$PAGE->set_cacheable(true);
$PAGE->navbar->add(get_string('tempusersedit', 'attendance'));
/** @var mod_attendance_renderer $output */
$output = $PAGE->get_renderer('mod_attendance');
if ($action == 'delete') {
if (optional_param('confirm', false, PARAM_BOOL)) {
require_sesskey();
// Remove the user from the grades table, the attendance log and the tempusers table.
$DB->delete_records('grade_grades', array('userid' => $tempuser->studentid));
$DB->delete_records('attendance_log', array('studentid' => $tempuser->studentid));
$DB->delete_records('attendance_tempusers', array('id' => $tempuser->id));
redirect($att->url_managetemp());
} else {
$info = (object)array(
'fullname' => $tempuser->fullname,
'email' => $tempuser->email,
);
$msg = get_string('confirmdeleteuser', 'attendance', $info);
$continue = new moodle_url($PAGE->url, array('confirm' => 1, 'sesskey' => sesskey()));
echo $output->header();
echo $output->confirm($msg, $continue, $att->url_managetemp());
echo $output->footer();
die();
}
}
$formdata = new stdClass();
$formdata->id = $cm->id;
$formdata->tname = $tempuser->fullname;
$formdata->userid = $tempuser->id;
$formdata->temail = $tempuser->email;
$mform = new tempedit_form();
$mform->set_data($formdata);
if ($mform->is_cancelled()) {
redirect($att->url_managetemp());
} else if ($tempuser = $mform->get_data()) {
global $DB;
$updateuser = new stdClass();
$updateuser->id = $tempuser->userid;
$updateuser->fullname = $tempuser->tname;
$updateuser->email = $tempuser->temail;
$DB->update_record('attendance_tempusers', $updateuser);
redirect($att->url_managetemp());
}
$tabs = new attendance_tabs($att, attendance_tabs::TAB_TEMPORARYUSERS);
echo $output->header();
echo $output->heading(get_string('tempusersedit', 'attendance').' : '.$course->fullname);
echo $output->render($tabs);
$mform->display();
echo $output->footer($course);

71
tempedit_form.php

@ -0,0 +1,71 @@
<?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/>.
/**
* Form for editing temporary users.
*
* @package mod_attendance
* @copyright 2013 Davo Smith, Synergy Learning
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir.'/formslib.php');
class tempedit_form extends moodleform {
function definition() {
$mform = $this->_form;
$mform->addElement('hidden', 'userid', 0);
$mform->setType('userid', PARAM_INT);
$mform->addElement('hidden', 'id', 0);
$mform->setType('id', PARAM_INT);
$mform->addElement('header', 'attheader', get_string('tempusersedit', 'attendance'));
$mform->addElement('text', 'tname', get_string('tusername', 'attendance'));
$mform->addRule('tname', 'Required', 'required', null, 'client');
$mform->setType('tname', PARAM_TEXT);
$mform->addElement('text', 'temail', get_string('tuseremail', 'attendance'));
$mform->addRule('temail', 'Email', 'email', null, 'client');
$mform->setType('temail', PARAM_EMAIL);
$buttonarray = array(
$mform->createElement('submit', 'submitbutton', get_string('edituser', 'attendance')),
$mform->createElement('cancel'),
);
$mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
$mform->closeHeaderBefore('submit');
}
function definition_after_data() {
$mform = $this->_form;
$mform->applyFilter('tname', 'trim');
}
function validation($data, $files) {
$errors = parent::validation($data, $files);
if ($err = attendance::check_existing_email($data['temail'], $data['userid'])) {
$errors['temail'] = $err;
}
return $errors;
}
}

104
tempmerge.php

@ -0,0 +1,104 @@
<?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/>.
/**
* Merge temporary user with real user.
*
* @package mod_attendance
* @copyright 2013 Davo Smith, Synergy Learning
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(dirname(__FILE__).'/../../config.php');
global $CFG, $DB, $PAGE, $OUTPUT;
require_once($CFG->dirroot.'/mod/attendance/locallib.php');
require_once($CFG->dirroot.'/mod/attendance/tempmerge_form.php');
$id = required_param('id', PARAM_INT);
$userid = required_param('userid', PARAM_INT);
$cm = get_coursemodule_from_id('attendance', $id, 0, false, MUST_EXIST);
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
$att = $DB->get_record('attendance', array('id' => $cm->instance), '*', MUST_EXIST);
$tempuser = $DB->get_record('attendance_tempusers', array('id' => $userid), '*', MUST_EXIST);
$att = new attendance($att, $cm, $course);
$params = array('userid' => $tempuser->id);
$PAGE->set_url($att->url_tempmerge($params));
require_login($course, true, $cm);
$PAGE->set_title($course->shortname.": ".$att->name.' - '.get_string('tempusermerge', 'attendance'));
$PAGE->set_heading($course->fullname);
$PAGE->set_cacheable(true);
$PAGE->set_button($OUTPUT->update_module_button($cm->id, 'attendance'));
$PAGE->navbar->add(get_string('tempusermerge', 'attendance'));
$formdata = (object)array(
'id' => $cm->id,
'userid' => $tempuser->id,
);
$custom = array(
'description' => format_string($tempuser->fullname).' ('.format_string($tempuser->email).')',
);
$mform = new tempmerge_form(null, $custom);
$mform->set_data($formdata);
if ($mform->is_cancelled()) {
redirect($att->url_managetemp());
} else if ($data = $mform->get_data()) {
$sql = "SELECT s.id, lr.id AS reallogid, lt.id AS templogid
FROM {attendance_sessions} s
LEFT JOIN {attendance_log} lr ON lr.sessionid = s.id AND lr.studentid = :realuserid
LEFT JOIN {attendance_log} lt ON lt.sessionid = s.id AND lt.studentid = :tempuserid
WHERE s.attendanceid = :attendanceid AND lt.id IS NOT NULL
ORDER BY s.id";
$params = array(
'realuserid' => $data->participant,
'tempuserid' => $tempuser->studentid,
'attendanceid' => $att->id,
);
$logs = $DB->get_recordset_sql($sql, $params);
foreach ($logs as $log) {
if (!is_null($log->reallogid)) {
// Remove the existing attendance for the real user for this session.
$DB->delete_records('attendance_log', array('id' => $log->reallogid));
}
// Adjust the 'temp user' attendance record to point at the real user.
$DB->set_field('attendance_log', 'studentid', $data->participant, array('id' => $log->templogid));
}
// Delete the temp user.
$DB->delete_records('attendance_tempusers', array('id' => $tempuser->id));
$att->update_users_grade(array($data->participant)); // Update the gradebook after the merge.
redirect($att->url_managetemp());
}
/** @var mod_attendance_renderer $output */
$output = $PAGE->get_renderer('mod_attendance');
$tabs = new attendance_tabs($att, attendance_tabs::TAB_TEMPORARYUSERS);
echo $output->header();
echo $output->heading(get_string('tempusermerge', 'attendance').' : '.$course->fullname);
echo $output->render($tabs);
$mform->display();
echo $output->footer($course);

40
tempmerge_form.php

@ -0,0 +1,40 @@
<?php
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir.'/formslib.php');
class tempmerge_form extends moodleform {
function definition() {
global $COURSE;
$context = context_course::instance($COURSE->id);
$namefields = get_all_user_name_fields(true, 'u');
$students = get_enrolled_users($context, 'mod/attendance:canbelisted', 0, 'u.id,'.$namefields.',u.email',
'u.lastname, u.firstname', 0, 0, true);
$partarray = array();
foreach ($students as $student) {
$partarray[$student->id] = fullname($student).' ('.$student->email.')';
}
$mform = $this->_form;
$description = $this->_customdata['description'];
$mform->addElement('hidden', 'id', 0);
$mform->setType('id', PARAM_INT);
$mform->addElement('hidden', 'userid', 0);
$mform->setType('userid', PARAM_INT);
$mform->addElement('header', 'attheader', get_string('tempusermerge', 'attendance'));
$mform->addElement('static', 'description', get_string('tempuser', 'attendance'), $description);
$mform->addElement('select', 'participant', get_string('participant', 'attendance'), $partarray);
$mform->addElement('static', 'requiredentries', '', get_string('requiredentries', 'attendance'));
$mform->addHelpButton('requiredentries', 'requiredentry', 'attendance');
$this->add_action_buttons(true, get_string('mergeuser', 'attendance'));
}
}

127
tempusers.php

@ -0,0 +1,127 @@
<?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/>.
/**
* Temporary user management.
*
* @package mod_attendance
* @copyright 2013 Davo Smith, Synergy Learning
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(dirname(__FILE__).'/../../config.php');
global $CFG, $DB, $OUTPUT, $PAGE, $COURSE;
require_once($CFG->dirroot.'/mod/attendance/locallib.php');
require_once($CFG->dirroot.'/mod/attendance/temp_form.php');
$id = required_param('id', PARAM_INT);
$cm = get_coursemodule_from_id('attendance', $id, 0, false, MUST_EXIST);
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
$att = $DB->get_record('attendance', array('id' => $cm->instance), '*', MUST_EXIST);
$att = new attendance($att, $cm, $course);
$PAGE->set_url($att->url_managetemp());
require_login($course, true, $cm);
$att->perm->require_managetemp_capability();
$PAGE->set_title($course->shortname.": ".$att->name.' - '.get_string('tempusers', 'attendance'));
$PAGE->set_heading($course->fullname);
$PAGE->set_cacheable(true);
$PAGE->navbar->add(get_string('tempusers', 'attendance'));
/** @var mod_attendance_renderer $output */
$output = $PAGE->get_renderer('mod_attendance');
$tabs = new attendance_tabs($att, attendance_tabs::TAB_TEMPORARYUSERS);
$formdata = (object)array(
'id' => $cm->id,
);
$mform = new temp_form();
$mform->set_data($formdata);
if ($data = $mform->get_data()) {
// Create temp user in main user table.
$user = new stdClass();
$user->auth = 'manual';
$user->confirmed = 1;
$user->deleted = 1;
$user->email = time().'@ghost.user.de';
$user->username = time().'@ghost.user.de';
$user->idnumber = 'tempghost';
$studentid = $DB->insert_record('user', $user);
// Create the temporary user record.
$newtempuser = new stdClass();
$newtempuser->fullname = $data->tname;
$newtempuser->courseid = $COURSE->id;
$newtempuser->email = $data->temail;
$newtempuser->created = time();
$newtempuser->studentid = $studentid;
$DB->insert_record('attendance_tempusers', $newtempuser);
redirect($att->url_managetemp());
}
/// Output starts here
echo $output->header();
echo $output->heading(get_string('tempusers', 'attendance').' : '.$course->fullname);
echo $output->render($tabs);
$mform->display();
$tempusers = $DB->get_records('attendance_tempusers', array('courseid' => $course->id), 'fullname, email');
echo '<div>';
echo '<p style="margin-left:10%;">'.get_string('tempuserslist', 'attendance').'</p>';
if ($tempusers) {
print_tempusers($tempusers, $att);
}
echo '</div>';
echo $output->footer($course);
function print_tempusers($tempusers, attendance $att) {
echo '<p></p>';
echo '<table border="1" bordercolor="#EEEEEE" style="background-color:#fff" cellpadding="2" align="center" width="80%" summary="'.get_string('temptable', 'attendance').'"><tr>';
echo '<th class="header">'.get_string('tusername', 'attendance').'</th>';
echo '<th class="header">'.get_string('tuseremail', 'attendance').'</th>';
echo '<th class="header">'.get_string('tcreated', 'attendance').'</th>';
echo '<th class="header">'.get_string('tactions', 'attendance').'</th>';
echo '</tr>';
$even = false; // used to colour rows
foreach ($tempusers as $tempuser) {
if ($even) {
echo '<tr style="background-color: #FCFCFC">';
} else {
echo '<tr>';
}
$even = !$even;
echo '<td>'.format_string($tempuser->fullname).'</td>';
echo '<td>'.format_string($tempuser->email).'</td>';
echo '<td>'.userdate($tempuser->created, get_string('strftimedatetime')).'</td>';
$params = array('userid' => $tempuser->id);
$editlink = html_writer::link($att->url_tempedit($params), get_string('edituser', 'attendance'));
$deletelink = html_writer::link($att->url_tempdelete($params), get_string('deleteuser', 'attendance'));
$mergelink = html_writer::link($att->url_tempmerge($params), get_string('mergeuser', 'attendance'));
echo '<td>'.$editlink.' | '.$deletelink.' | '.$mergelink.'</td>';
echo '</tr>';
}
echo '</table>';
}

112
tests/behat/extra_features.feature

@ -0,0 +1,112 @@
@mod @mod_attendance @javascript
Feature: Test the various new features in the attendance module
Background:
Given the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
| student2 | Student | 2 | student2@example.com |
| student3 | Student | 3 | student3@example.com |
| student4 | Student | 4 | student4@example.com |
| student5 | Student | 5 | student5@example.com |
And the following "course enrolments" exist:
| course | user | role |
| C1 | teacher1 | editingteacher |
| C1 | student1 | student |
| C1 | student2 | student |
| C1 | student3 | student |
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 fill the form with:
| Name | Test attendance |
And I log out
Scenario: A teacher can create and update temporary users
Given I log in as "teacher1"
And I follow "Course 1"
And I follow "Test attendance"
And I follow "Temporary users"
When I set the following fields to these values:
| Full name | Temporary user 1 |
| Email | |
And I press "Add user"
And I set the following fields to these values:
| Full name | Temporary user test 2 |
| Email | tempuser2test@example.com |
And I press "Add user"
Then I should see "Temporary user 1"
And "tempuser2test@example.com" "text" should exist in the "Temporary user test 2" "table_row"
When I click on "Edit user" "link" in the "Temporary user test 2" "table_row"
And the following fields match these values:
| Full name | Temporary user test 2 |
| Email | tempuser2test@example.com |
And I set the following fields to these values:
| Full name | Temporary user 2 |
| Email | tempuser2@example.com |
And I press "Edit user"
Then "tempuser2@example.com" "text" should exist in the "Temporary user 2" "table_row"
When I click on "Delete user" "link" in the "Temporary user 1" "table_row"
And I press "Continue"
Then I should not see "Temporary user 1"
And I should see "Temporary user 2"
Scenario: A teacher can take attendance for temporary users
Given I log in as "teacher1"
And I follow "Course 1"
And I follow "Test attendance"
And I follow "Temporary users"
And I set the following fields to these values:
| Full name | Temporary user 1 |
| Email | |
And I press "Add user"
And I set the following fields to these values:
| Full name | Temporary user 2 |
| Email | tempuser2@example.com |
And I press "Add user"
And I follow "Add"
And I set the following fields to these values:
| Create multiple sessions | 0 |
And I click on "submitbutton" "button"
And I follow "Sessions"
When I follow "Take attendance"
# Present
And I click on "td.c2 input" "css_element" in the "Student 1" "table_row"
# Late
And I click on "td.c3 input" "css_element" in the "Student 2" "table_row"
# Excused
And I click on "td.c4 input" "css_element" in the "Temporary user 1" "table_row"
# Absent
And I click on "td.c5 input" "css_element" in the "Temporary user 2" "table_row"
And I press "Save attendance"
And I follow "Report"
Then "P" "text" should exist in the "Student 1" "table_row"
And "L" "text" should exist in the "Student 2" "table_row"
And "E" "text" should exist in the "Temporary user 1" "table_row"
And "A" "text" should exist in the "Temporary user 2" "table_row"
When I follow "Temporary user 2"
Then I should see "Absent"
# Merge user.
When I follow "Test attendance"
And I follow "Temporary users"
And I click on "Merge user" "link" in the "Temporary user 2" "table_row"
And I set the field "Participant" to "Student 3"
And I press "Merge user"
And I follow "Report"
Then "P" "text" should exist in the "Student 1" "table_row"
And "L" "text" should exist in the "Student 2" "table_row"
And "E" "text" should exist in the "Temporary user 1" "table_row"
And "A" "text" should exist in the "Student 3" "table_row"
And I should not see "Temporary user 2"

2
version.php

@ -22,7 +22,7 @@
* @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
*/ */
$plugin->version = 2015040500; $plugin->version = 2015040501;
$plugin->requires = 2014042900; $plugin->requires = 2014042900;
$plugin->release = '2.9.1'; $plugin->release = '2.9.1';
$plugin->maturity = MATURITY_STABLE; $plugin->maturity = MATURITY_STABLE;

Loading…
Cancel
Save