Browse Source

Move hide session details (#238)

* Fixing missing fields in backup

* Fixing behat test due to changes in Moodle 3.2

* Add users taken sessions by acronym columns to the export report

* Fixing user name sort order links

* Adding buttons to hide/show session details and move them left/rigth

* Fixing errors and warnings reported by travis

* Fixing failures in behat tests because of enrol start date
MOODLE_32_STABLE
antonio-c-mariani 8 years ago
committed by Dan Marsden
parent
commit
db0ed29c43
  1. 9
      backup/moodle2/backup_attendance_stepslib.php
  2. 10
      classes/report_page_params.php
  3. 15
      classes/structure.php
  4. 2
      db/install.xml
  5. 13
      db/upgrade.php
  6. 19
      export.php
  7. 25
      lang/en/attendance.php
  8. 576
      renderer.php
  9. 3
      report.php
  10. 22
      styles.css
  11. 14
      tests/behat/attendance_mod.feature
  12. 11
      tests/behat/calendar_features.feature
  13. 15
      tests/behat/extra_features.feature
  14. 11
      tests/behat/preferences.feature
  15. 30
      tests/behat/report.feature
  16. 2
      version.php

9
backup/moodle2/backup_attendance_stepslib.php

@ -44,22 +44,21 @@ class backup_attendance_activity_structure_step extends backup_activity_structur
// XML nodes declaration - non-user data.
$attendance = new backup_nested_element('attendance', array('id'), array(
'name', 'grade'));
'name', 'grade', 'showsessiondetails', 'sessiondetailspos'));
$statuses = new backup_nested_element('statuses');
$status = new backup_nested_element('status', array('id'), array(
'acronym', 'description', 'grade', 'visible', 'deleted'));
'acronym', 'description', 'grade', 'visible', 'deleted', 'setnumber'));
$sessions = new backup_nested_element('sessions');
$session = new backup_nested_element('session', array('id'), array(
'groupid', 'sessdate', 'duration', 'lasttaken', 'lasttakenby',
'timemodified', 'description', 'descriptionformat', 'caleventid'));
'timemodified', 'description', 'descriptionformat', 'studentscanmark', 'statusset', 'caleventid'));
// XML nodes declaration - user data.
$logs = new backup_nested_element('logs');
$log = new backup_nested_element('log', array('id'), array(
'sessionid', 'studentid', 'statusid', 'lasttaken', 'statusset',
'timetaken', 'takenby', 'remarks'));
'sessionid', 'studentid', 'statusid', 'statusset', 'timetaken', 'takenby', 'remarks'));
// Build the tree in the order needed for restore.
$attendance->add_child($statuses);

10
classes/report_page_params.php

@ -32,6 +32,8 @@ defined('MOODLE_INTERNAL') || die();
class mod_attendance_report_page_params extends mod_attendance_page_with_filter_controls {
public $group;
public $sort;
public $showsessiondetails;
public $sessiondetailspos;
public function __construct() {
$this->selectortype = self::SELECTOR_GROUP;
@ -55,6 +57,14 @@ class mod_attendance_report_page_params extends mod_attendance_page_with_filter_
$params['sort'] = $this->sort;
}
if (empty($this->showsessiondetails)) {
$params['showsessiondetails'] = 0;
}
if ($this->sessiondetailspos != 'left') {
$params['sessiondetailspos'] = $this->sessiondetailspos;
}
return $params;
}
}

15
classes/structure.php

@ -61,6 +61,12 @@ class mod_attendance_structure {
public $subnet;
/** Define if session details should be shown in reports */
public $showsessiondetails;
/** Position for the session detail columns related to summary columns.*/
public $sessiondetailspos;
private $groupmode;
private $statuses;
@ -81,6 +87,8 @@ class mod_attendance_structure {
* @param stdClass $context The context of the workshop instance
*/
public function __construct(stdclass $dbrecord, stdclass $cm, stdclass $course, stdclass $context=null, $pageparams=null) {
global $DB;
foreach ($dbrecord as $field => $value) {
if (property_exists('mod_attendance_structure', $field)) {
$this->{$field} = $value;
@ -97,6 +105,13 @@ class mod_attendance_structure {
}
$this->pageparams = $pageparams;
if (isset($pageparams->showsessiondetails) && $pageparams->showsessiondetails != $this->showsessiondetails) {
$DB->set_field('attendance', 'showsessiondetails', $pageparams->showsessiondetails, array('id' => $this->id));
}
if (isset($pageparams->sessiondetailspos) && $pageparams->sessiondetailspos != $this->sessiondetailspos) {
$DB->set_field('attendance', 'sessiondetailspos', $pageparams->sessiondetailspos, array('id' => $this->id));
}
}
public function get_group_mode() {

2
db/install.xml

@ -12,6 +12,8 @@
<FIELD NAME="grade" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="100" SEQUENCE="false" COMMENT="This is maximum grade for instance"/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The time the settings for this attendance instance were last modified."/>
<FIELD NAME="subnet" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="Restrict ability for students to mark by subnet."/>
<FIELD NAME="sessiondetailspos" TYPE="char" LENGTH="5" NOTNULL="true" DEFAULT="left" SEQUENCE="false" COMMENT="Position for the session detail columns related to summary columns."/>
<FIELD NAME="showsessiondetails" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" SEQUENCE="false" COMMENT="Define if session details should be shown in reports."/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for attendance"/>

13
db/upgrade.php

@ -201,5 +201,18 @@ function xmldb_attendance_upgrade($oldversion=0) {
upgrade_mod_savepoint(true, 2016112100, 'attendance');
}
if ($oldversion < 2016121300) {
$table = new xmldb_table('attendance');
$field = new xmldb_field('sessiondetailspos', XMLDB_TYPE_CHAR, '5', null, null, null, 'left', 'subnet');
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
$field = new xmldb_field('showsessiondetails', XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '1', 'subnet');
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
upgrade_mod_savepoint(true, 2016121300, 'attendance');
}
return $result;
}

19
export.php

@ -122,6 +122,16 @@ if ($formdata = $mform->get_data()) {
} else {
print_error('sessionsnotfound', 'attendance', $att->url_manage());
}
$setnumber = -1;
foreach ($reportdata->statuses as $sts) {
if ($sts->setnumber != $setnumber) {
$setnumber = $sts->setnumber;
}
$data->tabhead[] = $sts->acronym;
}
$data->tabhead[] = get_string('takensessions', 'attendance');
$data->tabhead[] = get_string('points', 'attendance');
$data->tabhead[] = get_string('percentage', 'attendance');
@ -158,6 +168,15 @@ if ($formdata = $mform->get_data()) {
$data->table[$i] = array_merge($data->table[$i], $cellsgenerator->get_cells(isset($formdata->includeremarks)));
$usersummary = $reportdata->summary->get_taken_sessions_summary_for($user->id);
foreach ($reportdata->statuses as $sts) {
if (isset($usersummary->userstakensessionsbyacronym[$sts->setnumber][$sts->acronym])) {
$data->table[$i][] = $usersummary->userstakensessionsbyacronym[$sts->setnumber][$sts->acronym];
} else {
$data->table[$i][] = 0;
}
}
$data->table[$i][] = $usersummary->numtakensessions;
$data->table[$i][] = format_float($usersummary->takensessionspoints, 1, true, true) . ' / ' .
format_float($usersummary->takensessionsmaxpoints, 1, true, true);

25
lang/en/attendance.php

@ -26,6 +26,7 @@ $string['attendance:addinstance'] = 'Add a new attendance activity';
$string['Aacronym'] = 'A';
$string['adduser'] = 'Add user';
$string['Afull'] = 'Absent';
$string['allsessions'] = 'All sessions';
$string['Eacronym'] = 'E';
$string['Efull'] = 'Excused';
$string['Lacronym'] = 'L';
@ -127,6 +128,7 @@ $string['hiddensessions'] = 'Hidden sessions';
$string['hiddensessions_help'] = 'Sessions are hidden if they are scheduled before the course start date.
You can use this feature to hide older sessions instead of deleting them. Only visible sessions will appear in the Gradebook.';
$string['hidensessiondetails'] = 'Hide session details';
$string['identifyby'] = 'Identify student by';
$string['includeall'] = 'Select all sessions';
$string['includenottaken'] = 'Include not taken sessions';
@ -135,6 +137,12 @@ $string['indetail'] = 'In detail...';
$string['invalidsessionenddate'] = 'This date can not be earlier than the session date';
$string['invalidaction'] = 'You must select an action';
$string['jumpto'] = 'Jump to';
$string['maxpossible'] = 'Maximum possible';
$string['maxpossible_help'] = 'Shows the maximum points and percentages that each user can reach if they receive the maximum points of each session not yet taken (past and future):
<ul>
<li><strong>Points</strong>: maximum points each user can reach over all sessions.</li>
<li><strong>Percentage</strong>: maximum percentage each user can reach over all sessions.</li>
</ul>';
$string['maxpossiblepoints'] = 'Maximum possible points';
$string['maxpossiblepercentage'] = 'Maximum possible percentage';
$string['mergeuser'] = 'Merge user';
@ -147,6 +155,8 @@ Reports are available for the entire class or individual students.';
$string['modulenameplural'] = 'Attendances';
$string['months'] = 'Months';
$string['moreattendance'] = 'Attendance has been successfully taken for this page';
$string['moveleft'] = 'Move left';
$string['moveright'] = 'Move right';
$string['mustselectusers'] = 'Must select users to export';
$string['myvariables'] = 'My Variables';
$string['newdate'] = 'New date';
@ -249,6 +259,7 @@ $string['setallstatusesto'] = 'Set status for all users to «{$a}»';
$string['settings'] = 'Settings';
$string['showdefaults'] = 'Show defaults';
$string['showduration'] = 'Show duration';
$string['showsessiondetails'] = 'Show session details';
$string['sortedgrid'] = 'Sorted grid';
$string['sortedlist'] = 'Sorted list';
$string['startofperiod'] = 'Start of period';
@ -312,6 +323,20 @@ $string['submitattendance'] = 'Submit attendance';
$string['attendancenotset'] = 'You must set your attendance';
$string['export'] = 'Export';
$string['points'] = 'Points';
$string['oversessionstaken'] = 'Over taken sessions';
$string['oversessionstaken_help'] = 'Shows the points and percentages of each user over the taken sessions:
<ul>
<li><strong>Sessions</strong>: number of already taken sessions.</li>
<li><strong>Points</strong>: points due to each user based on the taken sessions.</li>
<li><strong>Percentage</strong>: percentage of points due to each user over the maxium possible points of the taken sessions.</li>
</ul>';
$string['overallsessions'] = 'Over all sessions';
$string['overallsessions_help'] = 'Shows the points and percentages of each user over all sessions including those not yet taken (past and future):
<ul>
<li><strong>Sessions</strong>: total number of sessions.</li>
<li><strong>Points</strong>: points due to each user based on all sessions.</li>
<li><strong>Percentage</strong>: percentage of points due to each user over the maxium possible points of all sessions.</li>
</ul>';
$string['pointssessionscompleted'] = 'Points over taken sessions';
$string['pointsallsessions'] = 'Points over all sessions';
$string['unknowngroup'] = 'Unknown group';

576
renderer.php

@ -622,12 +622,15 @@ class mod_attendance_renderer extends plugin_renderer_base {
private function construct_fullname_head($data) {
global $CFG;
$url = $data->url();
if ($data->pageparams->sort == ATT_SORT_LASTNAME) {
$firstname = html_writer::link($data->url(array('sort' => ATT_SORT_FIRSTNAME)), get_string('firstname'));
$url->param('sort', ATT_SORT_FIRSTNAME);
$firstname = html_writer::link($url, get_string('firstname'));
$lastname = get_string('lastname');
} else if ($data->pageparams->sort == ATT_SORT_FIRSTNAME) {
$firstname = get_string('firstname');
$lastname = html_writer::link($data->url(array('sort' => ATT_SORT_LASTNAME)), get_string('lastname'));
$url->param('sort', ATT_SORT_LASTNAME);
$lastname = html_writer::link($url, get_string('lastname'));
} else {
$firstname = html_writer::link($data->url(array('sort' => ATT_SORT_FIRSTNAME)), get_string('firstname'));
$lastname = html_writer::link($data->url(array('sort' => ATT_SORT_LASTNAME)), get_string('lastname'));
@ -846,175 +849,357 @@ class mod_attendance_renderer extends plugin_renderer_base {
// 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->attributes['class'] = 'generaltable attwidth attreport';
$table->attributes['class'] = 'generaltable attwidth';
$userrows = $this->get_user_rows($reportdata);
if ($reportdata->pageparams->view == ATT_VIEW_SUMMARY) {
$table->attributes['class'] .= ' summaryreport';
$sessionrows = array();
} else {
$sessionrows = $this->get_session_rows($reportdata);
}
$colclass = null;
// User picture.
$table->head[] = '';
$table->align[] = 'left';
$table->size[] = '1px';
$table->colclasses[] = $colclass;
$setnumber = -1;
$statusetcount = 0;
foreach ($reportdata->statuses as $sts) {
if ($sts->setnumber != $setnumber) {
$statusetcount++;
$setnumber = $sts->setnumber;
}
}
$table->head[] = $this->construct_fullname_head($reportdata);
$table->align[] = 'left';
$table->size[] = '';
$table->colclasses[] = $colclass;
$sessionstats = array();
$acronymrows = $this->get_acronym_rows($reportdata, true);
$startwithcontrast = $statusetcount % 2 == 0;
$summaryrows = $this->get_summary_rows($reportdata, $startwithcontrast);
foreach ($reportdata->sessions as $sess) {
$sesstext = userdate($sess->sessdate, get_string('strftimedm', 'attendance'));
$sesstext .= html_writer::empty_tag('br');
$sesstext .= userdate($sess->sessdate, '('.get_string('strftimehm', 'attendance').')');
$capabilities = array(
'mod/attendance:takeattendances',
'mod/attendance:changeattendances'
);
if (is_null($sess->lasttaken) and has_any_capability($capabilities, $reportdata->att->context)) {
$sesstext = html_writer::link($reportdata->url_take($sess->id, $sess->groupid), $sesstext);
}
$sesstext .= html_writer::empty_tag('br');
if ($sess->groupid) {
if (empty($reportdata->groups[$sess->groupid])) {
$sesstext .= get_string('deletedgroup', 'attendance');
// 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);
if ($bulkmessagecapability) {
$bulkmessagingrows = $this->get_bulkmessage_rows($reportdata);
}
// Extract rows from each part and collate them into one row each.
$sessiondetailsleft = $reportdata->pageparams->sessiondetailspos == 'left';
foreach ($userrows as $index => $row) {
$summaryrow = isset($summaryrows[$index]->cells) ? $summaryrows[$index]->cells : array();
$bulkmessagingrow = isset($bulkmessagingrows[$index]->cells) ? $bulkmessagingrows[$index]->cells : array();
$sessionrow = isset($sessionrows[$index]->cells) ? $sessionrows[$index]->cells : array();
if ($sessiondetailsleft) {
$row->cells = array_merge($row->cells, $sessionrow, $acronymrows[$index]->cells, $summaryrow, $bulkmessagingrow);
} else {
$sesstext .= get_string('group') . ': ' . $reportdata->groups[$sess->groupid]->name;
$row->cells = array_merge($row->cells, $acronymrows[$index]->cells, $summaryrow, $sessionrow, $bulkmessagingrow);
}
$table->data[] = $row;
}
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' => $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 {
$sesstext .= get_string('commonsession', 'attendance');
return html_writer::table($table).html_writer::tag('div', get_string('users').': '.count($reportdata->users));
}
}
$table->head[] = $sesstext;
$table->align[] = 'center';
$table->size[] = '1px';
$table->colclasses[] = $colclass;
/**
* Build and return the rows that will make up the left part of the attendance report.
* This consists of student names and icons, as well as header cells for these columns.
*
* @param attendance_report_data $reportdata the report data
* @return array Array of html_table_row objects
*/
protected function get_user_rows(attendance_report_data $reportdata) {
$rows = array();
$row = new html_table_row();
$row->cells[] = $this->build_header_cell('');
$row->cells[] = $this->build_header_cell(get_string('users'), false, false);
$rows[] = $row;
$row = new html_table_row();
$row->cells[] = $this->build_header_cell('');
$row->cells[] = $this->build_header_cell($this->construct_fullname_head($reportdata), false, false);
$rows[] = $row;
foreach ($reportdata->users as $user) {
$row = new html_table_row();
$row->cells[] = $this->build_data_cell($this->user_picture($user));
$text = html_writer::link($reportdata->url_view(array('studentid' => $user->id)), fullname($user));
$row->cells[] = $this->build_data_cell($text, false, false, null, null, false);
$rows[] = $row;
}
$row = new html_table_row();
$row->cells[] = $this->build_data_cell('');
$text = ($reportdata->pageparams->view == ATT_VIEW_SUMMARY) ? '' : get_string('summary');
$row->cells[] = $this->build_data_cell($text);
$rows[] = $row;
return $rows;
}
/**
* Build and return the rows that will make up the summary part of the attendance report.
* This consists of countings for each status set acronyms, as well as header cells for these columns.
*
* @param attendance_report_data $reportdata the report data
* @param boolean $startwithcontrast true if the first column must start with contrast (bgcolor)
* @return array Array of html_table_row objects
*/
protected function get_acronym_rows(attendance_report_data $reportdata, $startwithcontrast=false) {
$rows = array();
$summarycells = array();
$row1 = new html_table_row();
$row2 = new html_table_row();
$setnumber = -1;
$contrast = !$startwithcontrast;
foreach ($reportdata->statuses as $sts) {
if ($sts->setnumber != $setnumber) {
$colclass = empty($colclass) ? 'columncontrast' : null;
$contrast = !$contrast;
$setnumber = $sts->setnumber;
$text = attendance_get_setname($reportdata->att->id, $setnumber, false);
$cell = $this->build_header_cell($text, $contrast);
$row1->cells[] = $cell;
}
$cell->colspan++;
$sts->contrast = $contrast;
$row2->cells[] = $this->build_header_cell($sts->acronym, $contrast);
$summarycells[] = $this->build_data_cell('', $contrast);
}
$table->head[] = $sts->acronym;
$table->align[] = 'center';
$table->size[] = '1px';
$table->colclasses[] = $colclass;
$rows[] = $row1;
$rows[] = $row2;
foreach ($reportdata->users as $user) {
if ($reportdata->pageparams->view == ATT_VIEW_SUMMARY) {
$usersummary = $reportdata->summary->get_all_sessions_summary_for($user->id);
} else {
$usersummary = $reportdata->summary->get_taken_sessions_summary_for($user->id);
}
$table->head[] = get_string('takensessions', 'attendance');
$table->align[] = 'center';
$table->size[] = '1px';
$colclass = empty($colclass) ? 'columncontrast' : null;
$table->colclasses[] = $colclass;
$row = new html_table_row();
foreach ($reportdata->statuses as $sts) {
if (isset($usersummary->userstakensessionsbyacronym[$sts->setnumber][$sts->acronym])) {
$text = $usersummary->userstakensessionsbyacronym[$sts->setnumber][$sts->acronym];
} else {
$text = 0;
}
$row->cells[] = $this->build_data_cell($text, $sts->contrast);
}
$table->head[] = get_string('points', 'attendance');
$table->align[] = 'center';
$table->size[] = '1px';
$table->colclasses[] = $colclass;
$rows[] = $row;
}
$table->head[] = get_string('percentage', 'attendance');
$table->align[] = 'center';
$table->size[] = '1px';
$table->colclasses[] = $colclass;
$rows[] = new html_table_row($summarycells);
return $rows;
}
/**
* Build and return the rows that will make up the summary part of the attendance report.
* This consists of counts and percentages for taken sessions (all sessions for summary report),
* as well as header cells for these columns.
*
* @param attendance_report_data $reportdata the report data
* @param boolean $startwithcontrast true if the first column must start with contrast (bgcolor)
* @return array Array of html_table_row objects
*/
protected function get_summary_rows(attendance_report_data $reportdata, $startwithcontrast=false) {
$rows = array();
$contrast = $startwithcontrast;
$summarycells = array();
$row1 = new html_table_row();
$helpicon = $this->output->help_icon('oversessionstaken', 'attendance');
$row1->cells[] = $this->build_header_cell(get_string('oversessionstaken', 'attendance') . $helpicon, $contrast, true, 3);
$row2 = new html_table_row();
$row2->cells[] = $this->build_header_cell(get_string('sessions', 'attendance'), $contrast);
$row2->cells[] = $this->build_header_cell(get_string('points', 'attendance'), $contrast);
$row2->cells[] = $this->build_header_cell(get_string('percentage', 'attendance'), $contrast);
$summarycells[] = $this->build_data_cell('', $contrast);
$summarycells[] = $this->build_data_cell('', $contrast);
$summarycells[] = $this->build_data_cell('', $contrast);
if ($reportdata->pageparams->view == ATT_VIEW_SUMMARY) {
$table->head[] = get_string('sessionstotal', 'attendance');
$table->align[] = 'center';
$table->size[] = '1px';
$colclass = empty($colclass) ? 'columncontrast' : null;
$table->colclasses[] = $colclass;
$contrast = !$contrast;
$table->head[] = get_string('pointsallsessions', 'attendance');
$table->align[] = 'center';
$table->size[] = '1px';
$table->colclasses[] = $colclass;
$helpicon = $this->output->help_icon('overallsessions', 'attendance');
$row1->cells[] = $this->build_header_cell(get_string('overallsessions', 'attendance') . $helpicon, $contrast, true, 3);
$table->head[] = get_string('percentageallsessions', 'attendance');
$table->align[] = 'center';
$table->size[] = '1px';
$table->colclasses[] = $colclass;
$row2->cells[] = $this->build_header_cell(get_string('sessions', 'attendance'), $contrast);
$row2->cells[] = $this->build_header_cell(get_string('points', 'attendance'), $contrast);
$row2->cells[] = $this->build_header_cell(get_string('percentage', 'attendance'), $contrast);
$summarycells[] = $this->build_data_cell('', $contrast);
$summarycells[] = $this->build_data_cell('', $contrast);
$summarycells[] = $this->build_data_cell('', $contrast);
$table->head[] = get_string('maxpossiblepoints', 'attendance');
$table->align[] = 'center';
$table->size[] = '1px';
$colclass = empty($colclass) ? 'columncontrast' : null;
$table->colclasses[] = $colclass;
$contrast = !$contrast;
$helpicon = $this->output->help_icon('maxpossible', 'attendance');
$row1->cells[] = $this->build_header_cell(get_string('maxpossible', 'attendance') . $helpicon, $contrast, true, 2);
$table->head[] = get_string('maxpossiblepercentage', 'attendance');
$table->align[] = 'center';
$table->size[] = '1px';
$table->colclasses[] = $colclass;
$row2->cells[] = $this->build_header_cell(get_string('points', 'attendance'), $contrast);
$row2->cells[] = $this->build_header_cell(get_string('percentage', 'attendance'), $contrast);
$summarycells[] = $this->build_data_cell('', $contrast);
$summarycells[] = $this->build_data_cell('', $contrast);
}
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';
}
$rows[] = $row1;
$rows[] = $row2;
foreach ($reportdata->users as $user) {
$row = new html_table_row();
$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));
$cellsgenerator = new user_sessions_cells_html_generator($reportdata, $user);
$row->cells = array_merge($row->cells, $cellsgenerator->get_cells(true));
if ($reportdata->pageparams->view == ATT_VIEW_SUMMARY) {
$usersummary = $reportdata->summary->get_all_sessions_summary_for($user->id);
} else {
$usersummary = $reportdata->summary->get_taken_sessions_summary_for($user->id);
}
foreach ($reportdata->statuses as $sts) {
if (isset($usersummary->userstakensessionsbyacronym[$sts->setnumber][$sts->acronym])) {
$row->cells[] = $usersummary->userstakensessionsbyacronym[$sts->setnumber][$sts->acronym];
} else {
$row->cells[] = 0;
}
}
$row->cells[] = $usersummary->numtakensessions;
$row->cells[] = format_float($usersummary->takensessionspoints, 1, true, true) . ' / ' .
$contrast = $startwithcontrast;
$row = new html_table_row();
$row->cells[] = $this->build_data_cell($usersummary->numtakensessions, $contrast);
$text = format_float($usersummary->takensessionspoints, 1, true, true) . ' / ' .
format_float($usersummary->takensessionsmaxpoints, 1, true, true);
$row->cells[] = format_float($usersummary->takensessionspercentage * 100) . '%';
$row->cells[] = $this->build_data_cell($text, $contrast);
$row->cells[] = $this->build_data_cell(format_float($usersummary->takensessionspercentage * 100) . '%', $contrast);
if ($reportdata->pageparams->view == ATT_VIEW_SUMMARY) {
$row->cells[] = $usersummary->numallsessions;
$row->cells[] = format_float($usersummary->takensessionspoints, 1, true, true) . ' / ' .
$contrast = !$contrast;
$row->cells[] = $this->build_data_cell($usersummary->numallsessions, $contrast);
$text = format_float($usersummary->takensessionspoints, 1, true, true) . ' / ' .
format_float($usersummary->allsessionsmaxpoints, 1, true, true);
$row->cells[] = format_float($usersummary->allsessionspercentage * 100) . '%';
$row->cells[] = $this->build_data_cell($text, $contrast);
$row->cells[] = $this->build_data_cell(format_float($usersummary->allsessionspercentage * 100) . '%', $contrast);
$row->cells[] = format_float($usersummary->maxpossiblepoints, 1, true, true) . ' / ' .
$contrast = !$contrast;
$text = format_float($usersummary->maxpossiblepoints, 1, true, true) . ' / ' .
format_float($usersummary->allsessionsmaxpoints, 1, true, true);
$row->cells[] = format_float($usersummary->maxpossiblepercentage * 100) . '%';
$row->cells[] = $this->build_data_cell($text, $contrast);
$row->cells[] = $this->build_data_cell(format_float($usersummary->maxpossiblepercentage * 100) . '%', $contrast);
}
if ($bulkmessagecapability) { // Create the checkbox for bulk messaging.
$row->cells[] = html_writer::checkbox('user'.$user->id, 'on', false, '',
array('class' => 'attendancesesscheckbox'));
$rows[] = $row;
}
$table->data[] = $row;
$rows[] = new html_table_row($summarycells);
return $rows;
}
if ($reportdata->pageparams->view != ATT_VIEW_SUMMARY) {
// Calculate the sum of statuses for each user.
$statrow = new html_table_row();
$statrow->cells[] = '';
$statrow->cells[] = get_string('summary');
/**
* Build and return the rows that will make up the attendance report.
* This consists of details for each selected session, as well as header and summary cells for these columns.
*
* @param attendance_report_data $reportdata the report data
* @param boolean $startwithcontrast true if the first column must start with contrast (bgcolor)
* @return array Array of html_table_row objects
*/
protected function get_session_rows(attendance_report_data $reportdata, $startwithcontrast=false) {
global $OUTPUT;
$rows = array();
$row = new html_table_row();
$showsessiondetails = $reportdata->pageparams->showsessiondetails;
$text = get_string('sessions', 'attendance');
$params = $reportdata->pageparams->get_significant_params();
if (count($reportdata->sessions) > 1) {
if ($showsessiondetails) {
$params['showsessiondetails'] = 0;
$url = $reportdata->att->url_report($params);
$text .= $OUTPUT->action_icon($url, new pix_icon('t/switch_minus',
get_string('hidensessiondetails', 'attendance')), null, null);
$colspan = count($reportdata->sessions);
} else {
$params['showsessiondetails'] = 1;
$url = $reportdata->att->url_report($params);
$text .= $OUTPUT->action_icon($url, new pix_icon('t/switch_plus',
get_string('showsessiondetails', 'attendance')), null, null);
$colspan = 1;
}
} else {
$colspan = 1;
}
$params = $reportdata->pageparams->get_significant_params();
if ($reportdata->pageparams->sessiondetailspos == 'left') {
$params['sessiondetailspos'] = 'right';
$url = $reportdata->att->url_report($params);
$text .= $OUTPUT->action_icon($url, new pix_icon('t/right', get_string('moveright', 'attendance')), null, null);
} else {
$params['sessiondetailspos'] = 'left';
$url = $reportdata->att->url_report($params);
$text = $OUTPUT->action_icon($url, new pix_icon('t/left', get_string('moveleft', 'attendance')), null, null) . $text;
}
$row->cells[] = $this->build_header_cell($text, '', true, $colspan);
$rows[] = $row;
$row = new html_table_row();
if ($showsessiondetails && !empty($reportdata->sessions)) {
foreach ($reportdata->sessions as $sess) {
$sesstext = userdate($sess->sessdate, get_string('strftimedm', 'attendance'));
$sesstext .= html_writer::empty_tag('br');
$sesstext .= userdate($sess->sessdate, '('.get_string('strftimehm', 'attendance').')');
$capabilities = array(
'mod/attendance:takeattendances',
'mod/attendance:changeattendances'
);
if (is_null($sess->lasttaken) and has_any_capability($capabilities, $reportdata->att->context)) {
$sesstext = html_writer::link($reportdata->url_take($sess->id, $sess->groupid), $sesstext);
}
$sesstext .= html_writer::empty_tag('br');
if ($sess->groupid) {
if (empty($reportdata->groups[$sess->groupid])) {
$sesstext .= html_writer::tag('small', get_string('deletedgroup', 'attendance'));
} else {
$sesstext .= html_writer::tag('small', $reportdata->groups[$sess->groupid]->name);
}
} else {
$sesstext .= html_writer::tag('small', get_string('commonsession', 'attendance'));
}
$row->cells[] = $this->build_header_cell($sesstext, false, true, null, null, false);
}
} else {
$row->cells[] = $this->build_header_cell('');
}
$rows[] = $row;
foreach ($reportdata->users as $user) {
$row = new html_table_row();
if ($showsessiondetails && !empty($reportdata->sessions)) {
$cellsgenerator = new user_sessions_cells_html_generator($reportdata, $user);
foreach ($cellsgenerator->get_cells(true) as $cell) {
if ($cell instanceof html_table_cell) {
$cell->attributes['class'] .= ' center';
$row->cells[] = $cell;
} else {
$row->cells[] = $this->build_data_cell($cell);
}
}
} else {
$row->cells[] = $this->build_data_cell('');
}
$rows[] = $row;
}
$row = new html_table_row();
if ($showsessiondetails && !empty($reportdata->sessions)) {
foreach ($reportdata->sessions as $sess) {
$sessionstats = array();
foreach ($reportdata->statuses as $status) {
@ -1037,36 +1222,143 @@ class mod_attendance_renderer extends plugin_renderer_base {
foreach ($sessionstats as $status) {
$statsoutput .= "$status->description: {$status->count}<br/>";
}
$cell = new html_table_cell($statsoutput);
$cell->style = 'white-space:nowrap;';
$statrow->cells[] = $cell;
$row->cells[] = $this->build_data_cell($statsoutput);
}
foreach ($reportdata->statuses as $sts) {
$statrow->cells[] = '';
} else {
$row->cells[] = $this->build_header_cell('');
}
$statrow->cells[] = '';
$statrow->cells[] = '';
$statrow->cells[] = '';
$statrow->cells[] = '';
$table->data[] = $statrow;
$rows[] = $row;
return $rows;
}
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' => $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'));
/**
* Build and return the rows that will make up the right part of the attendance report.
* This consists of checkbox column for bulk message.
*
* @param attendance_report_data $reportdata the report data
* @return array Array of html_table_row objects
*/
protected function get_bulkmessage_rows(attendance_report_data $reportdata) {
$rows = array();
$row = new html_table_row();
$row->cells[] = $this->build_header_cell('');
$rows[] = $row;
// Display the table header for bulk messaging.
// The checkbox must have an id of cb_selector so that the JavaScript will pick it up.
$row = new html_table_row();
$text = html_writer::checkbox('cb_selector', 0, false, '', array('id' => 'cb_selector'));
$row->cells[] = $this->build_header_cell($text);
$rows[] = $row;
foreach ($reportdata->users as $user) {
// Create the checkbox for bulk messaging.
$row = new html_table_row();
$text = html_writer::checkbox('user'.$user->id, 'on', false, '', array('class' => 'attendancesesscheckbox'));
$row->cells[] = $this->build_data_cell($text);
$rows[] = $row;
}
$row = new html_table_row();
$row->cells[] = $this->build_data_cell('');
$rows[] = $row;
return $rows;
}
/**
* Build and return a html_table_cell for header rows
*
* @param Mixed (html_table_cell or string) $cell the cell or a label for a cell
* @param boolean $contrast true menans the cell must be shown with bgcolor contrast
* @param boolean $center true means the cell text should be centered. Othersiwe it should be left-aligned.
* @param int $colspan how many columns should cell spans
* @param int $rowspan how many rows should cell spans
* @param boolean $nowrap true means the cell text must be shown with nowrap option
* @return html_table_cell a html table cell
*/
protected function build_header_cell($cell, $contrast=false, $center=true, $colspan=null, $rowspan=null, $nowrap=true) {
$classes = array('header', 'bottom');
if ($center) {
$classes[] = 'center';
$classes[] = 'narrow';
} else {
return html_writer::table($table).html_writer::tag('div', get_string('users').': '.count($reportdata->users));
$classes[] = 'left';
}
if ($contrast) {
$classes[] = 'contrast';
}
if ($nowrap) {
$classes[] = 'nowrap';
}
return $this->build_cell($cell, $classes, $colspan, $rowspan, true);
}
/**
* Build and return a html_table_cell for data rows
*
* @param Mixed (html_table_cell or string) $cell the cell or a label for a cell
* @param boolean $contrast true menans the cell must be shown with bgcolor contrast
* @param boolean $center true means the cell text should be centered. Othersiwe it should be left-aligned.
* @param int $colspan how many columns should cell spans
* @param int $rowspan how many rows should cell spans
* @param boolean $nowrap true means the cell text must be shown with nowrap option
* @return html_table_cell a html table cell
*/
protected function build_data_cell($cell, $contrast=false, $center=true, $colspan=null, $rowspan=null, $nowrap=true) {
$classes = array();
if ($center) {
$classes[] = 'center';
$classes[] = 'narrow';
} else {
$classes[] = 'left';
}
if ($nowrap) {
$classes[] = 'nowrap';
}
if ($contrast) {
$classes[] = 'contrast';
}
return $this->build_cell($cell, $classes, $colspan, $rowspan, false);
}
/**
* Build and return a html_table_cell for header or data rows
*
* @param Mixed (html_table_cell or string) $cell the cell or a label for a cell
* @param Array $classes a list of css classes
* @param int $colspan how many columns should cell spans
* @param int $rowspan how many rows should cell spans
* @param boolean $header true if this should be a header cell
* @return html_table_cell a html table cell
*/
protected function build_cell($cell, $classes, $colspan=null, $rowspan=null, $header=false) {
if (!($cell instanceof html_table_cell)) {
$cell = new html_table_cell($cell);
}
$cell->header = $header;
$cell->scope = 'col';
if (!empty($colspan) && $colspan > 1) {
$cell->colspan = $colspan;
}
if (!empty($rowspan) && $rowspan > 1) {
$cell->rowspan = $rowspan;
}
if (!empty($classes)) {
$classes = implode(' ', $classes);
if (empty($cell->attributes['class'])) {
$cell->attributes['class'] = $classes;
} else {
$cell->attributes['class'] .= ' ' . $classes;
}
}
return $cell;
}
/**

3
report.php

@ -46,6 +46,9 @@ $context = context_module::instance($cm->id);
require_capability('mod/attendance:viewreports', $context);
$pageparams->init($cm);
$pageparams->showsessiondetails = optional_param('showsessiondetails', $attrecord->showsessiondetails, PARAM_INT);
$pageparams->sessiondetailspos = optional_param('sessiondetailspos', $attrecord->sessiondetailspos, PARAM_TEXT);
$att = new mod_attendance_structure($attrecord, $cm, $course, $context, $pageparams);
$PAGE->set_url($att->url_report());

22
styles.css

@ -163,6 +163,26 @@
color: red;
}
.path-mod-attendance .columncontrast {
.path-mod-attendance .attreport .contrast {
background-color: #EAEAEA;
}
.path-mod-attendance .attreport .center {
text-align:center;
}
.path-mod-attendance .attreport .left {
text-align:left;
}
.path-mod-attendance .attreport .bottom {
vertical-align:bottom;
}
.path-mod-attendance .attreport .nowrap {
white-space:nowrap;
}
.path-mod-attendance .attreport .narrow {
width:1px;
}

14
tests/behat/attendance_mod.feature

@ -14,19 +14,22 @@ Feature: Teachers and Students can record session attendance
Background:
Given the following "courses" exist:
| fullname | shortname | summary | category |
| Course 1 | C101 | Prove the attendance activity works | 0 |
| fullname | shortname | summary | category | timecreated | timemodified |
| Course 1 | C1 | Prove the attendance activity works | 0 | ##yesterday## | ##yesterday## |
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 |
| course | user | role | timestart |
| C1 | student1 | student | ##yesterday## |
| C1 | teacher1 | editingteacher | ##yesterday## |
When I log in as "teacher1"
And I follow "Course 1"
And I turn editing mode on
And I follow "Add a block"
And I follow "Administration"
And I add a "Attendance" to section "1" and I fill the form with:
| Name | Attendance |
And I log out
@ -76,6 +79,7 @@ Feature: Teachers and Students can record session attendance
And I click on "Send a message" "button"
Then I should see "Message body"
And I should see "student1@asd.com"
And I follow "Course 1"
And I expand "Reports" node
And I follow "Logs"
And I click on "Get these logs" "button"

11
tests/behat/calendar_features.feature

@ -3,16 +3,17 @@ Feature: Test the calendar related features in the attendance module
Background:
Given the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
| fullname | shortname | summary | category | timecreated | timemodified |
| Course 1 | C1 | Prove the attendance activity works | 0 | ##yesterday## | ##yesterday## |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "course enrolments" exist:
| course | user | role |
| C1 | teacher1 | editingteacher |
| C1 | student1 | student |
| course | user | role | timestart |
| C1 | student1 | student | ##yesterday## |
| C1 | teacher1 | editingteacher | ##yesterday## |
And I log in as "teacher1"
And I follow "Course 1"
And I turn editing mode on

15
tests/behat/extra_features.feature

@ -3,8 +3,8 @@ Feature: Test the various new features in the attendance module
Background:
Given the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
| fullname | shortname | summary | category | timecreated | timemodified |
| Course 1 | C1 | Prove the attendance activity works | 0 | ##yesterday## | ##yesterday## |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
@ -14,11 +14,12 @@ Feature: Test the various new features in the attendance module
| 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 |
| course | user | role | timestart |
| C1 | teacher1 | editingteacher | ##yesterday## |
| C1 | student1 | student | ##yesterday## |
| C1 | student2 | student | ##yesterday## |
| C1 | student3 | student | ##yesterday## |
And I log in as "teacher1"
And I follow "Course 1"
And I turn editing mode on

11
tests/behat/preferences.feature

@ -6,16 +6,17 @@ Feature: Teachers can't change status variables to have empty acronyms or descri
Background:
Given the following "courses" exist:
| fullname | shortname | summary | category |
| Course 1 | C101 | Prove the attendance activity settings works | 0 |
| fullname | shortname | summary | category | timecreated | timemodified |
| Course 1 | C1 | Prove the attendance activity works | 0 | ##yesterday## | ##yesterday## |
And the following "users" exist:
| username | firstname | lastname |
| student1 | Sam | Student |
| teacher1 | Teacher | One |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C101 | student |
| teacher1 | C101 | editingteacher |
| course | user | role | timestart |
| C1 | student1 | student | ##yesterday## |
| C1 | teacher1 | editingteacher | ##yesterday## |
And I log in as "teacher1"
And I follow "Course 1"
And I turn editing mode on

30
tests/behat/report.feature

@ -4,16 +4,16 @@ Feature: Visiting reports
Background:
Given the following "courses" exist:
| fullname | shortname | summary | category |
| Course 1 | C101 | Prove the attendance activity works | 0 |
| fullname | shortname | summary | category | timecreated | timemodified |
| Course 1 | C1 | Prove the attendance activity works | 0 | ##yesterday## | ##yesterday## |
And the following "users" exist:
| username | firstname | lastname | email | idnumber | department | institution |
| student1 | Student | 1 | student1@asd.com | 1234 | computer science | University of Nottingham |
| teacher1 | Teacher | 1 | teacher1@asd.com | 5678 | computer science | University of Nottingham |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C101 | student |
| teacher1 | C101 | editingteacher |
| course | user | role | timestart |
| C1 | student1 | student | ##yesterday## |
| C1 | teacher1 | editingteacher | ##yesterday## |
And I log in as "teacher1"
And I follow "Course 1"
@ -21,6 +21,8 @@ Feature: Visiting reports
And I add a "Attendance" to section "1" and I fill the form with:
| Name | Attendance |
And I follow "Attendance"
And I follow "Add a block"
And I follow "Administration"
And I follow "Add session"
And I set the following fields to these values:
| id_sestime_starthour | 01 |
@ -99,7 +101,7 @@ Feature: Visiting reports
Scenario: Teacher take attendance of group session
Given the following "groups" exist:
| course | name | idnumber |
| C101 | Group1 | Group1 |
| C1 | Group1 | Group1 |
And the following "group members" exist:
| group | user |
| Group1 | student1 |
@ -136,8 +138,8 @@ Feature: Visiting reports
And I press "Save attendance"
When I follow "Report"
Then "Student 1" row "Points" column of "generaltable" table should contain "3 / 4"
And "Student 1" row "Percentage" column of "generaltable" table should contain "75.0%"
Then "3 / 4" "text" should exist in the "Student 1" "table_row"
And "75.0%" "text" should exist in the "Student 1" "table_row"
When I follow "Grades" in the user menu
And I follow "Course 1"
@ -181,11 +183,11 @@ Feature: Visiting reports
When I follow "Report"
And I click on "Summary" "link" in the "All" "table_row"
Then "Student 1" row "Total number of sessions" column of "generaltable" table should contain "3"
And "Student 1" row "Points over all sessions" column of "generaltable" table should contain "3 / 6"
And "Student 1" row "Percentage over all sessions" column of "generaltable" table should contain "50.0%"
And "Student 1" row "Maximum possible points" column of "generaltable" table should contain "5 / 6"
And "Student 1" row "Maximum possible percentage" column of "generaltable" table should contain "83.3%"
Then "3 / 6" "text" should exist in the "Student 1" "table_row"
And "50.0%" "text" should exist in the "Student 1" "table_row"
And "5 / 6" "text" should exist in the "Student 1" "table_row"
And "83.3%" "text" should exist in the "Student 1" "table_row"
And I log out
@ -194,7 +196,7 @@ Feature: Visiting reports
And I follow "Course 1"
And I follow "Attendance"
And I follow "Edit settings"
And I set the following fields to these values:
Then I set the following fields to these values:
| id_grade_modgrade_type | Point |
| id_grade_modgrade_point | 50 |
And I press "Save and display"

2
version.php

@ -23,7 +23,7 @@
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2016113001;
$plugin->version = 2016121300;
$plugin->requires = 2016111800;
$plugin->release = '3.2.2';
$plugin->maturity = MATURITY_STABLE;

Loading…
Cancel
Save