diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 150b03a..9bf0172 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,33 +1,11 @@
-name: Runtests
+name: Run all tests
# Run this workflow every time a new commit pushed to your repository
on: push
jobs:
- selftest:
- name: CI test (make validate)
- runs-on: ubuntu-18.04
-
- steps:
- - name: Check out repository code
- uses: actions/checkout@v2
-
- - name: Setup PHP 7.3
- uses: shivammathur/setup-php@v2
- with:
- php-version: 7.3
-
- - name: Initialise
- run: make init
-
- - name: Validate
- run: make validate
-
- citest:
- name: CI test
- needs: selftest
- runs-on: ubuntu-18.04
-
+ setup:
+ runs-on: ubuntu-latest
services:
postgres:
image: postgres:9.6
@@ -36,74 +14,70 @@ jobs:
POSTGRES_HOST_AUTH_METHOD: 'trust'
# Health check to wait for postgres to start.
ports:
- - 5432:5432
+ - 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3
-
+ mariadb:
+ image: mariadb:10
+ env:
+ MYSQL_USER: 'root'
+ MYSQL_ALLOW_EMPTY_PASSWORD: "true"
+ ports:
+ - 3306:3306
+ options: --health-cmd="mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 3
strategy:
fail-fast: false
matrix:
- include:
- - php: '7.4'
- moodle-branch: 'master'
- - php: '7.4'
- moodle-branch: 'MOODLE_311_STABLE'
- - php: '7.4'
- moodle-branch: 'MOODLE_310_STABLE'
- - php: '7.4'
- moodle-branch: 'MOODLE_39_STABLE'
- - php: '7.4'
-
+ php-versions: ['7.3', '7.4']
+ database: ['pgsql', 'mariadb']
steps:
- - name: Check out repository code
- uses: actions/checkout@v2
+ - name: Check out repository code
+ uses: actions/checkout@v2
+ with:
+ # Clone in plugin subdir, so we can setup CI in default directory.
+ path: plugin
- - name: Install node
- uses: actions/setup-node@v1
- with:
- node-version: '14.15.0'
+ - name: Install node
+ uses: actions/setup-node@v1
+ with:
+ # TODO: Check if we can support .nvmrc
+ node-version: '14.15.0'
- - name: Setup PHP ${{ matrix.php }}
- uses: shivammathur/setup-php@v2
- with:
- php-version: ${{ matrix.php }}
- extensions: pgsql, zip, gd, xmlrpc, soap
- coverage: none
+ - name: Setup PHP environment
+ uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php
+ with:
+ php-version: ${{ matrix.php-versions }}
+ extensions: mbstring, pgsql, mysqli
+ tools: phpunit
- - name: Initialise moodle-plugin-ci
- run: |
- make init
- cp -R tests/Fixture/moodle-local_travis ../moodle-local_travis
- echo $(cd bin; pwd) >> $GITHUB_PATH
- echo $(cd vendor/bin; pwd) >> $GITHUB_PATH
- echo "TRAVIS_BUILD_DIR="$(cd ../moodle-local_travis; pwd) >> $GITHUB_ENV
- # PHPUnit depends on en_AU.UTF-8 locale
- sudo locale-gen en_AU.UTF-8
- - name: Install moodle-plugin-ci
- run: moodle-plugin-ci install -vvv
- env:
- DB: 'pgsql'
- MOODLE_BRANCH: ${{ matrix.moodle-branch }}
- IGNORE_PATHS: 'ignore'
- IGNORE_NAMES: 'ignore_name.php'
- MUSTACHE_IGNORE_NAMES: 'broken.mustache'
+ - name: Deploy moodle-plugin-ci
+ run: |
+ composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^3
+ # Add dirs to $PATH
+ echo $(cd ci/bin; pwd) >> $GITHUB_PATH
+ echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH
+ # PHPUnit depends on en_AU.UTF-8 locale
+ sudo locale-gen en_AU.UTF-8
+ - name: Install moodle-plugin-ci
+ # Need explicit IP to stop mysql client fail on attempt to use unix socket.
+ run: moodle-plugin-ci install -vvv --plugin ./plugin --db-host=127.0.0.1
+ env:
+ DB: ${{ matrix.database }}
+ # TODO: Omitted MOODLE_BRANCH results in regex failure, investigate.
+ MOODLE_BRANCH: 'master'
- - name: Run Integration tests
- env:
- MOODLE_BRANCH: ${{ matrix.moodle-branch }}
- run: |
- make test-phpunit
- moodle-plugin-ci phplint
- moodle-plugin-ci phpcpd
- moodle-plugin-ci phpmd
- moodle-plugin-ci codechecker
- moodle-plugin-ci validate
- moodle-plugin-ci savepoints
- moodle-plugin-ci mustache
- moodle-plugin-ci grunt || [ \
- "$MOODLE_BRANCH" != 'master' -a \
- "$MOODLE_BRANCH" != 'MOODLE_310_STABLE' -a \
- "$MOODLE_BRANCH" != 'MOODLE_39_STABLE' ]
- moodle-plugin-ci phpdoc
- moodle-plugin-ci phpunit --coverage-text
- moodle-plugin-ci behat --profile default
- moodle-plugin-ci behat --profile chrome
+ - name: Run Integration tests
+ run: |
+ # Currently it stops if any command return non 0 exit status, needs a
+ # wrapper to collect exit statuses and list result and the end.
+ # For testing purposes at this stage, just assume each command succeeds.
+ moodle-plugin-ci phplint || true
+ moodle-plugin-ci phpcpd || true
+ moodle-plugin-ci phpmd || true
+ moodle-plugin-ci codechecker || true
+ moodle-plugin-ci validate || true
+ moodle-plugin-ci savepoints || true
+ moodle-plugin-ci mustache || true
+ moodle-plugin-ci grunt || true
+ moodle-plugin-ci phpdoc || true
+ moodle-plugin-ci phpunit || true
+ moodle-plugin-ci behat --profile chrome || true
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 8b5a809..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,51 +0,0 @@
-language: php
-
-addons:
- postgresql: "9.6"
-
-services:
- - mysql
- - postgresql
- - docker
-
-cache:
- directories:
- - $HOME/.composer/cache
- - $HOME/.npm
-
-php:
- - 7.2
- - 7.4
-
-env:
- global:
- - MOODLE_BRANCH=master
- - MUSTACHE_IGNORE_NAMES=mobile_teacher_form.mustache
- matrix:
- - DB=pgsql
- - DB=mysqli
-
-before_install:
- - phpenv config-rm xdebug.ini
- - nvm install 14.0.0
- - nvm use 14.0.0
- - cd ../..
- - composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^3
- - export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH"
-
-install:
- - moodle-plugin-ci install
- - docker run -d -p 127.0.0.1:4444:4444 --net=host --shm-size=2g -v $HOME/build/moodle:$HOME/build/moodle selenium/standalone-chrome:3
-
-script:
- - moodle-plugin-ci phplint
- - moodle-plugin-ci phpcpd
- - moodle-plugin-ci phpmd
- - moodle-plugin-ci codechecker
- - moodle-plugin-ci validate
- - moodle-plugin-ci savepoints
- - moodle-plugin-ci mustache
- - moodle-plugin-ci grunt
- - moodle-plugin-ci phpdoc
- - moodle-plugin-ci phpunit
- - moodle-plugin-ci behat --profile chrome
diff --git a/classes/event/session_report_updated.php b/classes/event/session_report_updated.php
new file mode 100644
index 0000000..1c649ec
--- /dev/null
+++ b/classes/event/session_report_updated.php
@@ -0,0 +1,60 @@
+.
+
+/**
+ * This file contains an event for when a student's attendance report is viewed.
+ *
+ * @package mod_attendance
+ * @copyright 2014 onwards Dan Marsden
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace mod_attendance\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Event for when a student's attendance report is updated.
+ *
+ * @property-read array $other {
+ * Extra information about event properties.
+ *
+ * string studentid Id of student whose attendances were updated.
+ * string mode Mode of the report updated.
+ * }
+ * @package mod_attendance
+ * @copyright 2013 onwards Dan Marsden
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class session_report_updated extends \mod_attendance\event\session_report_viewed {
+
+ /**
+ * Init method.
+ */
+ protected function init() {
+ $this->data['crud'] = 'u';
+ $this->data['edulevel'] = self::LEVEL_TEACHING;
+ // Objecttable and objectid can't be meaningfully specified.
+ }
+
+ /**
+ * Returns localised general event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return get_string('eventstudentattendancesessionsupdated', 'mod_attendance');
+ }
+}
diff --git a/classes/event/session_report_viewed.php b/classes/event/session_report_viewed.php
index ba3cf0a..c4946f1 100644
--- a/classes/event/session_report_viewed.php
+++ b/classes/event/session_report_viewed.php
@@ -55,7 +55,7 @@ class session_report_viewed extends \core\event\base {
* @return string
*/
public function get_description() {
- return 'User with id ' . $this->userid . ' viewed attendance sessions for student with id ' .
+ return 'User with id ' . $this->userid . ' ' . $this->action . ' attendance sessions for student with id ' .
$this->relateduserid;
}
@@ -74,12 +74,16 @@ class session_report_viewed extends \core\event\base {
* @return \moodle_url
*/
public function get_url() {
- // Mode is optional.
+ // Mode, groupby, sesscourses are optional.
$mode = empty($this->other['mode']) ? "" : $this->other['mode'];
+ $groupby = empty($this->other['groupby']) ? "" : $this->other['groupby'];
+ $sesscourses = empty($this->other['sesscourses']) ? "" : $this->other['sesscourses'];
return new \moodle_url('/mod/attendance/view.php', array('id' => $this->contextinstanceid,
'studentid' => $this->relateduserid,
'mode' => $mode,
'view' => $this->other['view'],
+ 'groupby' => $groupby,
+ 'sesscourses' => $sesscourses,
'curdate' => $this->other['curdate']));
}
@@ -89,7 +93,7 @@ class session_report_viewed extends \core\event\base {
* @return array of parameters to be passed to legacy add_to_log() function.
*/
protected function get_legacy_logdata() {
- return array($this->courseid, 'attendance', 'student sessions viewed', $this->get_url(),
+ return array($this->courseid, 'attendance', 'student sessions ' . $this->action, $this->get_url(),
'student id ' . $this->relateduserid, $this->contextinstanceid);
}
@@ -119,17 +123,17 @@ class session_report_viewed extends \core\event\base {
*/
protected function validate_data() {
if (!isset($this->relateduserid)) {
- throw new \coding_exception('The event mod_attendance\\event\\session_report_viewed must specify relateduserid.');
+ throw new \coding_exception('The event ' . $this->eventname . ' must specify relateduserid.');
}
// View params can be left out as defaults will be the same when log event is viewed as when
// it was stored.
// filter params are important, but stored in session so default effectively unknown,
// hence required here.
if (!isset($this->other['view'])) {
- throw new \coding_exception('The event mod_attendance\\event\\session_report_viewed must specify view.');
+ throw new \coding_exception('The event ' . $this->eventname . ' must specify view.');
}
if (!isset($this->other['curdate'])) {
- throw new \coding_exception('The event mod_attendance\\event\\session_report_viewed must specify curdate.');
+ throw new \coding_exception('The event ' . $this->eventname . ' must specify curdate.');
}
parent::validate_data();
}
diff --git a/classes/structure.php b/classes/structure.php
index a767318..c5d349f 100644
--- a/classes/structure.php
+++ b/classes/structure.php
@@ -114,7 +114,7 @@ class mod_attendance_structure {
* @param stdClass $dbrecord Attandance instance data from {attendance} table
* @param stdClass $cm Course module record as returned by {@see get_coursemodule_from_id()}
* @param stdClass $course Course record from {course} table
- * @param stdClass $context The context of the workshop instance
+ * @param stdClass $context The context of the attendance instance
* @param stdClass $pageparams
*/
public function __construct(stdClass $dbrecord, stdClass $cm, stdClass $course, stdClass $context=null, $pageparams=null) {
diff --git a/classes/view_page_params.php b/classes/view_page_params.php
index c0f98a7..fd5d696 100644
--- a/classes/view_page_params.php
+++ b/classes/view_page_params.php
@@ -37,12 +37,21 @@ class mod_attendance_view_page_params extends mod_attendance_page_with_filter_co
/** All courses */
const MODE_ALL_COURSES = 1;
+ /** All sessions */
+ const MODE_ALL_SESSIONS = 2;
+
/** @var int */
public $studentid;
/** @var string */
public $mode;
+ /** @var string */
+ public $groupby;
+
+ /** @var string */
+ public $sesscourses;
+
/**
* mod_attendance_view_page_params constructor.
*/
@@ -64,6 +73,12 @@ class mod_attendance_view_page_params extends mod_attendance_page_with_filter_co
if ($this->mode != self::MODE_THIS_COURSE) {
$params['mode'] = $this->mode;
}
+ if ($this->groupby != 'course') {
+ $params['groupby'] = $this->groupby;
+ }
+ if ($this->sesscourses != 'current') {
+ $params['sesscourses'] = $this->sesscourses;
+ }
return $params;
}
diff --git a/lang/en/attendance.php b/lang/en/attendance.php
index e7eea16..7a5b5ef 100644
--- a/lang/en/attendance.php
+++ b/lang/en/attendance.php
@@ -43,6 +43,7 @@ $string['all'] = 'All';
$string['allcourses'] = 'All courses';
$string['allpast'] = 'All past';
$string['allsessions'] = 'All sessions';
+$string['allsessionstotals'] = 'Totals for selected sessions';
$string['attendance:addinstance'] = 'Add a new attendance activity';
$string['attendance:canbelisted'] = 'Appears in the roster';
$string['attendance:changeattendances'] = 'Changing Attendances';
@@ -235,6 +236,7 @@ $string['eventsessionupdated'] = 'Session updated';
$string['eventstatusadded'] = 'Status added';
$string['eventstatusupdated'] = 'Status updated';
$string['eventstudentattendancesessionsviewed'] = 'Session report viewed';
+$string['eventstudentattendancesessionsupdated'] = 'Session report updated';
$string['eventtaken'] = 'Attendance taken';
$string['eventtakenbystudent'] = 'Attendance taken by student';
$string['export'] = 'Export';
@@ -250,6 +252,7 @@ $string['gridcolumns'] = 'Grid columns';
$string['group'] = 'Group';
$string['groups'] = 'Groups';
$string['groupsession'] = 'Group of students';
+$string['groupsessionsby'] = 'Group sessions by';
$string['hiddensessions'] = 'Hidden sessions';
$string['hiddensessions_help'] = 'Sessions are hidden if they are scheduled before the course start date.
@@ -332,6 +335,7 @@ $string['noabsentstatusset'] = 'The status set in use does not have a status to
$string['noattendanceusers'] = 'It is not possible to export any data as there are no students enrolled in the course.';
$string['noattforuser'] = 'No attendance records exist for the user';
$string['noautomark'] = 'Disabled';
+$string['nocapabilitytotakethisattendance'] = 'You tried to change the attendance of a session with the cmid: {$a} that you do not have permission to modify.';
$string['nodescription'] = 'Regular class session';
$string['noeventstoreset'] = 'There are no calendar events that require an update.';
$string['nogroups'] = 'You can\'t add group sessions. No groups exists in course.';
@@ -487,7 +491,12 @@ $string['sessionduplicate'] = 'A duplicate session exists for course: {$a->cours
$string['sessionexist'] = 'Session not added (already exists)!';
$string['sessiongenerated'] = 'One session was successfully generated';
$string['sessions'] = 'Sessions';
+$string['sessionsallcourses'] = 'All courses';
+$string['sessionsbyactivity'] = 'Attendance instance';
+$string['sessionsbycourse'] = 'Course';
+$string['sessionsbydate'] = 'Week';
$string['sessionscompleted'] = 'Taken sessions';
+$string['sessionscurrentcourses'] = 'Current courses';
$string['sessionsgenerated'] = '{$a} sessions were successfully generated';
$string['sessionsids'] = 'IDs of sessions: ';
$string['sessionsnotfound'] = 'There is no sessions in the selected timespan';
@@ -531,6 +540,7 @@ $string['statusset'] = 'Status set {$a}';
$string['statussetsettings'] = 'Status set';
$string['statusunselected'] = 'unselected';
$string['strftimedm'] = '%b %d';
+$string['strftimedmw'] = '%a %b %d';
$string['strftimedmy'] = '%d %b %Y';
$string['strftimedmyhm'] = '%d %b %Y %I.%M%p'; // Line added to allow multiple sessions in the same day.
$string['strftimedmyw'] = '%a %d %b %Y';
@@ -583,6 +593,7 @@ $string['thiscourse'] = 'This course';
$string['time'] = 'Time';
$string['timeahead'] = 'Multiple sessions that exceed one year cannot be created, please adjust the start and end dates.';
$string['to'] = 'to:';
+$string['todate'] = 'to date';
$string['triggered'] = 'First notified';
$string['tuseremail'] = 'Email';
$string['tusername'] = 'Full name';
@@ -616,5 +627,6 @@ $string['warnings'] = 'Warnings set';
$string['warningthreshold'] = 'Warning threshold';
$string['warningupdated'] = 'Updated warnings';
$string['week'] = 'week(s)';
+$string['weekcommencing'] = 'Week commencing';
$string['weeks'] = 'Weeks';
$string['youcantdo'] = 'You can\'t do anything';
\ No newline at end of file
diff --git a/locallib.php b/locallib.php
index c40cd53..7764bef 100644
--- a/locallib.php
+++ b/locallib.php
@@ -109,6 +109,93 @@ function attendance_get_setname($attid, $statusset, $includevalues = true) {
return $statusname;
}
+/**
+ * Get full filtered log.
+ * @param int $userid
+ * @param stdClass $pageparams
+ * @return array
+ */
+function attendance_get_user_sessions_log_full($userid, $pageparams) {
+ global $DB;
+ // All taken sessions (including previous groups).
+
+ $usercourses = enrol_get_users_courses($userid);
+ list($usql, $uparams) = $DB->get_in_or_equal(array_keys($usercourses), SQL_PARAMS_NAMED, 'cid0');
+
+ $coursesql = "(1 = 1)";
+ $courseparams = array();
+ $now = time();
+ if ($pageparams->sesscourses === 'current') {
+ $coursesql = "(c.startdate = 0 OR c.startdate <= :now1) AND (c.enddate = 0 OR c.enddate >= :now2)";
+ $courseparams = array(
+ 'now1' => $now,
+ 'now2' => $now,
+ );
+ }
+
+ $datesql = "(1 = 1)";
+ $dateparams = array();
+ if ($pageparams->startdate && $pageparams->enddate) {
+ $datesql = "ats.sessdate >= :sdate AND ats.sessdate < :edate";
+ $dateparams = array(
+ 'sdate' => $pageparams->startdate,
+ 'edate' => $pageparams->enddate,
+ );
+ }
+
+ if ($pageparams->groupby === 'date') {
+ $ordersql = "ats.sessdate ASC, c.fullname ASC, att.name ASC, att.id ASC";
+ } else {
+ $ordersql = "c.fullname ASC, att.name ASC, att.id ASC, ats.sessdate ASC";
+ }
+
+ // WHERE clause is important:
+ // gm.userid not null => get unmarked attendances for user's current groups
+ // ats.groupid 0 => get all sessions that are for all students enrolled in course
+ // al.id not null => get all marked sessions whether or not user currently still in group.
+ $sql = "SELECT ats.id, ats.groupid, ats.sessdate, ats.duration, ats.description, ats.statusset,
+ al.statusid, al.remarks, ats.studentscanmark, ats.autoassignstatus,
+ ats.preventsharedip, ats.preventsharediptime,
+ ats.attendanceid, att.name AS attname, att.course AS courseid, c.fullname AS cname
+ FROM {attendance_sessions} ats
+ JOIN {attendance} att
+ ON att.id = ats.attendanceid
+ JOIN {course} c
+ ON att.course = c.id
+ LEFT JOIN {attendance_log} al
+ ON ats.id = al.sessionid AND al.studentid = :uid
+ LEFT JOIN {groups_members} gm
+ ON (ats.groupid = gm.groupid AND gm.userid = :uid1)
+ WHERE (gm.userid IS NOT NULL OR ats.groupid = 0 OR al.id IS NOT NULL)
+ AND att.course $usql
+ AND $datesql
+ AND $coursesql
+ ORDER BY $ordersql";
+
+ $params = array(
+ 'uid' => $userid,
+ 'uid1' => $userid,
+ );
+ $params = array_merge($params, $uparams);
+ $params = array_merge($params, $dateparams);
+ $params = array_merge($params, $courseparams);
+ $sessions = $DB->get_records_sql($sql, $params);
+
+ foreach ($sessions as $sess) {
+ if (empty($sess->description)) {
+ $sess->description = get_string('nodescription', 'attendance');
+ } else {
+ $modinfo = get_fast_modinfo($sess->courseid);
+ $cmid = $modinfo->instances['attendance'][$sess->attendanceid]->get_course_module_record()->id;
+ $ctx = context_module::instance($cmid);
+ $sess->description = file_rewrite_pluginfile_urls($sess->description,
+ 'pluginfile.php', $ctx->id, 'mod_attendance', 'session', $sess->id);
+ }
+ }
+
+ return $sessions;
+}
+
/**
* Get users courses and the relevant attendances.
*
@@ -275,6 +362,54 @@ function attendance_update_users_grade($attendance, $userids=array()) {
return grade_update('mod/attendance', $course->id, 'mod', 'attendance', $attendance->id, 0, $grades);
}
+/**
+ * Update grades for specified users for specified attendance
+ *
+ * @param integer $attendanceid - the id of the attendance to update
+ * @param integer $grade - the value of the 'grade' property of the specified attendance
+ * @param array $userids - the userids of the users to be updated
+ */
+function attendance_update_users_grades_by_id($attendanceid, $grade, $userids) {
+ global $DB;
+
+ if (empty($grade)) {
+ return false;
+ }
+
+ list($course, $cm) = get_course_and_cm_from_instance($attendanceid, 'attendance');
+
+ $summary = new mod_attendance_summary($attendanceid, $userids);
+
+ if (empty($userids)) {
+ $context = context_module::instance($cm->id);
+ $userids = array_keys(get_enrolled_users($context, 'mod/attendance:canbelisted', 0, 'u.id'));
+ }
+
+ if ($grade < 0) {
+ $dbparams = array('id' => -($grade));
+ $scale = $DB->get_record('scale', $dbparams);
+ $scalearray = explode(',', $scale->scale);
+ $attendancegrade = count($scalearray);
+ } else {
+ $attendancegrade = $grade;
+ }
+
+ $grades = array();
+ foreach ($userids as $userid) {
+ $grades[$userid] = new stdClass();
+ $grades[$userid]->userid = $userid;
+
+ if ($summary->has_taken_sessions($userid)) {
+ $usersummary = $summary->get_taken_sessions_summary_for($userid);
+ $grades[$userid]->rawgrade = $usersummary->takensessionspercentage * $attendancegrade;
+ } else {
+ $grades[$userid]->rawgrade = null;
+ }
+ }
+
+ return grade_update('mod/attendance', $course->id, 'mod', 'attendance', $attendanceid, 0, $grades);
+}
+
/**
* Add an attendance status variable
*
diff --git a/renderables.php b/renderables.php
index 1f4fdab..3a5b9ca 100644
--- a/renderables.php
+++ b/renderables.php
@@ -486,6 +486,42 @@ class attendance_user_data implements renderable {
$this->sessionslog = $att->get_user_filtered_sessions_log_extended($userid);
$this->groups = groups_get_all_groups($att->course->id);
+ } else if ($this->pageparams->mode == mod_attendance_view_page_params::MODE_ALL_SESSIONS) {
+ $this->coursesatts = attendance_get_user_courses_attendances($userid);
+ $this->statuses = array();
+ $this->summaries = array();
+ $this->groups = array();
+
+ foreach ($this->coursesatts as $atid => $ca) {
+ // Check to make sure the user can view this cm.
+ $modinfo = get_fast_modinfo($ca->courseid);
+ if (!$modinfo->instances['attendance'][$ca->attid]->uservisible) {
+ unset($this->coursesatts[$atid]);
+ continue;
+ } else {
+ $this->coursesatts[$atid]->cmid = $modinfo->instances['attendance'][$ca->attid]->get_course_module_record()->id;
+ }
+ $this->statuses[$ca->attid] = attendance_get_statuses($ca->attid);
+ $this->summaries[$ca->attid] = new mod_attendance_summary($ca->attid, array($userid));
+
+ if (!array_key_exists($ca->courseid, $this->groups)) {
+ $this->groups[$ca->courseid] = groups_get_all_groups($ca->courseid);
+ }
+ }
+
+ if (!$mobile) {
+ $this->summary = new mod_attendance_summary($att->id, array($userid), $att->pageparams->startdate,
+ $att->pageparams->enddate);
+
+ $this->filtercontrols = new attendance_filter_controls($att);
+ }
+
+ $this->sessionslog = attendance_get_user_sessions_log_full($userid, $this->pageparams);
+
+ foreach ($this->sessionslog as $sessid => $sess) {
+ $this->sessionslog[$sessid]->cmid = $this->coursesatts[$sess->attendanceid]->cmid;
+ }
+
} else {
$this->coursesatts = attendance_get_user_courses_attendances($userid);
$this->statuses = array();
@@ -510,11 +546,131 @@ class attendance_user_data implements renderable {
}
/**
- * url helper.
+ * Url function
+ * @param array $params
+ * @param array $excludeparams
* @return moodle_url
*/
- public function url() {
- return new moodle_url($this->urlpath, $this->urlparams);
+ public function url($params=array(), $excludeparams=array()) {
+ $params = array_merge($this->urlparams, $params);
+
+ foreach ($excludeparams as $paramkey) {
+ unset($params[$paramkey]);
+ }
+
+ return new moodle_url($this->urlpath, $params);
+ }
+
+ /**
+ * Take multiple sessions attendance from form data.
+ *
+ * @param stdClass $formdata
+ */
+ public function take_sessions_from_form_data($formdata) {
+ global $DB, $USER;
+ // TODO: WARNING - $formdata is unclean - comes from direct $_POST - ideally needs a rewrite but we do some cleaning below.
+ // This whole function could do with a nice clean up.
+
+ $now = time();
+ $sesslog = array();
+ $formdata = (array)$formdata;
+ $updatedsessions = array();
+ $sessionatt = array();
+
+ foreach ($formdata as $key => $value) {
+ // Look at Remarks field because the user options may not be passed if empty.
+ if (substr($key, 0, 7) == 'remarks') {
+ $parts = explode('sess', substr($key, 7));
+ $stid = $parts[0];
+ if (!(is_numeric($stid))) { // Sanity check on $stid.
+ print_error('nonnumericid', 'attendance');
+ }
+ $sessid = $parts[1];
+ if (!(is_numeric($sessid))) { // Sanity check on $sessid.
+ print_error('nonnumericid', 'attendance');
+ }
+ $dbsession = $this->sessionslog[$sessid];
+
+ $context = context_module::instance($dbsession->cmid);
+ if (!has_capability('mod/attendance:takeattendances', $context)) {
+ // How do we tell user about this?
+ \core\notification::warning(get_string("nocapabilitytotakethisattendance", "attendance", $dbsession->cmid));
+ continue;
+ }
+
+ $formkey = 'user'.$stid.'sess'.$sessid;
+ $attid = $dbsession->attendanceid;
+ $statusset = array_filter($this->statuses[$attid],
+ function($x) use($dbsession) {
+ return $x->setnumber === $dbsession->statusset;
+ });
+ $sessionatt[$sessid] = $attid;
+ $formlog = new stdClass();
+ if (array_key_exists($formkey, $formdata) && is_numeric($formdata[$formkey])) {
+ $formlog->statusid = $formdata[$formkey];
+ }
+ $formlog->studentid = $stid; // We check is_numeric on this above.
+ $formlog->statusset = implode(',', array_keys($statusset));
+ $formlog->remarks = $value;
+ $formlog->sessionid = $sessid;
+ $formlog->timetaken = $now;
+ $formlog->takenby = $USER->id;
+
+ if (!array_key_exists($stid, $sesslog)) {
+ $sesslog[$stid] = array();
+ }
+ $sesslog[$stid][$sessid] = $formlog;
+ }
+ }
+
+ $updateatts = array();
+ foreach ($sesslog as $stid => $userlog) {
+ $dbstudlog = $DB->get_records('attendance_log', array('studentid' => $stid), '',
+ 'sessionid,statusid,remarks,id,statusset');
+ foreach ($userlog as $log) {
+ if (array_key_exists($log->sessionid, $dbstudlog)) {
+ $attid = $sessionatt[$log->sessionid];
+ // Check if anything important has changed before updating record.
+ // Don't update timetaken/takenby records if nothing has changed.
+ if ($dbstudlog[$log->sessionid]->remarks != $log->remarks ||
+ $dbstudlog[$log->sessionid]->statusid != $log->statusid ||
+ $dbstudlog[$log->sessionid]->statusset != $log->statusset) {
+
+ $log->id = $dbstudlog[$log->sessionid]->id;
+ $DB->update_record('attendance_log', $log);
+
+ $updatedsessions[$log->sessionid] = $log->sessionid;
+ if (!array_key_exists($attid, $updateatts)) {
+ $updateatts[$attid] = array();
+ }
+ array_push($updateatts[$attid], $log->studentid);
+ }
+ } else {
+ $DB->insert_record('attendance_log', $log, false);
+ $updatedsessions[$log->sessionid] = $log->sessionid;
+ if (!array_key_exists($attid, $updateatts)) {
+ $updateatts[$attid] = array();
+ }
+ array_push($updateatts[$attid], $log->studentid);
+ }
+ }
+ }
+
+ foreach ($updatedsessions as $sessionid) {
+ $session = $this->sessionslog[$sessionid];
+ $session->lasttaken = $now;
+ $session->lasttakenby = $USER->id;
+ $DB->update_record('attendance_sessions', $session);
+ }
+
+ if (!empty($updateatts)) {
+ $attendancegrade = $DB->get_records_list('attendance', 'id', array_keys($updateatts), '', 'id, grade');
+ foreach ($updateatts as $attid => $updateusers) {
+ if ($attendancegrade[$attid] != 0) {
+ attendance_update_users_grades_by_id($attid, $grade, $updateusers);
+ }
+ }
+ }
}
}
diff --git a/renderer.php b/renderer.php
index 1a19c86..00036de 100644
--- a/renderer.php
+++ b/renderer.php
@@ -56,21 +56,42 @@ class mod_attendance_renderer extends plugin_renderer_base {
* @return string html code
*/
protected function render_attendance_filter_controls(attendance_filter_controls $fcontrols) {
+ $classes = 'attfiltercontrols';
$filtertable = new html_table();
$filtertable->attributes['class'] = ' ';
$filtertable->width = '100%';
$filtertable->align = array('left', 'center', 'right', 'right');
- $filtertable->data[0][] = $this->render_sess_group_selector($fcontrols);
+ if (property_exists($fcontrols->pageparams, 'mode') &&
+ $fcontrols->pageparams->mode === mod_attendance_view_page_params::MODE_ALL_SESSIONS) {
+ $classes .= ' float-right';
- $filtertable->data[0][] = $this->render_curdate_controls($fcontrols);
+ $row = array();
+ $row[] = '';
+ $row[] = '';
+ $row[] = '';
+ $row[] = $this->render_grouping_controls($fcontrols);
+ $filtertable->data[] = $row;
- $filtertable->data[0][] = $this->render_paging_controls($fcontrols);
+ $row = array();
+ $row[] = '';
+ $row[] = '';
+ $row[] = '';
+ $row[] = $this->render_course_controls($fcontrols);
+ $filtertable->data[] = $row;
+ }
+
+ $row = array();
+
+ $row[] = $this->render_sess_group_selector($fcontrols);
+ $row[] = $this->render_curdate_controls($fcontrols);
+ $row[] = $this->render_paging_controls($fcontrols);
+ $row[] = $this->render_view_controls($fcontrols);
- $filtertable->data[0][] = $this->render_view_controls($fcontrols);
+ $filtertable->data[] = $row;
$o = html_writer::table($filtertable);
- $o = $this->output->container($o, 'attfiltercontrols');
+ $o = $this->output->container($o, $classes);
return $o;
}
@@ -198,6 +219,59 @@ class mod_attendance_renderer extends plugin_renderer_base {
return $curdatecontrols;
}
+ /**
+ * Render grouping controls (for all sessions report).
+ *
+ * @param attendance_filter_controls $fcontrols
+ * @return string
+ */
+ protected function render_grouping_controls(attendance_filter_controls $fcontrols) {
+ if ($fcontrols->pageparams->mode === mod_attendance_view_page_params::MODE_ALL_SESSIONS) {
+ $groupoptions = array(
+ 'date' => get_string('sessionsbydate', 'attendance'),
+ 'activity' => get_string('sessionsbyactivity', 'attendance'),
+ 'course' => get_string('sessionsbycourse', 'attendance')
+ );
+ $groupcontrols = get_string('groupsessionsby', 'attendance') . ":";
+ foreach ($groupoptions as $key => $opttext) {
+ if ($key != $fcontrols->pageparams->groupby) {
+ $link = html_writer::link($fcontrols->url(array('groupby' => $key)), $opttext);
+ $groupcontrols .= html_writer::tag('span', $link, array('class' => 'attbtn'));
+ } else {
+ $groupcontrols .= html_writer::tag('span', $opttext, array('class' => 'attcurbtn'));
+ }
+ }
+ return html_writer::tag('nobr', $groupcontrols);
+ }
+ return "";
+ }
+
+ /**
+ * Render course controls (for all sessions report).
+ *
+ * @param attendance_filter_controls $fcontrols
+ * @return string
+ */
+ protected function render_course_controls(attendance_filter_controls $fcontrols) {
+ if ($fcontrols->pageparams->mode === mod_attendance_view_page_params::MODE_ALL_SESSIONS) {
+ $courseoptions = array(
+ 'all' => get_string('sessionsallcourses', 'attendance'),
+ 'current' => get_string('sessionscurrentcourses', 'attendance')
+ );
+ $coursecontrols = "";
+ foreach ($courseoptions as $key => $opttext) {
+ if ($key != $fcontrols->pageparams->sesscourses) {
+ $link = html_writer::link($fcontrols->url(array('sesscourses' => $key)), $opttext);
+ $coursecontrols .= html_writer::tag('span', $link, array('class' => 'attbtn'));
+ } else {
+ $coursecontrols .= html_writer::tag('span', $opttext, array('class' => 'attcurbtn'));
+ }
+ }
+ return html_writer::tag('nobr', $coursecontrols);
+ }
+ return "";
+ }
+
/**
* Render view controls.
*
@@ -926,6 +1000,72 @@ class mod_attendance_renderer extends plugin_renderer_base {
return $celldata;
}
+ /**
+ * Construct take session controls.
+ *
+ * @param attendance_take_data $takedata
+ * @param stdClass $user
+ * @return array
+ */
+ private function construct_take_session_controls(attendance_take_data $takedata, $user) {
+ $celldata = array();
+ $celldata['remarks'] = '';
+ if ($user->enrolmentend and $user->enrolmentend < $takedata->sessioninfo->sessdate) {
+ $celldata['text'] = get_string('enrolmentend', 'attendance', userdate($user->enrolmentend, '%d.%m.%Y'));
+ $celldata['colspan'] = count($takedata->statuses) + 1;
+ $celldata['class'] = 'userwithoutenrol';
+ } else if (!$user->enrolmentend and $user->enrolmentstatus == ENROL_USER_SUSPENDED) {
+ // No enrolmentend and ENROL_USER_SUSPENDED.
+ $celldata['text'] = get_string('enrolmentsuspended', 'attendance');
+ $celldata['colspan'] = count($takedata->statuses) + 1;
+ $celldata['class'] = 'userwithoutenrol';
+ } else {
+ if ($takedata->updatemode and !array_key_exists($user->id, $takedata->sessionlog)) {
+ $celldata['class'] = 'userwithoutdata';
+ }
+
+ $celldata['text'] = array();
+ foreach ($takedata->statuses as $st) {
+ $params = array(
+ 'type' => 'radio',
+ 'name' => 'user'.$user->id.'sess'.$takedata->sessioninfo->id,
+ 'class' => 'st'.$st->id,
+ 'value' => $st->id);
+ if (array_key_exists($user->id, $takedata->sessionlog) and $st->id == $takedata->sessionlog[$user->id]->statusid) {
+ $params['checked'] = '';
+ }
+
+ $input = html_writer::empty_tag('input', $params);
+
+ if ($takedata->pageparams->viewmode == mod_attendance_take_page_params::SORTED_GRID) {
+ $input = html_writer::tag('nobr', $input . $st->acronym);
+ }
+
+ $celldata['text'][] = $input;
+ }
+ $params = array(
+ 'type' => 'text',
+ 'name' => 'remarks'.$user->id.'sess'.$takedata->sessioninfo->id,
+ 'maxlength' => 255);
+ if (array_key_exists($user->id, $takedata->sessionlog)) {
+ $params['value'] = $takedata->sessionlog[$user->id]->remarks;
+ }
+ $input = html_writer::empty_tag('input', $params);
+ if ($takedata->pageparams->viewmode == mod_attendance_take_page_params::SORTED_GRID) {
+ $input = html_writer::empty_tag('br').$input;
+ }
+ $celldata['remarks'] = $input;
+
+ if ($user->enrolmentstart > $takedata->sessioninfo->sessdate + $takedata->sessioninfo->duration) {
+ $celldata['warning'] = get_string('enrolmentstart', 'attendance',
+ userdate($user->enrolmentstart, '%H:%M %d.%m.%Y'));
+ $celldata['class'] = 'userwithoutenrol';
+ }
+ }
+
+ return $celldata;
+ }
+
/**
* Render header.
*
@@ -960,7 +1100,8 @@ class mod_attendance_renderer extends plugin_renderer_base {
$o = $this->render_user_report_tabs($userdata);
- if ($USER->id == $userdata->user->id) {
+ if ($USER->id == $userdata->user->id ||
+ $userdata->pageparams->mode === mod_attendance_view_page_params::MODE_ALL_SESSIONS) {
$o .= $this->construct_user_data($userdata);
@@ -993,11 +1134,14 @@ class mod_attendance_renderer extends plugin_renderer_base {
$userdata->url()->out(true, array('mode' => mod_attendance_view_page_params::MODE_THIS_COURSE)),
get_string('thiscourse', 'attendance'));
- // Skip the 'all courses' tab for 'temporary' users.
+ // Skip the 'all courses' and 'all sessions' tabs for 'temporary' users.
if ($userdata->user->type == 'standard') {
$tabs[] = new tabobject(mod_attendance_view_page_params::MODE_ALL_COURSES,
$userdata->url()->out(true, array('mode' => mod_attendance_view_page_params::MODE_ALL_COURSES)),
get_string('allcourses', 'attendance'));
+ $tabs[] = new tabobject(mod_attendance_view_page_params::MODE_ALL_SESSIONS,
+ $userdata->url()->out(true, array('mode' => mod_attendance_view_page_params::MODE_ALL_SESSIONS)),
+ get_string('allsessions', 'attendance'));
}
return print_tabs(array($tabs), $userdata->pageparams->mode, null, null, true);
@@ -1022,6 +1166,22 @@ class mod_attendance_renderer extends plugin_renderer_base {
$o .= html_writer::empty_tag('hr');
$o .= construct_user_data_stat($userdata->summary->get_all_sessions_summary_for($userdata->user->id),
$userdata->pageparams->view);
+ } else if ($userdata->pageparams->mode == mod_attendance_view_page_params::MODE_ALL_SESSIONS) {
+ $allsessions = $this->construct_user_allsessions_log($userdata);
+ $o .= html_writer::start_div('allsessionssummary');
+ $o .= html_writer::start_div('float-left');
+ $o .= html_writer::start_div('float-left');
+ $o .= $this->user_picture($userdata->user, array('size' => 100, 'class' => 'userpicture float-left'));
+ $o .= html_writer::end_div();
+ $o .= html_writer::start_div('float-right');
+ $o .= $allsessions->summary;
+ $o .= html_writer::end_div();
+ $o .= html_writer::end_div();
+ $o .= html_writer::start_div('float-right');
+ $o .= $this->render_attendance_filter_controls($userdata->filtercontrols);
+ $o .= html_writer::end_div();
+ $o .= html_writer::end_div();
+ $o .= $allsessions->detail;
} else {
$table = new html_table();
$table->head = array(get_string('course'),
@@ -1226,6 +1386,658 @@ class mod_attendance_renderer extends plugin_renderer_base {
return html_writer::table($table);
}
+ /**
+ * Construct table showing all sessions, not limited to current course.
+ *
+ * @param attendance_user_data $userdata
+ * @return string
+ */
+ private function construct_user_allsessions_log(attendance_user_data $userdata) {
+ global $USER;
+
+ $allsessions = new stdClass();
+
+ $shortform = false;
+ if ($USER->id == $userdata->user->id) {
+ // This is a user viewing their own stuff - hide non-relevant columns.
+ $shortform = true;
+ }
+
+ $groupby = $userdata->pageparams->groupby;
+
+ $table = new html_table();
+ $table->attributes['class'] = 'generaltable attwidth boxaligncenter allsessions';
+ $table->head = array();
+ $table->align = array();
+ $table->size = array();
+ $table->colclasses = array();
+ $colcount = 0;
+ $summarywidth = 0;
+
+ // If grouping by date, we need some form of date up front.
+ // Only need course column if we are not using course to group
+ // (currently date is only option which does not use course).
+ if ($groupby === 'date') {
+ $table->head[] = '';
+ $table->align[] = 'left';
+ $table->colclasses[] = 'grouper';
+ $table->size[] = '1px';
+
+ $table->head[] = get_string('date');
+ $table->align[] = 'left';
+ $table->colclasses[] = 'datecol';
+ $table->size[] = '1px';
+ $colcount++;
+
+ $table->head[] = get_string('course');
+ $table->align[] = 'left';
+ $table->colclasses[] = 'colcourse';
+ $colcount++;
+ } else {
+ $table->head[] = '';
+ $table->align[] = 'left';
+ $table->colclasses[] = 'grouper';
+ $table->size[] = '1px';
+ if ($groupby === 'activity') {
+ $table->head[] = '';
+ $table->align[] = 'left';
+ $table->colclasses[] = 'grouper';
+ $table->size[] = '1px';
+ }
+ }
+
+ // Need activity column unless we are using activity to group.
+ if ($groupby !== 'activity') {
+ $table->head[] = get_string('pluginname', 'mod_attendance');
+ $table->align[] = 'left';
+ $table->colclasses[] = 'colcourse';
+ $table->size[] = '*';
+ $colcount++;
+ }
+
+ // If grouping by date, it belongs up front rather than here.
+ if ($groupby !== 'date') {
+ $table->head[] = get_string('date');
+ $table->align[] = 'left';
+ $table->colclasses[] = 'datecol';
+ $table->size[] = '1px';
+ $colcount++;
+ }
+
+ // Use "session" instead of "description".
+ $table->head[] = get_string('session', 'attendance');
+ $table->align[] = 'left';
+ $table->colclasses[] = 'desccol';
+ $table->size[] = '*';
+ $colcount++;
+
+ if (!$shortform) {
+ $table->head[] = get_string('sessiontypeshort', 'attendance');
+ $table->align[] = '';
+ $table->size[] = '*';
+ $table->colclasses[] = '';
+ $colcount++;
+ }
+
+ if (!empty($USER->attendanceediting)) {
+ $table->head[] = get_string('status', 'attendance');
+ $table->align[] = 'center';
+ $table->colclasses[] = 'statuscol';
+ $table->size[] = '*';
+ $colcount++;
+ $summarywidth++;
+
+ $table->head[] = get_string('remarks', 'attendance');
+ $table->align[] = 'center';
+ $table->colclasses[] = 'remarkscol';
+ $table->size[] = '*';
+ $colcount++;
+ $summarywidth++;
+ } else {
+ $table->head[] = get_string('status', 'attendance');
+ $table->align[] = 'center';
+ $table->colclasses[] = 'statuscol';
+ $table->size[] = '*';
+ $colcount++;
+ $summarywidth++;
+
+ $table->head[] = get_string('points', 'attendance');
+ $table->align[] = 'center';
+ $table->colclasses[] = 'pointscol';
+ $table->size[] = '1px';
+ $colcount++;
+ $summarywidth++;
+
+ $table->head[] = get_string('remarks', 'attendance');
+ $table->align[] = 'center';
+ $table->colclasses[] = 'remarkscol';
+ $table->size[] = '*';
+ $colcount++;
+ $summarywidth++;
+ }
+
+ $statusmaxpoints = array();
+ foreach ($userdata->statuses as $attid => $attstatuses) {
+ $statusmaxpoints[$attid] = attendance_get_statusset_maxpoints($attstatuses);
+ }
+
+ $lastgroup = array(null, null);
+ $groups = array();
+ $stats = array(
+ 'course' => array(),
+ 'activity' => array(),
+ 'date' => array(),
+ 'overall' => array(
+ 'points' => 0,
+ 'maxpointstodate' => 0,
+ 'maxpoints' => 0,
+ 'pcpointstodate' => null,
+ 'pcpoints' => null,
+ 'statuses' => array()
+ )
+ );
+ $group = null;
+ if ($userdata->sessionslog) {
+ foreach ($userdata->sessionslog as $sess) {
+ if ($groupby === 'date') {
+ $weekformat = date("YW", $sess->sessdate);
+ if ($weekformat != $lastgroup[0]) {
+ if ($group !== null) {
+ array_push($groups, $group);
+ }
+ $group = array();
+ $lastgroup[0] = $weekformat;
+ }
+ if (!array_key_exists($weekformat, $stats['date'])) {
+ $stats['date'][$weekformat] = array(
+ 'points' => 0,
+ 'maxpointstodate' => 0,
+ 'maxpoints' => 0,
+ 'pcpointstodate' => null,
+ 'pcpoints' => null,
+ 'statuses' => array()
+ );
+ }
+ $statussetmaxpoints = $statusmaxpoints[$sess->attendanceid];
+ // Ensure all possible acronyms for current sess's statusset are available as
+ // keys in status array for period.
+ //
+ // A bit yucky because we can't tell whether we've seen statusset before, and
+ // we usually will have, so much wasted spinning.
+ foreach ($userdata->statuses[$sess->attendanceid] as $attstatus) {
+ if ($attstatus->setnumber === $sess->statusset) {
+ if (!array_key_exists($attstatus->acronym, $stats['date'][$weekformat]['statuses'])) {
+ $stats['date'][$weekformat]['statuses'][$attstatus->acronym] =
+ array('count' => 0, 'description' => $attstatus->description);
+ }
+ if (!array_key_exists($attstatus->acronym, $stats['overall']['statuses'])) {
+ $stats['overall']['statuses'][$attstatus->acronym] =
+ array('count' => 0, 'description' => $attstatus->description);
+ }
+ }
+ }
+ // The array_key_exists check is for hidden statuses.
+ if (isset($sess->statusid) && array_key_exists($sess->statusid, $userdata->statuses[$sess->attendanceid])) {
+ $status = $userdata->statuses[$sess->attendanceid][$sess->statusid];
+ $stats['date'][$weekformat]['statuses'][$status->acronym]['count']++;
+ $stats['date'][$weekformat]['points'] += $status->grade;
+ $stats['date'][$weekformat]['maxpointstodate'] += $statussetmaxpoints[$sess->statusset];
+ $stats['overall']['statuses'][$status->acronym]['count']++;
+ $stats['overall']['points'] += $status->grade;
+ $stats['overall']['maxpointstodate'] += $statussetmaxpoints[$sess->statusset];
+ }
+ $stats['date'][$weekformat]['maxpoints'] += $statussetmaxpoints[$sess->statusset];
+ $stats['overall']['maxpoints'] += $statussetmaxpoints[$sess->statusset];
+ } else {
+ // By course and perhaps activity.
+ if (
+ ($sess->courseid != $lastgroup[0]) ||
+ ($groupby === 'activity' && $sess->cmid != $lastgroup[1])
+ ) {
+ if ($group !== null) {
+ array_push($groups, $group);
+ }
+ $group = array();
+ $lastgroup[0] = $sess->courseid;
+ $lastgroup[1] = $sess->cmid;
+ }
+ if (!array_key_exists($sess->courseid, $stats['course'])) {
+ $stats['course'][$sess->courseid] = array(
+ 'points' => 0,
+ 'maxpointstodate' => 0,
+ 'maxpoints' => 0,
+ 'pcpointstodate' => null,
+ 'pcpoints' => null,
+ 'statuses' => array()
+ );
+ }
+ $statussetmaxpoints = $statusmaxpoints[$sess->attendanceid];
+ // Ensure all possible acronyms for current sess's statusset are available as
+ // keys in status array for course
+ //
+ // A bit yucky because we can't tell whether we've seen statusset before, and
+ // we usually will have, so much wasted spinning.
+ foreach ($userdata->statuses[$sess->attendanceid] as $attstatus) {
+ if ($attstatus->setnumber === $sess->statusset) {
+ if (!array_key_exists($attstatus->acronym, $stats['course'][$sess->courseid]['statuses'])) {
+ $stats['course'][$sess->courseid]['statuses'][$attstatus->acronym] =
+ array('count' => 0, 'description' => $attstatus->description);
+ }
+ if (!array_key_exists($attstatus->acronym, $stats['overall']['statuses'])) {
+ $stats['overall']['statuses'][$attstatus->acronym] =
+ array('count' => 0, 'description' => $attstatus->description);
+ }
+ }
+ }
+ // The array_key_exists check is for hidden statuses.
+ if (isset($sess->statusid) && array_key_exists($sess->statusid, $userdata->statuses[$sess->attendanceid])) {
+ $status = $userdata->statuses[$sess->attendanceid][$sess->statusid];
+ $stats['course'][$sess->courseid]['statuses'][$status->acronym]['count']++;
+ $stats['course'][$sess->courseid]['points'] += $status->grade;
+ $stats['course'][$sess->courseid]['maxpointstodate'] += $statussetmaxpoints[$sess->statusset];
+ $stats['overall']['statuses'][$status->acronym]['count']++;
+ $stats['overall']['points'] += $status->grade;
+ $stats['overall']['maxpointstodate'] += $statussetmaxpoints[$sess->statusset];
+ }
+ $stats['course'][$sess->courseid]['maxpoints'] += $statussetmaxpoints[$sess->statusset];
+ $stats['overall']['maxpoints'] += $statussetmaxpoints[$sess->statusset];
+
+ if (!array_key_exists($sess->cmid, $stats['activity'])) {
+ $stats['activity'][$sess->cmid] = array(
+ 'points' => 0,
+ 'maxpointstodate' => 0,
+ 'maxpoints' => 0,
+ 'pcpointstodate' => null,
+ 'pcpoints' => null,
+ 'statuses' => array()
+ );
+ }
+ $statussetmaxpoints = $statusmaxpoints[$sess->attendanceid];
+ // Ensure all possible acronyms for current sess's statusset are available as
+ // keys in status array for period
+ //
+ // A bit yucky because we can't tell whether we've seen statusset before, and
+ // we usually will have, so much wasted spinning.
+ foreach ($userdata->statuses[$sess->attendanceid] as $attstatus) {
+ if ($attstatus->setnumber === $sess->statusset) {
+ if (!array_key_exists($attstatus->acronym, $stats['activity'][$sess->cmid]['statuses'])) {
+ $stats['activity'][$sess->cmid]['statuses'][$attstatus->acronym] =
+ array('count' => 0, 'description' => $attstatus->description);
+ }
+ if (!array_key_exists($attstatus->acronym, $stats['overall']['statuses'])) {
+ $stats['overall']['statuses'][$attstatus->acronym] =
+ array('count' => 0, 'description' => $attstatus->description);
+ }
+ }
+ }
+ // The array_key_exists check is for hidden statuses.
+ if (isset($sess->statusid) && array_key_exists($sess->statusid, $userdata->statuses[$sess->attendanceid])) {
+ $status = $userdata->statuses[$sess->attendanceid][$sess->statusid];
+ $stats['activity'][$sess->cmid]['statuses'][$status->acronym]['count']++;
+ $stats['activity'][$sess->cmid]['points'] += $status->grade;
+ $stats['activity'][$sess->cmid]['maxpointstodate'] += $statussetmaxpoints[$sess->statusset];
+ $stats['overall']['statuses'][$status->acronym]['count']++;
+ $stats['overall']['points'] += $status->grade;
+ $stats['overall']['maxpointstodate'] += $statussetmaxpoints[$sess->statusset];
+ }
+ $stats['activity'][$sess->cmid]['maxpoints'] += $statussetmaxpoints[$sess->statusset];
+ $stats['overall']['maxpoints'] += $statussetmaxpoints[$sess->statusset];
+ }
+ array_push($group, $sess);
+ }
+ array_push($groups, $group);
+ }
+
+ $points = $stats['overall']['points'];
+ $maxpoints = $stats['overall']['maxpointstodate'];
+ $summarytable = new html_table();
+ $summarytable->attributes['class'] = 'generaltable table-bordered table-condensed';
+ $row = new html_table_row();
+ $cell = new html_table_cell(get_string('allsessionstotals', 'attendance'));
+ $cell->colspan = 2;
+ $cell->header = true;
+ $row->cells[] = $cell;
+ $summarytable->data[] = $row;
+ foreach ($stats['overall']['statuses'] as $acronym => $status) {
+ $row = new html_table_row();
+ $row->cells[] = $status['description'] . ":";
+ $row->cells[] = $status['count'];
+ $summarytable->data[] = $row;
+ }
+
+ $row = new html_table_row();
+ if ($maxpoints !== 0) {
+ $pctodate = format_float( $points * 100 / $maxpoints);
+ $pointsinfo = get_string('points', 'attendance') . ": " . $points . "/" . $maxpoints;
+ $pointsinfo .= " (" . $pctodate . "%)";
+ } else {
+ $pointsinfo = get_string('points', 'attendance') . ": " . $points . "/" . $maxpoints;
+ }
+ $pointsinfo .= " " . get_string('todate', 'attendance');
+ $cell = new html_table_cell($pointsinfo);
+ $cell->colspan = 2;
+ $row->cells[] = $cell;
+ $summarytable->data[] = $row;
+ $allsessions->summary = html_writer::table($summarytable);
+
+ $lastgroup = array(null, null);
+ foreach ($groups as $group) {
+
+ $statussetmaxpoints = $statusmaxpoints[$sess->attendanceid];
+
+ // For use in headings etc.
+ $sess = $group[0];
+
+ if ($groupby === 'date') {
+ $row = new html_table_row();
+ $row->attributes['class'] = 'grouper';
+ $cell = new html_table_cell();
+ $cell->rowspan = count($group) + 2;
+ $row->cells[] = $cell;
+ $week = date("W", $sess->sessdate);
+ $year = date("Y", $sess->sessdate);
+ // ISO week starts on day 1, Monday.
+ $weekstart = date_timestamp_get(date_isodate_set(date_create(), $year, $week, 1));
+ $dmywformat = get_string('strftimedmyw', 'attendance');
+ $cell = new html_table_cell(get_string('weekcommencing', 'attendance') . ": " . userdate($weekstart, $dmywformat));
+ $cell->colspan = $colcount - $summarywidth;
+ $cell->rowspan = 2;
+ $cell->attributes['class'] = 'groupheading';
+ $row->cells[] = $cell;
+ $weekformat = date("YW", $sess->sessdate);
+ $points = $stats['date'][$weekformat]['points'];
+ $maxpoints = $stats['date'][$weekformat]['maxpointstodate'];
+ if ($maxpoints !== 0) {
+ $pctodate = format_float( $points * 100 / $maxpoints);
+ $summary = get_string('points', 'attendance') . ": " . $points . "/" . $maxpoints;
+ $summary .= " (" . $pctodate . "%)";
+ } else {
+ $summary = get_string('points', 'attendance') . ": " . $points . "/" . $maxpoints;
+ }
+ $summary .= " " . get_string('todate', 'attendance');
+ $cell = new html_table_cell($summary);
+ $cell->colspan = $summarywidth;
+ $row->cells[] = $cell;
+ $table->data[] = $row;
+ $row = new html_table_row();
+ $row->attributes['class'] = 'grouper';
+ $summary = array();
+ foreach ($stats['date'][$weekformat]['statuses'] as $acronym => $status) {
+ array_push($summary, html_writer::tag('b', $acronym) . $status['count']);
+ }
+ $cell = new html_table_cell(implode(" ", $summary));
+ $cell->colspan = $summarywidth;
+ $row->cells[] = $cell;
+ $table->data[] = $row;
+ $lastgroup[0] = date("YW", $weekstart);
+ } else {
+ if ($groupby === 'course' || $sess->courseid !== $lastgroup[0]) {
+ $row = new html_table_row();
+ $row->attributes['class'] = 'grouper';
+ $cell = new html_table_cell();
+ $cell->rowspan = count($group) + 2;
+ if ($groupby === 'activity') {
+ $headcell = $cell; // Keep ref to be able to adjust rowspan later.
+ $cell->rowspan += 2;
+ $row->cells[] = $cell;
+ $cell = new html_table_cell();
+ $cell->rowspan = 2;
+ }
+ $row->cells[] = $cell;
+ $courseurl = new moodle_url('/course/view.php', array('id' => $sess->courseid));
+ $cell = new html_table_cell(get_string('course', 'attendance') . ": " .
+ html_writer::link($courseurl, $sess->cname));
+ $cell->colspan = $colcount - $summarywidth;
+ $cell->rowspan = 2;
+ $cell->attributes['class'] = 'groupheading';
+ $row->cells[] = $cell;
+ $points = $stats['course'][$sess->courseid]['points'];
+ $maxpoints = $stats['course'][$sess->courseid]['maxpointstodate'];
+ if ($maxpoints !== 0) {
+ $pctodate = format_float( $points * 100 / $maxpoints);
+ $summary = get_string('points', 'attendance') . ": " . $points . "/" . $maxpoints;
+ $summary .= " (" . $pctodate . "%)";
+ } else {
+ $summary = get_string('points', 'attendance') . ": " . $points . "/" . $maxpoints;
+ }
+ $summary .= " " . get_string('todate', 'attendance');
+ $cell = new html_table_cell($summary);
+ $cell->colspan = $summarywidth;
+ $row->cells[] = $cell;
+ $table->data[] = $row;
+ $row = new html_table_row();
+ $row->attributes['class'] = 'grouper';
+ $summary = array();
+ foreach ($stats['course'][$sess->courseid]['statuses'] as $acronym => $status) {
+ array_push($summary, html_writer::tag('b', $acronym) . $status['count']);
+ }
+ $cell = new html_table_cell(implode(" ", $summary));
+ $cell->colspan = $summarywidth;
+ $row->cells[] = $cell;
+ $table->data[] = $row;
+ }
+ if ($groupby === 'activity') {
+ if ($sess->courseid === $lastgroup[0]) {
+ $headcell->rowspan += count($group) + 2;
+ }
+ $row = new html_table_row();
+ $row->attributes['class'] = 'grouper';
+ $cell = new html_table_cell();
+ $cell->rowspan = count($group) + 2;
+ $row->cells[] = $cell;
+ $attendanceurl = new moodle_url('/mod/attendance/view.php', array('id' => $sess->cmid,
+ 'studentid' => $userdata->user->id,
+ 'view' => ATT_VIEW_ALL));
+ $cell = new html_table_cell(get_string('pluginname', 'mod_attendance') .
+ ": " . html_writer::link($attendanceurl, $sess->attname));
+ $cell->colspan = $colcount - $summarywidth;
+ $cell->rowspan = 2;
+ $cell->attributes['class'] = 'groupheading';
+ $row->cells[] = $cell;
+ $points = $stats['activity'][$sess->cmid]['points'];
+ $maxpoints = $stats['activity'][$sess->cmid]['maxpointstodate'];
+ if ($maxpoints !== 0) {
+ $pctodate = format_float( $points * 100 / $maxpoints);
+ $summary = get_string('points', 'attendance') . ": " . $points . "/" . $maxpoints;
+ $summary .= " (" . $pctodate . "%)";
+ } else {
+ $summary = get_string('points', 'attendance') . ": " . $points . "/" . $maxpoints;
+ }
+ $summary .= " " . get_string('todate', 'attendance');
+ $cell = new html_table_cell($summary);
+ $cell->colspan = $summarywidth;
+ $row->cells[] = $cell;
+ $table->data[] = $row;
+ $row = new html_table_row();
+ $row->attributes['class'] = 'grouper';
+ $summary = array();
+ foreach ($stats['activity'][$sess->cmid]['statuses'] as $acronym => $status) {
+ array_push($summary, html_writer::tag('b', $acronym) . $status['count']);
+ }
+ $cell = new html_table_cell(implode(" ", $summary));
+ $cell->colspan = $summarywidth;
+ $row->cells[] = $cell;
+ $table->data[] = $row;
+ }
+ $lastgroup[0] = $sess->courseid;
+ $lastgroup[1] = $sess->cmid;
+ }
+
+ // Now iterate over sessions in group...
+
+ foreach ($group as $sess) {
+ $row = new html_table_row();
+
+ // If grouping by date, we need some form of date up front.
+ // Only need course column if we are not using course to group
+ // (currently date is only option which does not use course).
+ if ($groupby === 'date') {
+ // What part of date do we want if grouped by it already?
+ $row->cells[] = userdate($sess->sessdate, get_string('strftimedmw', 'attendance')) .
+ " ". $this->construct_time($sess->sessdate, $sess->duration);
+
+ $courseurl = new moodle_url('/course/view.php', array('id' => $sess->courseid));
+ $row->cells[] = html_writer::link($courseurl, $sess->cname);
+ }
+
+ // Need activity column unless we are using activity to group.
+ if ($groupby !== 'activity') {
+ $attendanceurl = new moodle_url('/mod/attendance/view.php', array('id' => $sess->cmid,
+ 'studentid' => $userdata->user->id,
+ 'view' => ATT_VIEW_ALL));
+ $row->cells[] = html_writer::link($attendanceurl, $sess->attname);
+ }
+
+ // If grouping by date, it belongs up front rather than here.
+ if ($groupby !== 'date') {
+ $row->cells[] = userdate($sess->sessdate, get_string('strftimedmyw', 'attendance')) .
+ " ". $this->construct_time($sess->sessdate, $sess->duration);
+ }
+
+ $sesscontext = context_module::instance($sess->cmid);
+ if (has_capability('mod/attendance:takeattendances', $sesscontext)) {
+ $sessionurl = new moodle_url('/mod/attendance/take.php', array('id' => $sess->cmid,
+ 'sessionid' => $sess->id,
+ 'grouptype' => $sess->groupid));
+ $description = html_writer::link($sessionurl, $sess->description);
+ } else {
+ $description = $sess->description;
+ }
+ $row->cells[] = $description;
+
+ if (!$shortform) {
+ if ($sess->groupid) {
+ $sessiontypeshort = get_string('group') . ': ' . $userdata->groups[$sess->courseid][$sess->groupid]->name;
+ } else {
+ $sessiontypeshort = get_string('commonsession', 'attendance');
+ }
+ $row->cells[] = html_writer::tag('nobr', $sessiontypeshort);
+ }
+
+ if (!empty($USER->attendanceediting)) {
+ $context = context_module::instance($sess->cmid);
+ if (has_capability('mod/attendance:takeattendances', $context)) {
+ // Takedata needs:
+ // sessioninfo->sessdate
+ // sessioninfo->duration
+ // statuses
+ // updatemode
+ // sessionlog[userid]->statusid
+ // sessionlog[userid]->remarks
+ // pageparams->viewmode == mod_attendance_take_page_params::SORTED_GRID
+ // and urlparams to be able to use url method later.
+ //
+ // user needs:
+ // enrolmentstart
+ // enrolmentend
+ // enrolmentstatus
+ // id.
+
+ $nastyhack = new ReflectionClass('attendance_take_data');
+ $takedata = $nastyhack->newInstanceWithoutConstructor();
+ $takedata->sessioninfo = $sess;
+ $takedata->statuses = array_filter($userdata->statuses[$sess->attendanceid], function($x) use ($sess) {
+ return ($x->setnumber == $sess->statusset);
+ });
+ $takedata->updatemode = true;
+ $takedata->sessionlog = array($userdata->user->id => $sess);
+ $takedata->pageparams = new stdClass();
+ $takedata->pageparams->viewmode = mod_attendance_take_page_params::SORTED_GRID;
+ $ucdata = $this->construct_take_session_controls($takedata, $userdata->user);
+
+ $celltext = join($ucdata['text']);
+
+ if (array_key_exists('warning', $ucdata)) {
+ $celltext .= html_writer::empty_tag('br');
+ $celltext .= $ucdata['warning'];
+ }
+ if (array_key_exists('class', $ucdata)) {
+ $row->attributes['class'] = $ucdata['class'];
+ }
+
+ $cell = new html_table_cell($celltext);
+ $row->cells[] = $cell;
+
+ $celltext = empty($ucdata['remarks']) ? '' : $ucdata['remarks'];
+ $cell = new html_table_cell($celltext);
+ $row->cells[] = $cell;
+
+ } else {
+ if (!empty($sess->statusid)) {
+ $status = $userdata->statuses[$sess->attendanceid][$sess->statusid];
+ $row->cells[] = $status->description;
+ $row->cells[] = $sess->remarks;
+ }
+ }
+
+ } else {
+ if (!empty($sess->statusid)) {
+ $status = $userdata->statuses[$sess->attendanceid][$sess->statusid];
+ $row->cells[] = $status->description;
+ $row->cells[] = format_float($status->grade, 1, true, true) . ' / ' .
+ format_float($statussetmaxpoints[$status->setnumber], 1, true, true);
+ $row->cells[] = $sess->remarks;
+ } else if (($sess->sessdate + $sess->duration) < $userdata->user->enrolmentstart) {
+ $cell = new html_table_cell(get_string('enrolmentstart', 'attendance',
+ userdate($userdata->user->enrolmentstart, '%d.%m.%Y')));
+ $cell->colspan = 3;
+ $row->cells[] = $cell;
+ } else if ($userdata->user->enrolmentend and $sess->sessdate > $userdata->user->enrolmentend) {
+ $cell = new html_table_cell(get_string('enrolmentend', 'attendance',
+ userdate($userdata->user->enrolmentend, '%d.%m.%Y')));
+ $cell->colspan = 3;
+ $row->cells[] = $cell;
+ } else {
+ list($canmark, $reason) = attendance_can_student_mark($sess, false);
+ if ($canmark) {
+ // Student can mark their own attendance.
+ // URL to the page that lets the student modify their attendance.
+
+ $url = new moodle_url('/mod/attendance/attendance.php',
+ array('sessid' => $sess->id, 'sesskey' => sesskey()));
+ $cell = new html_table_cell(html_writer::link($url, get_string('submitattendance', 'attendance')));
+ $cell->colspan = 3;
+ $row->cells[] = $cell;
+ } else { // Student cannot mark their own attendace.
+ $row->cells[] = '?';
+ $row->cells[] = '? / ' . format_float($statussetmaxpoints[$sess->statusset], 1, true, true);
+ $row->cells[] = '';
+ }
+ }
+ }
+
+ $table->data[] = $row;
+ }
+ }
+
+ if (!empty($USER->attendanceediting)) {
+ $row = new html_table_row();
+ $params = array(
+ 'type' => 'submit',
+ 'class' => 'btn btn-primary',
+ 'value' => get_string('save', 'attendance'));
+ $cell = new html_table_cell(html_writer::tag('center', html_writer::empty_tag('input', $params)));
+ $cell->colspan = $colcount + (($groupby == 'activity') ? 2 : 1);
+ $row->cells[] = $cell;
+ $table->data[] = $row;
+ }
+
+ $logtext = html_writer::table($table);
+
+ if (!empty($USER->attendanceediting)) {
+ $formtext = html_writer::start_div('no-overflow');
+ $formtext .= $logtext;
+ $formtext .= html_writer::input_hidden_params($userdata->url(array('sesskey' => sesskey())));
+ $formtext .= html_writer::end_div();
+ // Could use userdata->urlpath if not private or userdata->url_path() if existed, but '' turns
+ // out to DTRT.
+ $logtext = html_writer::tag('form', $formtext, array('method' => 'post', 'action' => '',
+ 'id' => 'attendancetakeform'));
+ }
+ $allsessions->detail = $logtext;
+ return $allsessions;
+ }
+
/**
* Construct time for display.
*
diff --git a/styles.css b/styles.css
index 6b1a0d8..e635046 100644
--- a/styles.css
+++ b/styles.css
@@ -4,6 +4,7 @@
margin-left: 2px;
margin-right: 2px;
padding: 5px;
+ display: inline-block;
}
.path-mod-attendance .attcurbtn {
@@ -16,7 +17,6 @@
margin-bottom: 10px;
margin-left: auto;
margin-right: auto;
- width: 90%;
}
.path-mod-attendance .attfiltercontrols #currentdate {
@@ -54,6 +54,10 @@
font-size: 0.8em;
}
+.path-mod-attendance div.allsessionssummary + form#attendancetakeform > div {
+ width: 100%;
+}
+
.path-mod-attendance table.controls {
text-align: center;
width: 100%;
@@ -105,9 +109,27 @@
background-color: #eee;
padding: 30px 10px;
}
+.path-mod-attendance table.userinfobox .userpicture {
+ margin: 0;
+}
.path-mod-attendance table.attlist td.c0 {
text-align: right;
}
+.path-mod-attendance table.allsessions tr.grouper td {
+ background-color: #eee;
+}
+.path-mod-attendance table.allsessions td.groupheading {
+ font-weight: bold;
+}
+.path-mod-attendance .allsessionssummary > * {
+ display: inline-block;
+}
+.path-mod-attendance .allsessionssummary .float-right {
+ float: right;
+}
+.path-mod-attendance .allsessionssummary .float-left {
+ float: left;
+}
#page-mod-attendance-preferences .generalbox {
text-align: center;
diff --git a/view.php b/view.php
index dc5da51..dea964d 100644
--- a/view.php
+++ b/view.php
@@ -29,10 +29,13 @@ require_once(dirname(__FILE__).'/locallib.php');
$pageparams = new mod_attendance_view_page_params();
$id = required_param('id', PARAM_INT);
+$edit = optional_param('edit', -1, PARAM_BOOL);
$pageparams->studentid = optional_param('studentid', null, PARAM_INT);
$pageparams->mode = optional_param('mode', mod_attendance_view_page_params::MODE_THIS_COURSE, PARAM_INT);
$pageparams->view = optional_param('view', null, PARAM_INT);
$pageparams->curdate = optional_param('curdate', null, PARAM_INT);
+$pageparams->groupby = optional_param('groupby', 'course', PARAM_ALPHA);
+$pageparams->sesscourses = optional_param('sesscourses', 'current', PARAM_ALPHA);
$cm = get_coursemodule_from_id('attendance', $id, 0, false, MUST_EXIST);
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
@@ -60,14 +63,6 @@ if (!$pageparams->studentid) {
}
}
-$PAGE->set_url($att->url_view());
-$PAGE->set_title($course->shortname. ": ".$att->name);
-$PAGE->set_heading($course->fullname);
-$PAGE->set_cacheable(true);
-$PAGE->navbar->add(get_string('attendancereport', 'attendance'));
-
-$output = $PAGE->get_renderer('mod_attendance');
-
if (isset($pageparams->studentid) && $USER->id != $pageparams->studentid) {
// Only users with proper permissions should be able to see any user's individual report.
require_capability('mod/attendance:viewreports', $context);
@@ -77,6 +72,36 @@ if (isset($pageparams->studentid) && $USER->id != $pageparams->studentid) {
$userid = $USER->id;
}
+$url = $att->url_view($pageparams->get_significant_params());
+$PAGE->set_url($url);
+
+$buttons = '';
+$capabilities = array('mod/attendance:takeattendances', 'mod/attendance:changeattendances');
+if (has_any_capability($capabilities, $context) &&
+ $pageparams->mode == mod_attendance_view_page_params::MODE_ALL_SESSIONS) {
+
+ if (!isset($USER->attendanceediting)) {
+ $USER->attendanceediting = false;
+ }
+
+ if (($edit == 1) and confirm_sesskey()) {
+ $USER->attendanceediting = true;
+ } else if ($edit == 0 and confirm_sesskey()) {
+ $USER->attendanceediting = false;
+ }
+
+ if ($USER->attendanceediting) {
+ $options['edit'] = 0;
+ $string = get_string('turneditingoff');
+ } else {
+ $options['edit'] = 1;
+ $string = get_string('turneditingon');
+ }
+ $options['sesskey'] = sesskey();
+ $button = new single_button(new moodle_url($PAGE->url, $options), $string, 'post');
+ $PAGE->set_button($OUTPUT->render($button));
+}
+
$userdata = new attendance_user_data($att, $userid);
// Create url for link in log screen.
@@ -87,21 +112,43 @@ $filterparams = array(
'enddate' => $userdata->pageparams->enddate
);
$params = array_merge($userdata->pageparams->get_significant_params(), $filterparams);
+
+$header = new mod_attendance_header($att);
+
if (empty($userdata->pageparams->studentid)) {
$relateduserid = $USER->id;
} else {
$relateduserid = $userdata->pageparams->studentid;
}
-// Trigger viewed event.
-$event = \mod_attendance\event\session_report_viewed::create(array(
- 'relateduserid' => $relateduserid,
- 'context' => $context,
- 'other' => $params));
-$event->add_record_snapshot('course_modules', $cm);
-$event->trigger();
+if (($formdata = data_submitted()) && confirm_sesskey() && $edit == -1) {
+ $userdata->take_sessions_from_form_data($formdata);
-$header = new mod_attendance_header($att);
+ // Trigger updated event.
+ $event = \mod_attendance\event\session_report_updated::create(array(
+ 'relateduserid' => $relateduserid,
+ 'context' => $context,
+ 'other' => $params));
+ $event->add_record_snapshot('course_modules', $cm);
+ $event->trigger();
+
+ redirect($url, get_string('attendancesuccess', 'attendance'));
+} else {
+ // Trigger viewed event.
+ $event = \mod_attendance\event\session_report_viewed::create(array(
+ 'relateduserid' => $relateduserid,
+ 'context' => $context,
+ 'other' => $params));
+ $event->add_record_snapshot('course_modules', $cm);
+ $event->trigger();
+}
+
+$PAGE->set_title($course->shortname. ": ".$att->name);
+$PAGE->set_heading($course->fullname);
+$PAGE->set_cacheable(true);
+$PAGE->navbar->add(get_string('attendancereport', 'attendance'));
+
+$output = $PAGE->get_renderer('mod_attendance');
echo $output->header();