Compare commits
176 Commits
40-behatfi
...
MOODLE_32_
Author | SHA1 | Date |
---|---|---|
Morgan Harris | de770cd85e | 6 years ago |
Dan Marsden | 2a4a6e346f | 6 years ago |
Dan Marsden | 9fed2b2b56 | 6 years ago |
Dan Marsden | 67a4d16038 | 6 years ago |
Tõnis Tartes | 90648f0797 | 6 years ago |
Dan Marsden | 73ef68c1e2 | 6 years ago |
Dan Marsden | b9e65039e1 | 7 years ago |
Dan Marsden | 6f96016904 | 7 years ago |
Dan Marsden | 0de2abeede | 7 years ago |
Dan Marsden | 95d90eb931 | 7 years ago |
Dan Marsden | 7fd0d7770b | 7 years ago |
Dan Marsden | 7ee4db4c64 | 7 years ago |
Dan Marsden | 6479912c3b | 7 years ago |
Dan Marsden | 297edb8d8c | 7 years ago |
Dan Marsden | 9befe0c66c | 7 years ago |
Dan Marsden | 267a947b41 | 7 years ago |
Dan Marsden | 6798c344c8 | 7 years ago |
Dan Marsden | dc94a0ed54 | 7 years ago |
Dan Marsden | 52363e7b89 | 7 years ago |
Dan Marsden | 5597f5f0ce | 7 years ago |
Nick Phillips | b365a6facb | 7 years ago |
Nick Phillips | 2941e69810 | 7 years ago |
Dan Marsden | 6462700904 | 7 years ago |
Nick Phillips | 7a5a69df23 | 7 years ago |
Dan Marsden | 377c0b5408 | 7 years ago |
Dan Marsden | 69dc833194 | 7 years ago |
Dan Marsden | f045c7f34d | 7 years ago |
Dan Marsden | 3a700014c8 | 7 years ago |
Dan Marsden | bed019e33d | 7 years ago |
Dan Marsden | 561cccb681 | 7 years ago |
Dan Marsden | c33127770f | 7 years ago |
Dan Marsden | 464e0d1c5d | 7 years ago |
Dan Marsden | ab8a5455be | 7 years ago |
Dan Marsden | 25e3f42638 | 7 years ago |
Dan Marsden | d72613065f | 7 years ago |
Dan Marsden | 5f405665f7 | 7 years ago |
Dan Marsden | f6902c2bc6 | 7 years ago |
Dan Marsden | f8ab61f9f4 | 7 years ago |
Dan Marsden | 66acd7e0ef | 7 years ago |
Dan Marsden | ebaef74abf | 7 years ago |
Dan Marsden | c17174598f | 7 years ago |
Dan Marsden | 0e1e449109 | 7 years ago |
Dan Marsden | b3ed9f6217 | 7 years ago |
Dan Marsden | bb30545010 | 7 years ago |
Dan Marsden | a55eadcc72 | 7 years ago |
Dan Marsden | 7fb1fbfd01 | 7 years ago |
James Voong | d69d70172e | 7 years ago |
Dan Marsden | 109a1f02af | 7 years ago |
Dan Marsden | 2c5a2c8e89 | 7 years ago |
Dan Marsden | ec75d8095b | 7 years ago |
Dan Marsden | c38a02cd0e | 7 years ago |
Dan Marsden | 39732e8c2f | 7 years ago |
Dan Marsden | 11362ad458 | 7 years ago |
Chris Wharton | c1f1f9f765 | 7 years ago |
Dan Marsden | 105ae71bf1 | 7 years ago |
Dan Marsden | b88244a706 | 7 years ago |
Dan Marsden | 2e8387442c | 7 years ago |
Dan Marsden | 9bb37e5668 | 7 years ago |
Dan Marsden | c56313c9f6 | 7 years ago |
Dan Marsden | 8d8322229e | 7 years ago |
Dan Marsden | c0a1d50e52 | 7 years ago |
Dan Marsden | b64c0ead61 | 7 years ago |
Dan Marsden | 9b71d5ee4d | 7 years ago |
Dan Marsden | 9c13beca74 | 7 years ago |
Dan Marsden | 96fb1017f7 | 7 years ago |
Dan Marsden | fe20e88964 | 7 years ago |
Dan Marsden | bf7e16f2c9 | 7 years ago |
Dan Marsden | 37f5a2735f | 7 years ago |
Dan Marsden | c75a060d65 | 7 years ago |
Dan Marsden | 5ce7ee488c | 7 years ago |
Dan Marsden | 9488a5585b | 7 years ago |
Dan Marsden | e8f7cbcc0b | 8 years ago |
Dan Marsden | d8357769cc | 8 years ago |
Dan Marsden | fc3078ecd3 | 8 years ago |
Dan Marsden | afe0a72e7f | 8 years ago |
Dan Marsden | b9c07817f6 | 8 years ago |
Dan Marsden | d9c1236772 | 8 years ago |
Dan Marsden | 2aea1988e9 | 8 years ago |
Dan Marsden | 9f2251c315 | 8 years ago |
Dan Marsden | ea32a3535f | 8 years ago |
Dan Marsden | 4bbed2c160 | 8 years ago |
Dan Marsden | e2580f491d | 8 years ago |
Dan Marsden | 332ee78344 | 8 years ago |
Dan Marsden | 782f4086e0 | 8 years ago |
Dan Marsden | a27adac3e9 | 8 years ago |
Dan Marsden | 3260294bfe | 8 years ago |
Dan Marsden | 9fc4221a81 | 8 years ago |
Dan Marsden | ad6919e3ec | 8 years ago |
Dan Marsden | e487adaccc | 8 years ago |
Dan Marsden | 49b7ca4999 | 8 years ago |
Dan Marsden | 296a696904 | 8 years ago |
Dan Marsden | 181cd6234b | 8 years ago |
Dan Marsden | 60a2f79bbb | 8 years ago |
Dan Marsden | a985d1dab3 | 8 years ago |
Dan Marsden | 2eb0517644 | 8 years ago |
Dan Marsden | 39644e9476 | 8 years ago |
Dan Marsden | 70e1bb6e59 | 8 years ago |
Dan Marsden | 18d46879c5 | 8 years ago |
Dan Marsden | 478d7fee2c | 8 years ago |
Dan Marsden | 2d9fb84dd1 | 8 years ago |
Dan Marsden | ae91534ddc | 8 years ago |
Dan Marsden | bf93d84aa9 | 8 years ago |
Dan Marsden | 959f576025 | 8 years ago |
Dan Marsden | 34183f0c5c | 8 years ago |
Dan Marsden | 5547855ad0 | 8 years ago |
Dan Marsden | f8420243ff | 8 years ago |
Dan Marsden | 1e65aa6785 | 8 years ago |
Dan Marsden | f6b5190fe0 | 8 years ago |
Dan Marsden | 5337794927 | 8 years ago |
Dan Marsden | 201601e359 | 8 years ago |
Dan Marsden | 39f2b19832 | 8 years ago |
Dan Marsden | 8a94c10a09 | 8 years ago |
Dan Marsden | 35c1712ed4 | 8 years ago |
Dan Marsden | 38f5469cf6 | 8 years ago |
Dan Marsden | 70569a53df | 8 years ago |
Dan Marsden | 8fdf17d30f | 8 years ago |
Dan Marsden | 7ca915eb68 | 8 years ago |
Dan Marsden | 17f51afaf1 | 8 years ago |
Dan Marsden | 142bafb5ef | 8 years ago |
Dan Marsden | 142fc543cc | 8 years ago |
Dan Marsden | 2d9c88224c | 8 years ago |
Dan Marsden | eccf8784d1 | 8 years ago |
Dan Marsden | af7d666777 | 8 years ago |
Dan Marsden | f34760ca17 | 8 years ago |
Dan Marsden | 9eaf63b746 | 8 years ago |
Dan Marsden | d4498ccebe | 8 years ago |
Dan Marsden | 00ce366a41 | 8 years ago |
Dan Marsden | e89c46aaa9 | 8 years ago |
Dan Marsden | f2df0d239e | 8 years ago |
Dan Marsden | 3569d778d5 | 8 years ago |
Dan Marsden | 40721dc1d5 | 8 years ago |
Dan Marsden | 22a98145cf | 8 years ago |
Dan Marsden | be48371a17 | 8 years ago |
Dan Marsden | 913c35aa35 | 8 years ago |
Dan Marsden | c668a63213 | 8 years ago |
Dan Marsden | 1617ce7cdd | 8 years ago |
Dan Marsden | 9de4a283fe | 8 years ago |
Dan Marsden | f9c61f4efc | 8 years ago |
Dan Marsden | c6739acf7f | 8 years ago |
Dan Marsden | 9766cae6ef | 8 years ago |
Dan Marsden | c55d38af16 | 8 years ago |
Dan Marsden | 6122dc179d | 8 years ago |
Dan Marsden | 848e1f6349 | 8 years ago |
Dan Marsden | 92ddadb87f | 8 years ago |
Dan Marsden | d73402bf7a | 8 years ago |
Dan Marsden | 67fc97868d | 8 years ago |
Dan Marsden | 4ad3201de8 | 8 years ago |
Dan Marsden | 2e0bfea6bf | 8 years ago |
Dan Marsden | d5618de89d | 8 years ago |
Dan Marsden | 25e3f2f7a0 | 8 years ago |
Dan Marsden | cc8db5bab9 | 8 years ago |
Dan Marsden | 4ba19a86ca | 8 years ago |
Dan Marsden | 51751271f1 | 8 years ago |
Dan Marsden | fb96b30c29 | 8 years ago |
Dan Marsden | f1311f3cf2 | 8 years ago |
Dan Marsden | 84d0609ac6 | 8 years ago |
Dan Marsden | 8ca6c26f96 | 8 years ago |
Dan Marsden | c2282bc6ae | 8 years ago |
Dan Marsden | 6d8c2c2418 | 8 years ago |
Dan Marsden | 9bf96ab3bc | 8 years ago |
Dan Marsden | 0e31f6796a | 8 years ago |
Dan Marsden | 73011e5bdb | 8 years ago |
Dan Marsden | f02845a616 | 8 years ago |
Dan Marsden | 1936ddf929 | 8 years ago |
Dan Marsden | 64e6df0154 | 8 years ago |
Dan Marsden | 7c3845ae58 | 8 years ago |
Daniel Thee Roperto | b79dac055f | 8 years ago |
Dan Marsden | a624a59139 | 8 years ago |
Dan Marsden | 4a7789f1df | 8 years ago |
Dan Marsden | 682ce4af85 | 8 years ago |
Dan Marsden | 27095c459e | 8 years ago |
Dan Marsden | 9ef35c4ea4 | 8 years ago |
Dan Marsden | 49714bf427 | 8 years ago |
Dan Marsden | eef7cf7afe | 8 years ago |
Dan Marsden | 6895d64c92 | 8 years ago |
Dan Marsden | 4cff027414 | 8 years ago |
84 changed files with 6784 additions and 989 deletions
@ -0,0 +1,35 @@ |
|||
### Date: 2017-June-22 |
|||
### Release: 3.2.14 |
|||
- New Feature: Allow automatic marking using site logs. |
|||
- New Feature: Warn users when attendance drops below threshold. |
|||
- Improvement: Allow default view for teachers to be set at admin level. |
|||
- Improvement: All courses user report now displays as table. |
|||
- Bug fix: Restored attendances do not create calendar events correctly. |
|||
|
|||
### Date: 2017-May-23 |
|||
### Release: 3.2.12 |
|||
- New Feature: New site Level/course category report with average course attendance. |
|||
- New Feature: Allow unmarked students to be automatically marked when session closes. |
|||
|
|||
--- |
|||
|
|||
### Date: 2017-May-11 |
|||
- New Feature: Allow subnet mask to be set at the attendance session level. |
|||
- New Feature: Allow certain statuses to be hidden from students when self-marking attendance. |
|||
- New Feature: Allow student password to be viewed on session list page. |
|||
- Improvement: Improve usablity by grouping settings on session add form. |
|||
- Bug fix - fix issue with displaying dates when site hosted on Windows server. |
|||
- Bug fix - improve compliance with Moodle coding guidelines. |
|||
|
|||
--- |
|||
|
|||
### Date: 2017-Apr-21 |
|||
- Feature: Allow a random self-marking password to be used when creating session. |
|||
- Improvement: #63 use core useridentity setting when showing list of users. |
|||
- Improvement: #258 Add link to attendance on student overview report. |
|||
- Improvement: allow student self-marking to be restricted to the session time. |
|||
- Improvement: allow admin to set default values when teachers creating new sessions. |
|||
- Bug fix - improve compliance with Moodle coding guidelines - phpdocs etc. |
|||
|
|||
--- |
|||
|
@ -0,0 +1,140 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Attendance course summary report. |
|||
* |
|||
* @package mod_attendance |
|||
* @copyright 2017 onwards Dan Marsden http://danmarsden.com |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
require_once('../../config.php'); |
|||
require_once($CFG->libdir.'/adminlib.php'); |
|||
require_once($CFG->dirroot.'/mod/attendance/lib.php'); |
|||
require_once($CFG->dirroot.'/mod/attendance/locallib.php'); |
|||
require_once($CFG->libdir.'/tablelib.php'); |
|||
require_once($CFG->libdir.'/coursecatlib.php'); |
|||
|
|||
$category = optional_param('category', 0, PARAM_INT); |
|||
$attendancecm = optional_param('id', 0, PARAM_INT); |
|||
$download = optional_param('download', '', PARAM_ALPHA); |
|||
$sort = optional_param('tsort', 'timesent', PARAM_ALPHA); |
|||
|
|||
if (!empty($category)) { |
|||
$context = context_coursecat::instance($category); |
|||
$coursecat = coursecat::get($category); |
|||
$courses = $coursecat->get_courses(array('recursive' => true, 'idonly' => true)); |
|||
$PAGE->set_category_by_id($category); |
|||
require_login(); |
|||
} else if (!empty($attendancecm)) { |
|||
$cm = get_coursemodule_from_id('attendance', $attendancecm, 0, false, MUST_EXIST); |
|||
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); |
|||
$att = $DB->get_record('attendance', array('id' => $cm->instance), '*', MUST_EXIST); |
|||
$courses = array($course->id); |
|||
$context = context_module::instance($cm->id); |
|||
require_login($course, false, $cm); |
|||
} else { |
|||
admin_externalpage_setup('managemodules'); |
|||
$context = context_system::instance(); |
|||
$courses = array(); // Show all courses. |
|||
} |
|||
// Check permissions. |
|||
require_capability('mod/attendance:viewreports', $context); |
|||
|
|||
$exportfilename = 'attendance-absentee.csv'; |
|||
|
|||
$PAGE->set_url('/mod/attendance/absentee.php', array('category' => $category, 'id' => $attendancecm)); |
|||
|
|||
$PAGE->set_heading($SITE->fullname); |
|||
|
|||
$table = new flexible_table('attendanceabsentee'); |
|||
$table->define_baseurl($PAGE->url); |
|||
|
|||
if (!$table->is_downloading($download, $exportfilename)) { |
|||
if (!empty($attendancecm)) { |
|||
$pageparams = new mod_attendance_sessions_page_params(); |
|||
$att = new mod_attendance_structure($att, $cm, $course, $context, $pageparams); |
|||
$output = $PAGE->get_renderer('mod_attendance'); |
|||
$tabs = new attendance_tabs($att, attendance_tabs::TAB_ABSENTEE); |
|||
echo $output->header(); |
|||
echo $output->heading(get_string('attendanceforthecourse', 'attendance').' :: ' .format_string($course->fullname)); |
|||
echo $output->render($tabs); |
|||
} else { |
|||
echo $OUTPUT->header(); |
|||
echo $OUTPUT->heading(get_string('absenteereport', 'mod_attendance')); |
|||
if (empty($category)) { |
|||
// Only show tabs if displaying via the admin page. |
|||
$tabmenu = attendance_print_settings_tabs('absentee'); |
|||
echo $tabmenu; |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
$table->define_columns(array('coursename', 'aname', 'userid', 'numtakensessions', 'percent', 'timesent')); |
|||
$table->define_headers(array(get_string('course'), |
|||
get_string('pluginname', 'attendance'), |
|||
get_string('user'), |
|||
get_string('takensessions', 'attendance'), |
|||
get_string('averageattendance', 'attendance'), |
|||
get_string('triggered', 'attendance'))); |
|||
$table->sortable(true); |
|||
$table->set_attribute('cellspacing', '0'); |
|||
$table->set_attribute('class', 'generaltable generalbox'); |
|||
$table->show_download_buttons_at(array(TABLE_P_BOTTOM)); |
|||
$table->setup(); |
|||
|
|||
// Work out direction of sort required. |
|||
$sortcolumns = $table->get_sort_columns(); |
|||
// Now do sorting if specified. |
|||
|
|||
$orderby = ' ORDER BY percent ASC'; |
|||
if (!empty($sort)) { |
|||
$direction = ' DESC'; |
|||
if (!empty($sortcolumns[$sort]) && $sortcolumns[$sort] == SORT_ASC) { |
|||
$direction = ' ASC'; |
|||
} |
|||
$orderby = " ORDER BY $sort $direction"; |
|||
|
|||
} |
|||
|
|||
$records = attendance_get_users_to_notify($courses, $orderby); |
|||
foreach ($records as $record) { |
|||
if (!$table->is_downloading($download, $exportfilename)) { |
|||
$url = new moodle_url('/mod/attendance/index.php', array('id' => $record->courseid)); |
|||
$name = html_writer::link($url, $record->coursename); |
|||
} else { |
|||
$name = $record->coursename; |
|||
} |
|||
$url = new moodle_url('/mod/attendance/view.php', array('studentid' => $record->userid, |
|||
'id' => $record->cmid, 'view' => ATT_VIEW_ALL)); |
|||
$attendancename = html_writer::link($url, $record->aname); |
|||
|
|||
$username = html_writer::link($url, fullname($record)); |
|||
$percent = round($record->percent * 100)."%"; |
|||
$timesent = "-"; |
|||
if (!empty($record->timesent)) { |
|||
$timesent = userdate($record->timesent); |
|||
} |
|||
|
|||
$table->add_data(array($name, $attendancename, $username, $record->numtakensessions, $percent, $timesent)); |
|||
} |
|||
$table->finish_output(); |
|||
|
|||
if (!$table->is_downloading()) { |
|||
echo $OUTPUT->footer(); |
|||
} |
@ -0,0 +1,113 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Contains class mod_attendance_add_warning_form |
|||
* |
|||
* @package mod_attendance |
|||
* @copyright 2017 Dan Marsden |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
defined('MOODLE_INTERNAL') || die(); |
|||
|
|||
/** |
|||
* Class mod_attendance_add_warning_form |
|||
* |
|||
* @package mod_attendance |
|||
* @copyright 2017 Dan Marsden |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
class mod_attendance_add_warning_form extends moodleform { |
|||
/** |
|||
* Form definition |
|||
*/ |
|||
public function definition() { |
|||
global $COURSE; |
|||
$mform = $this->_form; |
|||
|
|||
// Load global defaults. |
|||
$config = get_config('attendance'); |
|||
|
|||
$options = array(); |
|||
for ($i = 1; $i <= 100; $i++) { |
|||
$options[$i] = "$i%"; |
|||
} |
|||
$mform->addElement('select', 'warningpercent', get_string('warningpercent', 'mod_attendance'), $options); |
|||
$mform->addHelpButton('warningpercent', 'warningpercent', 'mod_attendance'); |
|||
$mform->setType('warningpercent', PARAM_INT); |
|||
$mform->setDefault('warningpercent', $config->warningpercent); |
|||
|
|||
$options = array(); |
|||
for ($i = 1; $i <= ATTENDANCE_MAXWARNAFTER; $i++) { |
|||
$options[$i] = "$i"; |
|||
} |
|||
$mform->addElement('select', 'warnafter', get_string('warnafter', 'mod_attendance'), $options); |
|||
$mform->addHelpButton('warnafter', 'warnafter', 'mod_attendance'); |
|||
$mform->setType('warnafter', PARAM_INT); |
|||
$mform->setDefault('warnafter', $config->warnafter); |
|||
|
|||
$mform->addElement('select', 'maxwarn', get_string('maxwarn', 'mod_attendance'), $options); |
|||
$mform->addHelpButton('maxwarn', 'maxwarn', 'mod_attendance'); |
|||
$mform->setType('maxwarn', PARAM_INT); |
|||
$mform->setDefault('maxwarn', $config->maxwarn); |
|||
|
|||
$mform->addElement('checkbox', 'emailuser', get_string('emailuser', 'mod_attendance')); |
|||
$mform->addHelpButton('emailuser', 'emailuser', 'mod_attendance'); |
|||
$mform->setDefault('emailuser', $config->emailuser); |
|||
|
|||
$mform->addElement('text', 'emailsubject', get_string('emailsubject', 'mod_attendance'), array('size' => '64')); |
|||
$mform->setType('emailsubject', PARAM_TEXT); |
|||
$mform->addRule('emailsubject', get_string('maximumchars', '', 255), 'maxlength', 255, 'client'); |
|||
$mform->addHelpButton('emailsubject', 'emailsubject', 'mod_attendance'); |
|||
$mform->setDefault('emailsubject', $config->emailsubject); |
|||
|
|||
$mform->addElement('editor', 'emailcontent', get_string('emailcontent', 'mod_attendance'), null, null); |
|||
$mform->setDefault('emailcontent', array('text' => format_text($config->emailcontent))); |
|||
$mform->setType('emailcontent', PARAM_RAW); |
|||
$mform->addHelpButton('emailcontent', 'emailcontent', 'mod_attendance'); |
|||
|
|||
$users = get_users_by_capability(context_course::instance($COURSE->id), 'mod/attendance:warningemails'); |
|||
$options = array(); |
|||
foreach ($users as $user) { |
|||
$options[$user->id] = fullname($user); |
|||
} |
|||
|
|||
$select = $mform->addElement('searchableselector', 'thirdpartyemails', |
|||
get_string('thirdpartyemails', 'mod_attendance'), $options); |
|||
$mform->setType('thirdpartyemails', PARAM_TEXT); |
|||
$mform->addHelpButton('thirdpartyemails', 'thirdpartyemails', 'mod_attendance'); |
|||
$select->setMultiple(true); |
|||
|
|||
// Need to set hidden elements when adding default options. |
|||
$mform->addElement('hidden', 'idnumber', 0); // Default options use 0 as the idnumber. |
|||
$mform->setType('idnumber', PARAM_INT); |
|||
|
|||
$mform->addElement('hidden', 'notid', 0); // The id of warning record. |
|||
$mform->setType('notid', PARAM_INT); |
|||
|
|||
$mform->addElement('hidden', 'id', $this->_customdata['id']); // The id of course module record if attendance level. |
|||
$mform->setType('id', PARAM_INT); |
|||
|
|||
if (!empty($this->_customdata['notid'])) { |
|||
$btnstring = get_string('update', 'attendance'); |
|||
} else { |
|||
$btnstring = get_string('add', 'attendance'); |
|||
} |
|||
$this->add_action_buttons(true, $btnstring); |
|||
|
|||
} |
|||
} |
@ -0,0 +1,93 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* This file contains an event for when self-marking is blocked because |
|||
* another student used the same IP address to self-mark. |
|||
* |
|||
* @package mod_attendance |
|||
* @author Dan Marsden <dan@danmarsden.com> |
|||
* @copyright 2018 Catalyst IT |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
namespace mod_attendance\event; |
|||
|
|||
defined('MOODLE_INTERNAL') || die(); |
|||
|
|||
/** |
|||
* Event for when self-marking is blocked |
|||
* |
|||
* @property-read array $other { |
|||
* Extra information about event properties. |
|||
* |
|||
* string mode Mode of the report viewed. |
|||
* } |
|||
* @package mod_attendance |
|||
* @author Dan Marsden <dan@danmarsden.com> |
|||
* @copyright 2018 Catalyst IT |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
class session_ip_shared extends \core\event\base { |
|||
|
|||
/** |
|||
* Init method. |
|||
*/ |
|||
protected function init() { |
|||
$this->data['crud'] = 'r'; |
|||
$this->data['edulevel'] = self::LEVEL_PARTICIPATING; |
|||
$this->data['objecttable'] = 'attendance_log'; |
|||
} |
|||
|
|||
/** |
|||
* Returns non-localised description of what happened. |
|||
* |
|||
* @return string |
|||
*/ |
|||
public function get_description() { |
|||
return 'User with id ' . $this->userid . ' was blocked from taking attendance for sessionid: ' . $this->other['sessionid'] . |
|||
' because user with id '.$this->other['otheruser'] . ' previously marked attendance with the same IP address.'; |
|||
} |
|||
|
|||
/** |
|||
* Returns localised general event name. |
|||
* |
|||
* @return string |
|||
*/ |
|||
public static function get_name() { |
|||
return get_string('eventsessionipshared', 'mod_attendance'); |
|||
} |
|||
|
|||
/** |
|||
* Get URL related to the action |
|||
* |
|||
* @return \moodle_url |
|||
*/ |
|||
public function get_url() { |
|||
return new \moodle_url('/mod/attendance/attendance.php'); |
|||
} |
|||
|
|||
/** |
|||
* Get objectid mapping |
|||
* |
|||
* @return array of parameters for object mapping. |
|||
*/ |
|||
public static function get_objectid_mapping() { |
|||
return array( |
|||
'db' => 'attendance', |
|||
'restore' => 'attendance' |
|||
); |
|||
} |
|||
} |
@ -0,0 +1,92 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* This file contains an event for when an attendance sessions is imported. |
|||
* |
|||
* @package mod_attendance |
|||
* @author Chris Wharton <chriswharton@catalyst.net.nz> |
|||
* @copyright 2017 Catalyst IT |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
namespace mod_attendance\event; |
|||
|
|||
defined('MOODLE_INTERNAL') || die(); |
|||
|
|||
/** |
|||
* Event for when an attendance sessions is imported |
|||
* |
|||
* @property-read array $other { |
|||
* Extra information about event properties. |
|||
* |
|||
* string mode Mode of the report viewed. |
|||
* } |
|||
* @package mod_attendance |
|||
* @since Moodle 2.7 |
|||
* @author Chris Wharton <chriswharton@catalyst.net.nz> |
|||
* @copyright 2017 Catalyst IT |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
class sessions_imported extends \core\event\base { |
|||
|
|||
/** |
|||
* Init method. |
|||
*/ |
|||
protected function init() { |
|||
$this->data['crud'] = 'c'; |
|||
$this->data['edulevel'] = self::LEVEL_OTHER; |
|||
$this->data['objecttable'] = 'attendance_sessions'; |
|||
} |
|||
|
|||
/** |
|||
* Returns non-localised description of what happened. |
|||
* |
|||
* @return string |
|||
*/ |
|||
public function get_description() { |
|||
return 'User with id ' . $this->userid . ' imported ' . $this->other['count'] . ' sessions'; |
|||
} |
|||
|
|||
/** |
|||
* Returns localised general event name. |
|||
* |
|||
* @return string |
|||
*/ |
|||
public static function get_name() { |
|||
return get_string('eventsessionsimported', 'mod_attendance'); |
|||
} |
|||
|
|||
/** |
|||
* Get URL related to the action |
|||
* |
|||
* @return \moodle_url |
|||
*/ |
|||
public function get_url() { |
|||
return new \moodle_url('/mod/attendance/import/sessions.php'); |
|||
} |
|||
|
|||
/** |
|||
* Get objectid mapping |
|||
* |
|||
* @return array of parameters for object mapping. |
|||
*/ |
|||
public static function get_objectid_mapping() { |
|||
return array( |
|||
'db' => 'attendance', |
|||
'restore' => 'attendance' |
|||
); |
|||
} |
|||
} |
@ -0,0 +1,86 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* This file contains the form for importing sessions from a file. |
|||
* |
|||
* @package mod_attendance |
|||
* @author Chris Wharton <chriswharton@catalyst.net.nz> |
|||
* @copyright 2017 Catalyst IT |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
namespace mod_attendance\form\import; |
|||
|
|||
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.'); |
|||
|
|||
use core_text; |
|||
use csv_import_reader; |
|||
use moodleform; |
|||
require_once($CFG->libdir . '/formslib.php'); |
|||
require_once($CFG->libdir . '/csvlib.class.php'); |
|||
|
|||
/** |
|||
* Import attendance sessions. |
|||
* |
|||
* @package mod_attendance |
|||
* @author Chris Wharton <chriswharton@catalyst.net.nz> |
|||
* @copyright 2017 Catalyst IT |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
class sessions extends moodleform { |
|||
|
|||
/** |
|||
* Define the form - called by parent constructor |
|||
*/ |
|||
public function definition() { |
|||
global $CFG; |
|||
|
|||
$mform = $this->_form; |
|||
$element = $mform->createElement('filepicker', 'importfile', get_string('importfile', 'mod_attendance')); |
|||
$mform->addElement($element); |
|||
$mform->addHelpButton('importfile', 'importfile', 'mod_attendance'); |
|||
$mform->addRule('importfile', null, 'required'); |
|||
$mform->addElement('hidden', 'confirm', 0); |
|||
$mform->setType('confirm', PARAM_BOOL); |
|||
|
|||
$choices = csv_import_reader::get_delimiter_list(); |
|||
$mform->addElement('select', 'delimiter_name', get_string('csvdelimiter', 'mod_attendance'), $choices); |
|||
if (array_key_exists('cfg', $choices)) { |
|||
$mform->setDefault('delimiter_name', 'cfg'); |
|||
} else if (get_string('listsep', 'langconfig') == ';') { |
|||
$mform->setDefault('delimiter_name', 'semicolon'); |
|||
} else { |
|||
$mform->setDefault('delimiter_name', 'comma'); |
|||
} |
|||
|
|||
$choices = core_text::get_encodings(); |
|||
$mform->addElement('select', 'encoding', get_string('encoding', 'mod_attendance'), $choices); |
|||
$mform->setDefault('encoding', 'UTF-8'); |
|||
|
|||
$this->add_action_buttons(false, get_string('import', 'mod_attendance')); |
|||
} |
|||
|
|||
/** |
|||
* Display an error on the import form. |
|||
* |
|||
* @param string $msg |
|||
*/ |
|||
public function set_import_error($msg) { |
|||
$mform = $this->_form; |
|||
|
|||
$mform->setElementError('importfile', $msg); |
|||
} |
|||
} |
@ -0,0 +1,73 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Import attendance sessions. |
|||
* |
|||
* @package mod_attendance |
|||
* @author Chris Wharton <chriswharton@catalyst.net.nz> |
|||
* @copyright 2017 Catalyst IT |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
namespace mod_attendance\form\import; |
|||
|
|||
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.'); |
|||
|
|||
use moodleform; |
|||
require_once($CFG->libdir . '/formslib.php'); |
|||
|
|||
/** |
|||
* Import attendance sessions. |
|||
* |
|||
* @package mod_attendance |
|||
* @author Chris Wharton <chriswharton@catalyst.net.nz> |
|||
* @copyright 2017 Catalyst IT |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
class sessions_confirm extends moodleform { |
|||
|
|||
/** |
|||
* Define the form - called by parent constructor |
|||
*/ |
|||
public function definition() { |
|||
$importer = $this->_customdata; |
|||
|
|||
$mform = $this->_form; |
|||
$mform->addElement('hidden', 'confirm', 1); |
|||
$mform->setType('confirm', PARAM_BOOL); |
|||
$mform->addElement('hidden', 'importid', $importer->get_importid()); |
|||
$mform->setType('importid', PARAM_INT); |
|||
|
|||
$requiredheaders = $importer->list_required_headers(); |
|||
$foundheaders = $importer->list_found_headers(); |
|||
|
|||
if (empty($foundheaders)) { |
|||
$foundheaders = range(0, count($requiredheaders)); |
|||
} |
|||
$foundheaders[- 1] = get_string('none'); |
|||
|
|||
foreach ($requiredheaders as $index => $requiredheader) { |
|||
$mform->addElement('select', 'header' . $index, $requiredheader, $foundheaders); |
|||
if (isset($foundheaders[$index])) { |
|||
$mform->setDefault('header' . $index, $index); |
|||
} else { |
|||
$mform->setDefault('header' . $index, - 1); |
|||
} |
|||
} |
|||
|
|||
$this->add_action_buttons(true, get_string('confirm', 'mod_attendance')); |
|||
} |
|||
} |
@ -0,0 +1,80 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Class definition for mod_attendance_header |
|||
* |
|||
* @package mod_attendance |
|||
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net> |
|||
* @copyright 2017 Catalyst IT Australia {@link http://www.catalyst-au.net} |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
defined('MOODLE_INTERNAL') || die(); |
|||
|
|||
/** |
|||
* Used to render the page header. |
|||
* |
|||
* @package mod_attendance |
|||
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net> |
|||
* @copyright 2017 Catalyst IT Australia {@link http://www.catalyst-au.net} |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
class mod_attendance_header implements renderable { |
|||
/** @var mod_attendance_structure */ |
|||
private $attendance; |
|||
|
|||
/** @var string */ |
|||
private $title; |
|||
|
|||
/** |
|||
* mod_attendance_header constructor. |
|||
* |
|||
* @param mod_attendance_structure $attendance |
|||
* @param null $title |
|||
*/ |
|||
public function __construct(mod_attendance_structure $attendance, $title = null) { |
|||
$this->attendance = $attendance; |
|||
$this->title = $title; |
|||
} |
|||
|
|||
/** |
|||
* Gets the attendance data. |
|||
* |
|||
* @return mod_attendance_structure |
|||
*/ |
|||
public function get_attendance() { |
|||
return $this->attendance; |
|||
} |
|||
|
|||
/** |
|||
* Gets the title. If title was not provided, use the module name. |
|||
* |
|||
* @return string |
|||
*/ |
|||
public function get_title() { |
|||
return is_null($this->title) ? $this->attendance->name : $this->title; |
|||
} |
|||
|
|||
/** |
|||
* Checks if the header should be rendered. |
|||
* |
|||
* @return bool |
|||
*/ |
|||
public function should_render() { |
|||
return !is_null($this->title) || !empty($this->attendance->intro); |
|||
} |
|||
} |
@ -0,0 +1,497 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Import attendance sessions class. |
|||
* |
|||
* @package mod_attendance |
|||
* @author Chris Wharton <chriswharton@catalyst.net.nz> |
|||
* @copyright 2017 Catalyst IT |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
namespace mod_attendance\import; |
|||
|
|||
defined('MOODLE_INTERNAL') || die(); |
|||
|
|||
use csv_import_reader; |
|||
use mod_attendance_notifyqueue; |
|||
use mod_attendance_structure; |
|||
use stdClass; |
|||
|
|||
/** |
|||
* Import attendance sessions. |
|||
* |
|||
* @package mod_attendance |
|||
* @author Chris Wharton <chriswharton@catalyst.net.nz> |
|||
* @copyright 2017 Catalyst IT |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
class sessions { |
|||
|
|||
/** @var string $error The errors message from reading the xml */ |
|||
protected $error = ''; |
|||
|
|||
/** @var array $sessions The sessions info */ |
|||
protected $sessions = array(); |
|||
|
|||
/** @var array $mappings The mappings info */ |
|||
protected $mappings = array(); |
|||
|
|||
/** @var int The id of the csv import */ |
|||
protected $importid = 0; |
|||
|
|||
/** @var csv_import_reader|null $importer */ |
|||
protected $importer = null; |
|||
|
|||
/** @var array $foundheaders */ |
|||
protected $foundheaders = array(); |
|||
|
|||
/** @var bool $useprogressbar Control whether importing should use progress bars or not. */ |
|||
protected $useprogressbar = false; |
|||
|
|||
/** @var \core\progress\display_if_slow|null $progress The progress bar instance. */ |
|||
protected $progress = null; |
|||
|
|||
/** |
|||
* Store an error message for display later |
|||
* |
|||
* @param string $msg |
|||
*/ |
|||
public function fail($msg) { |
|||
$this->error = $msg; |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* Get the CSV import id |
|||
* |
|||
* @return string The import id. |
|||
*/ |
|||
public function get_importid() { |
|||
return $this->importid; |
|||
} |
|||
|
|||
/** |
|||
* Get the list of headers required for import. |
|||
* |
|||
* @return array The headers (lang strings) |
|||
*/ |
|||
public static function list_required_headers() { |
|||
return array( |
|||
get_string('course', 'attendance'), |
|||
get_string('groups', 'attendance'), |
|||
get_string('sessiondate', 'attendance'), |
|||
get_string('from', 'attendance'), |
|||
get_string('to', 'attendance'), |
|||
get_string('description', 'attendance'), |
|||
get_string('repeaton', 'attendance'), |
|||
get_string('repeatevery', 'attendance'), |
|||
get_string('repeatuntil', 'attendance'), |
|||
get_string('studentscanmark', 'attendance'), |
|||
get_string('passwordgrp', 'attendance'), |
|||
get_string('randompassword', 'attendance'), |
|||
get_string('subnet', 'attendance'), |
|||
get_string('automark', 'attendance'), |
|||
get_string('autoassignstatus', 'attendance'), |
|||
get_string('absenteereport', 'attendance'), |
|||
get_string('preventsharedip', 'attendance'), |
|||
get_string('preventsharediptime', 'attendance') |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* Get the list of headers found in the import. |
|||
* |
|||
* @return array The found headers (names from import) |
|||
*/ |
|||
public function list_found_headers() { |
|||
return $this->foundheaders; |
|||
} |
|||
|
|||
/** |
|||
* Read the data from the mapping form. |
|||
* |
|||
* @param array $data The mapping data. |
|||
*/ |
|||
protected function read_mapping_data($data) { |
|||
if ($data) { |
|||
return array( |
|||
'course' => $data->header0, |
|||
'groups' => $data->header1, |
|||
'sessiondate' => $data->header2, |
|||
'from' => $data->header3, |
|||
'to' => $data->header4, |
|||
'description' => $data->header5, |
|||
'repeaton' => $data->header6, |
|||
'repeatevery' => $data->header7, |
|||
'repeatuntil' => $data->header8, |
|||
'studentscanmark' => $data->header9, |
|||
'passwordgrp' => $data->header10, |
|||
'randompassword' => $data->header11, |
|||
'subnet' => $data->header12, |
|||
'automark' => $data->header13, |
|||
'autoassignstatus' => $data->header14, |
|||
'absenteereport' => $data->header15, |
|||
'preventsharedip' => $data->header16, |
|||
'preventsharediptime' => $data->header17, |
|||
); |
|||
} else { |
|||
return array( |
|||
'course' => 0, |
|||
'groups' => 1, |
|||
'sessiondate' => 2, |
|||
'from' => 3, |
|||
'to' => 4, |
|||
'description' => 5, |
|||
'repeaton' => 6, |
|||
'repeatevery' => 7, |
|||
'repeatuntil' => 8, |
|||
'studentscanmark' => 9, |
|||
'passwordgrp' => 10, |
|||
'randompassword' => 11, |
|||
'subnet' => 12, |
|||
'automark' => 13, |
|||
'autoassignstatus' => 14, |
|||
'absenteereport' => 15, |
|||
'preventsharedip' => 16, |
|||
'preventsharediptime' => 17 |
|||
); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Get the a column from the imported data. |
|||
* |
|||
* @param array $row The imported raw row |
|||
* @param int $index The column index we want |
|||
* @return string The column data. |
|||
*/ |
|||
protected function get_column_data($row, $index) { |
|||
if ($index < 0) { |
|||
return ''; |
|||
} |
|||
return isset($row[$index]) ? $row[$index] : ''; |
|||
} |
|||
|
|||
/** |
|||
* Constructor - parses the raw text for sanity. |
|||
* |
|||
* @param string $text The raw csv text. |
|||
* @param string $encoding The encoding of the csv file. |
|||
* @param string $delimiter The specified delimiter for the file. |
|||
* @param string $importid The id of the csv import. |
|||
* @param array $mappingdata The mapping data from the import form. |
|||
* @param bool $useprogressbar Whether progress bar should be displayed, to avoid html output on CLI. |
|||
*/ |
|||
public function __construct($text = null, $encoding = null, $delimiter = null, $importid = 0, |
|||
$mappingdata = null, $useprogressbar = false) { |
|||
global $CFG; |
|||
|
|||
require_once($CFG->libdir . '/csvlib.class.php'); |
|||
|
|||
$pluginconfig = get_config('attendance'); |
|||
|
|||
$type = 'sessions'; |
|||
|
|||
if (! $importid) { |
|||
if ($text === null) { |
|||
return; |
|||
} |
|||
$this->importid = csv_import_reader::get_new_iid($type); |
|||
|
|||
$this->importer = new csv_import_reader($this->importid, $type); |
|||
|
|||
if (! $this->importer->load_csv_content($text, $encoding, $delimiter)) { |
|||
$this->fail(get_string('invalidimportfile', 'attendance')); |
|||
$this->importer->cleanup(); |
|||
return; |
|||
} |
|||
} else { |
|||
$this->importid = $importid; |
|||
|
|||
$this->importer = new csv_import_reader($this->importid, $type); |
|||
} |
|||
|
|||
if (! $this->importer->init()) { |
|||
$this->fail(get_string('invalidimportfile', 'attendance')); |
|||
$this->importer->cleanup(); |
|||
return; |
|||
} |
|||
|
|||
$this->foundheaders = $this->importer->get_columns(); |
|||
$this->useprogressbar = $useprogressbar; |
|||
$domainid = 1; |
|||
|
|||
$sessions = array(); |
|||
|
|||
while ($row = $this->importer->next()) { |
|||
// This structure mimics what the UI form returns. |
|||
$mapping = $this->read_mapping_data($mappingdata); |
|||
|
|||
$session = new stdClass(); |
|||
$session->course = $this->get_column_data($row, $mapping['course']); |
|||
if (empty($session->course)) { |
|||
\mod_attendance_notifyqueue::notify_problem(get_string('error:sessioncourseinvalid', 'attendance')); |
|||
continue; |
|||
} |
|||
|
|||
// Handle multiple group assignments per session. Expect semicolon separated group names. |
|||
$groups = $this->get_column_data($row, $mapping['groups']); |
|||
if (! empty($groups)) { |
|||
$session->groups = explode(';', $groups); |
|||
$session->sessiontype = \mod_attendance_structure::SESSION_GROUP; |
|||
} else { |
|||
$session->sessiontype = \mod_attendance_structure::SESSION_COMMON; |
|||
} |
|||
|
|||
// Expect standardised date format, eg YYYY-MM-DD. |
|||
$sessiondate = strtotime($this->get_column_data($row, $mapping['sessiondate'])); |
|||
if ($sessiondate === false) { |
|||
\mod_attendance_notifyqueue::notify_problem(get_string('error:sessiondateinvalid', 'attendance')); |
|||
continue; |
|||
} |
|||
$session->sessiondate = $sessiondate; |
|||
|
|||
// Expect standardised time format, eg HH:MM. |
|||
$from = $this->get_column_data($row, $mapping['from']); |
|||
if (empty($from)) { |
|||
\mod_attendance_notifyqueue::notify_problem(get_string('error:sessionstartinvalid', 'attendance')); |
|||
continue; |
|||
} |
|||
$from = explode(':', $from); |
|||
$session->sestime['starthour'] = $from[0]; |
|||
$session->sestime['startminute'] = $from[1]; |
|||
|
|||
$to = $this->get_column_data($row, $mapping['to']); |
|||
if (empty($to)) { |
|||
\mod_attendance_notifyqueue::notify_problem(get_string('error:sessionendinvalid', 'attendance')); |
|||
continue; |
|||
} |
|||
$to = explode(':', $to); |
|||
$session->sestime['endhour'] = $to[0]; |
|||
$session->sestime['endminute'] = $to[1]; |
|||
|
|||
// Wrap the plain text description in html tags. |
|||
$session->sdescription['text'] = '<p>' . $this->get_column_data($row, $mapping['description']) . '</p>'; |
|||
$session->sdescription['format'] = FORMAT_HTML; |
|||
$session->sdescription['itemid'] = 0; |
|||
|
|||
$session->repeaton = $this->get_column_data($row, $mapping['repeaton']); |
|||
$session->repeatevery = $this->get_column_data($row, $mapping['repeatevery']); |
|||
$session->repeatuntil = $this->get_column_data($row, $mapping['repeatuntil']); |
|||
$session->passwordgrp = $this->get_column_data($row, $mapping['passwordgrp']); |
|||
$session->subnet = $this->get_column_data($row, $mapping['subnet']); |
|||
// Set session subnet restriction. Use the default activity level subnet if there isn't one set for this session. |
|||
if (empty($session->subnet)) { |
|||
$session->usedefaultsubnet = '1'; |
|||
} else { |
|||
$session->usedefaultsubnet = ''; |
|||
} |
|||
|
|||
if ($mapping['studentscanmark'] == -1) { |
|||
$session->studentscanmark = $pluginconfig->studentscanmark_default; |
|||
} else { |
|||
$session->studentscanmark = $this->get_column_data($row, $mapping['studentscanmark']); |
|||
} |
|||
if ($mapping['randompassword'] == -1) { |
|||
$session->randompassword = $pluginconfig->randompassword_default; |
|||
} else { |
|||
$session->randompassword = $this->get_column_data($row, $mapping['randompassword']); |
|||
} |
|||
if ($mapping['automark'] == -1) { |
|||
$session->automark = $pluginconfig->automark_default; |
|||
} else { |
|||
$session->automark = $this->get_column_data($row, $mapping['automark']); |
|||
} |
|||
if ($mapping['autoassignstatus'] == -1) { |
|||
$session->autoassignstatus = $pluginconfig->autoassignstatus; |
|||
} else { |
|||
$session->autoassignstatus = $this->get_column_data($row, $mapping['autoassignstatus']); |
|||
} |
|||
if ($mapping['absenteereport'] == -1) { |
|||
$session->absenteereport = $pluginconfig->absenteereport_default; |
|||
} else { |
|||
$session->absenteereport = $this->get_column_data($row, $mapping['absenteereport']); |
|||
} |
|||
if ($mapping['preventsharedip'] == -1) { |
|||
$session->preventsharedip = $pluginconfig->preventsharedip; |
|||
} else { |
|||
$session->preventsharedip = $this->get_column_data($row, $mapping['preventsharedip']); |
|||
} |
|||
if ($mapping['preventsharediptime'] == -1) { |
|||
$session->preventsharediptime = $pluginconfig->preventsharediptime; |
|||
} else { |
|||
$session->preventsharediptime = $this->get_column_data($row, $mapping['preventsharediptime']); |
|||
} |
|||
|
|||
$session->statusset = 0; |
|||
|
|||
$sessions[] = $session; |
|||
} |
|||
$this->sessions = $sessions; |
|||
|
|||
$this->importer->close(); |
|||
if ($this->sessions == null) { |
|||
$this->fail(get_string('invalidimportfile', 'attendance')); |
|||
return; |
|||
} else { |
|||
// We are calling from browser, display progress bar. |
|||
if ($this->useprogressbar === true) { |
|||
$this->progress = new \core\progress\display_if_slow(get_string('processingfile', 'attendance')); |
|||
$this->progress->start_html(); |
|||
} else { |
|||
// Avoid html output on CLI scripts. |
|||
$this->progress = new \core\progress\none(); |
|||
} |
|||
$this->progress->start_progress('', count($this->sessions)); |
|||
raise_memory_limit(MEMORY_EXTRA); |
|||
$this->progress->end_progress(); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Get parse errors. |
|||
* |
|||
* @return array of errors from parsing the xml. |
|||
*/ |
|||
public function get_error() { |
|||
return $this->error; |
|||
} |
|||
|
|||
/** |
|||
* Create sessions using the CSV data. |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function import() { |
|||
global $DB; |
|||
|
|||
// Count of sessions added. |
|||
$okcount = 0; |
|||
|
|||
foreach ($this->sessions as $session) { |
|||
$groupids = array(); |
|||
// Check course shortname matches. |
|||
if ($DB->record_exists('course', array( |
|||
'shortname' => $session->course |
|||
))) { |
|||
// Get course. |
|||
$course = $DB->get_record('course', array( |
|||
'shortname' => $session->course |
|||
), '*', MUST_EXIST); |
|||
|
|||
// Check course has activities. |
|||
if ($DB->record_exists('attendance', array( |
|||
'course' => $course->id |
|||
))) { |
|||
// Translate group names to group IDs. They are unique per course. |
|||
if ($session->sessiontype === \mod_attendance_structure::SESSION_GROUP) { |
|||
foreach ($session->groups as $groupname) { |
|||
$gid = groups_get_group_by_name($course->id, $groupname); |
|||
if ($gid === false) { |
|||
\mod_attendance_notifyqueue::notify_problem(get_string('sessionunknowngroup', |
|||
'attendance', $groupname)); |
|||
} else { |
|||
$groupids[] = $gid; |
|||
} |
|||
} |
|||
$session->groups = $groupids; |
|||
} |
|||
|
|||
// Get activities in course. |
|||
$activities = $DB->get_recordset('attendance', array( |
|||
'course' => $course->id |
|||
), 'id', 'id'); |
|||
|
|||
foreach ($activities as $activity) { |
|||
// Build the session data. |
|||
$cm = get_coursemodule_from_instance('attendance', $activity->id, $course->id); |
|||
if (!empty($cm->deletioninprogress)) { |
|||
// Don't do anything if this attendance is in recycle bin. |
|||
continue; |
|||
} |
|||
$att = new mod_attendance_structure($activity, $cm, $course); |
|||
$sessions = attendance_construct_sessions_data_for_add($session, $att); |
|||
|
|||
foreach ($sessions as $index => $sess) { |
|||
// Check for duplicate sessions. |
|||
if ($this->session_exists($sess)) { |
|||
mod_attendance_notifyqueue::notify_message(get_string('sessionduplicate', 'attendance', (array( |
|||
'course' => $session->course, |
|||
'activity' => $cm->name |
|||
)))); |
|||
unset($sessions[$index]); |
|||
} else { |
|||
$okcount ++; |
|||
} |
|||
} |
|||
if (! empty($sessions)) { |
|||
$att->add_sessions($sessions); |
|||
} |
|||
} |
|||
$activities->close(); |
|||
} else { |
|||
mod_attendance_notifyqueue::notify_problem(get_string('error:coursehasnoattendance', |
|||
'attendance', $session->course)); |
|||
} |
|||
} else { |
|||
mod_attendance_notifyqueue::notify_problem(get_string('error:coursenotfound', 'attendance', $session->course)); |
|||
} |
|||
} |
|||
|
|||
$message = get_string('sessionsgenerated', 'attendance', $okcount); |
|||
if ($okcount < 1) { |
|||
mod_attendance_notifyqueue::notify_message($message); |
|||
} else { |
|||
mod_attendance_notifyqueue::notify_success($message); |
|||
} |
|||
|
|||
// Trigger a sessions imported event. |
|||
$event = \mod_attendance\event\sessions_imported::create(array( |
|||
'objectid' => 0, |
|||
'context' => \context_system::instance(), |
|||
'other' => array( |
|||
'count' => $okcount |
|||
) |
|||
)); |
|||
|
|||
$event->trigger(); |
|||
} |
|||
|
|||
/** |
|||
* Check if an identical session exists. |
|||
* |
|||
* @param stdClass $session |
|||
* @return boolean |
|||
*/ |
|||
private function session_exists(stdClass $session) { |
|||
global $DB; |
|||
|
|||
$check = clone $session; |
|||
|
|||
// Remove the properties that aren't useful to check. |
|||
unset($check->description); |
|||
unset($check->descriptionitemid); |
|||
unset($check->timemodified); |
|||
$check = (array) $check; |
|||
|
|||
if ($DB->record_exists('attendance_sessions', $check)) { |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
} |
@ -0,0 +1,57 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Event observers supported by this module |
|||
* |
|||
* @package mod_attendance |
|||
* @copyright 2017 Dan Marsden |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
defined('MOODLE_INTERNAL') || die(); |
|||
|
|||
/** |
|||
* Event observers supported by this module |
|||
* |
|||
* @package mod_attendance |
|||
* @copyright 2017 Dan Marsden |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
class mod_attendance_observer { |
|||
|
|||
/** |
|||
* Observer for the event course_content_deleted - delete all attendance stuff. |
|||
* |
|||
* @param \core\event\course_content_deleted $event |
|||
*/ |
|||
public static function course_content_deleted(\core\event\course_content_deleted $event) { |
|||
global $DB; |
|||
|
|||
$attids = array_keys($DB->get_records('attendance', array('course' => $event->objectid), '', 'id')); |
|||
$sessids = array_keys($DB->get_records_list('attendance_sessions', 'attendanceid', $attids, '', 'id')); |
|||
if (attendance_existing_calendar_events_ids($sessids)) { |
|||
attendance_delete_calendar_events($sessids); |
|||
} |
|||
if ($sessids) { |
|||
$DB->delete_records_list('attendance_log', 'sessionid', $sessids); |
|||
} |
|||
if ($attids) { |
|||
$DB->delete_records_list('attendance_statuses', 'attendanceid', $attids); |
|||
$DB->delete_records_list('attendance_sessions', 'attendanceid', $attids); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,230 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Attendance task - auto mark. |
|||
* |
|||
* @package mod_attendance |
|||
* @copyright 2017 onwards Dan Marsden http://danmarsden.com |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
namespace mod_attendance\task; |
|||
defined('MOODLE_INTERNAL') || die(); |
|||
|
|||
require_once($CFG->dirroot . '/mod/attendance/locallib.php'); |
|||
/** |
|||
* get_scores class, used to get scores for submitted files. |
|||
* |
|||
* @package mod_attendance |
|||
* @copyright 2017 onwards Dan Marsden http://danmarsden.com |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
class auto_mark extends \core\task\scheduled_task { |
|||
/** |
|||
* Returns localised general event name. |
|||
* |
|||
* @return string |
|||
*/ |
|||
public function get_name() { |
|||
// Shown in admin screens. |
|||
return get_string('automarktask', 'mod_attendance'); |
|||
} |
|||
|
|||
/** |
|||
* Execte the task. |
|||
*/ |
|||
public function execute() { |
|||
global $DB; |
|||
// Create some cache vars - might be nice to restructure this and make a smaller number of sql calls. |
|||
$cachecm = array(); |
|||
$cacheatt = array(); |
|||
$cachecourse = array(); |
|||
$now = time(); // Store current time to use in queries so they all match nicely. |
|||
|
|||
$sessions = $DB->get_recordset_select('attendance_sessions', |
|||
'automark > 0 AND automarkcompleted < 2 AND sessdate < ? ', array($now)); |
|||
|
|||
foreach ($sessions as $session) { |
|||
if ($session->sessdate + $session->duration < $now || // If session is over. |
|||
// OR if session is currently open and automark is set to do all. |
|||
($session->sessdate < $now && $session->automark == 1)) { |
|||
|
|||
$userfirstaccess = array(); |
|||
$donesomething = false; // Only trigger grades/events when an update actually occurs. |
|||
$sessionover = false; // Is this session over? |
|||
if ($session->sessdate + $session->duration < $now) { |
|||
$sessionover = true; |
|||
} |
|||
|
|||
// Store cm/att/course in cachefields so we don't make unnecessary db calls. |
|||
// Would probably be nice to grab this stuff outside of the loop. |
|||
// Make sure this status set has something to setunmarked. |
|||
$setunmarked = $DB->get_field('attendance_statuses', 'id', |
|||
array('attendanceid' => $session->attendanceid, 'setnumber' => $session->statusset, |
|||
'setunmarked' => 1, 'deleted' => 0)); |
|||
if (empty($setunmarked)) { |
|||
mtrace("No unmarked status configured for session id: ".$session->id); |
|||
continue; |
|||
} |
|||
if (empty($cacheatt[$session->attendanceid])) { |
|||
$cacheatt[$session->attendanceid] = $DB->get_record('attendance', array('id' => $session->attendanceid)); |
|||
} |
|||
if (empty($cachecm[$session->attendanceid])) { |
|||
$cachecm[$session->attendanceid] = get_coursemodule_from_instance('attendance', |
|||
$session->attendanceid, $cacheatt[$session->attendanceid]->course); |
|||
} |
|||
$courseid = $cacheatt[$session->attendanceid]->course; |
|||
if (empty($cachecourse[$courseid])) { |
|||
$cachecourse[$courseid] = $DB->get_record('course', array('id' => $courseid)); |
|||
} |
|||
$context = \context_module::instance($cachecm[$session->attendanceid]->id); |
|||
|
|||
$pageparams = new \mod_attendance_take_page_params(); |
|||
$pageparams->group = $session->groupid; |
|||
if (empty($session->groupid)) { |
|||
$pageparams->grouptype = 0; |
|||
} else { |
|||
$pageparams->grouptype = 1; |
|||
} |
|||
$pageparams->sessionid = $session->id; |
|||
|
|||
if ($session->automark == 1) { |
|||
$userfirstacess = array(); |
|||
// If set to do full automarking, get all users that have accessed course during session open. |
|||
$id = $DB->sql_concat('userid', 'ip'); // Users may access from multiple ip, make the first field unique. |
|||
$sql = "SELECT $id, userid, ip, min(timecreated) as timecreated |
|||
FROM {logstore_standard_log} |
|||
WHERE courseid = ? AND timecreated > ? AND timecreated < ? |
|||
GROUP BY userid, ip"; |
|||
|
|||
$timestart = $session->sessdate; |
|||
if (empty($session->lasttakenby) && $session->lasttaken > $timestart) { |
|||
// If the last time session was taken it was done automatically, use the last time taken |
|||
// as the start time for the logs we are interested in to help with performance. |
|||
$timestart = $session->lasttaken; |
|||
} |
|||
$duration = $session->duration; |
|||
if (empty($duration)) { |
|||
$duration = get_config('attendance', 'studentscanmarksessiontimeend') * 60; |
|||
} |
|||
$timeend = $timestart + $duration; |
|||
$logusers = $DB->get_recordset_sql($sql, array($courseid, $timestart, $timeend)); |
|||
// Check if user access is in allowed subnet. |
|||
foreach ($logusers as $loguser) { |
|||
if (!empty($session->subnet) && !address_in_subnet($loguser->ip, $session->subnet)) { |
|||
// This record isn't in the right subnet. |
|||
continue; |
|||
} |
|||
if (empty($userfirstaccess[$loguser->userid]) || |
|||
$userfirstaccess[$loguser->userid] > $loguser->timecreated) { |
|||
// Users may have accessed from mulitple ip addresses, find the earliest access. |
|||
$userfirstaccess[$loguser->userid] = $loguser->timecreated; |
|||
} |
|||
} |
|||
$logusers->close(); |
|||
} |
|||
|
|||
// Get all unmarked students. |
|||
$att = new \mod_attendance_structure($cacheatt[$session->attendanceid], |
|||
$cachecm[$session->attendanceid], $cachecourse[$courseid], $context, $pageparams); |
|||
|
|||
$users = $att->get_users($session->groupid, 0); |
|||
|
|||
$existinglog = $DB->get_recordset('attendance_log', array('sessionid' => $session->id)); |
|||
$updated = 0; |
|||
|
|||
foreach ($existinglog as $log) { |
|||
if (empty($log->statusid)) { |
|||
if ($sessionover || !empty($userfirstaccess[$log->studentid])) { |
|||
// Status needs updating. |
|||
if ($sessionover) { |
|||
$log->statusid = $setunmarked; |
|||
} else if (!empty($userfirstaccess[$log->studentid])) { |
|||
$log->statusid = $att->get_automark_status($userfirstaccess[$log->studentid], $session->id); |
|||
} |
|||
if (!empty($log->statusid)) { |
|||
$log->timetaken = $now; |
|||
$log->takenby = 0; |
|||
$log->remarks = get_string('autorecorded', 'attendance'); |
|||
|
|||
$DB->update_record('attendance_log', $log); |
|||
$updated++; |
|||
$donesomething = true; |
|||
} |
|||
} |
|||
} |
|||
unset($users[$log->studentid]); |
|||
} |
|||
$existinglog->close(); |
|||
mtrace($updated . " session status updated"); |
|||
|
|||
$newlog = new \stdClass(); |
|||
$newlog->timetaken = $now; |
|||
$newlog->takenby = 0; |
|||
$newlog->sessionid = $session->id; |
|||
$newlog->remarks = get_string('autorecorded', 'attendance'); |
|||
$newlog->statusset = implode(',', array_keys( (array)$att->get_statuses())); |
|||
|
|||
$added = 0; |
|||
foreach ($users as $user) { |
|||
if ($sessionover || !empty($userfirstaccess[$user->id])) { |
|||
if ($sessionover) { |
|||
$newlog->statusid = $setunmarked; |
|||
} else if (!empty($userfirstaccess[$user->id])) { |
|||
$newlog->statusid = $att->get_automark_status($userfirstaccess[$user->id], $session->id); |
|||
} |
|||
if (!empty($newlog->statusid)) { |
|||
$newlog->studentid = $user->id; |
|||
$DB->insert_record('attendance_log', $newlog); |
|||
$added++; |
|||
$donesomething = true; |
|||
} |
|||
} |
|||
} |
|||
mtrace($added . " session status inserted"); |
|||
|
|||
// Update lasttaken time and automarkcompleted for this session. |
|||
$session->lasttaken = $now; |
|||
$session->lasttakenby = 0; |
|||
if ($sessionover) { |
|||
$session->automarkcompleted = 2; |
|||
} else { |
|||
$session->automarkcompleted = 1; |
|||
} |
|||
|
|||
$DB->update_record('attendance_sessions', $session); |
|||
|
|||
if ($donesomething) { |
|||
if ($att->grade != 0) { |
|||
$att->update_users_grade(array_keys($users)); |
|||
} |
|||
|
|||
$params = array( |
|||
'sessionid' => $att->pageparams->sessionid, |
|||
'grouptype' => $att->pageparams->grouptype); |
|||
$event = \mod_attendance\event\attendance_taken::create(array( |
|||
'objectid' => $att->id, |
|||
'context' => $att->context, |
|||
'other' => $params)); |
|||
$event->add_record_snapshot('course_modules', $att->cm); |
|||
$event->add_record_snapshot('attendance_sessions', $session); |
|||
$event->trigger(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,158 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Attendance task - Send warnings. |
|||
* |
|||
* @package mod_attendance |
|||
* @copyright 2017 onwards Dan Marsden http://danmarsden.com |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
namespace mod_attendance\task; |
|||
defined('MOODLE_INTERNAL') || die(); |
|||
|
|||
require_once($CFG->dirroot . '/mod/attendance/locallib.php'); |
|||
/** |
|||
* Task class |
|||
* |
|||
* @package mod_attendance |
|||
* @copyright 2017 onwards Dan Marsden http://danmarsden.com |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
class notify extends \core\task\scheduled_task { |
|||
/** |
|||
* Returns localised general event name. |
|||
* |
|||
* @return string |
|||
*/ |
|||
public function get_name() { |
|||
// Shown in admin screens. |
|||
return get_string('notifytask', 'mod_attendance'); |
|||
} |
|||
|
|||
/** |
|||
* Execute the task. |
|||
*/ |
|||
public function execute() { |
|||
global $DB; |
|||
if (empty(get_config('attendance', 'enablewarnings'))) { |
|||
return; // Warnings not enabled. |
|||
} |
|||
$now = time(); // Store current time to use in queries so they all match nicely. |
|||
|
|||
$orderby = 'ORDER BY cm.id, atl.studentid, n.warningpercent ASC'; |
|||
|
|||
// Get records for attendance sessions that have been updated since last time this task ran. |
|||
// Note: this returns all users for these sessions - even if the users attendance wasn't changed |
|||
// since last time we ran, before sending a notification we check to see if the users have |
|||
// updated attendance logs since last time they were notified. |
|||
$records = attendance_get_users_to_notify(array(), $orderby, true); |
|||
$sentnotifications = array(); |
|||
$thirdpartynotifications = array(); |
|||
$numsentusers = 0; |
|||
$numsentthird = 0; |
|||
foreach ($records as $record) { |
|||
if (empty($sentnotifications[$record->userid])) { |
|||
$sentnotifications[$record->userid] = array(); |
|||
} |
|||
|
|||
if (!empty($record->emailuser)) { |
|||
// Only send one warning to this user from each attendance in this run. |
|||
// Flag any higher percent notifications as sent. |
|||
if (empty($sentnotifications[$record->userid]) || !in_array($record->aid, $sentnotifications[$record->userid])) { |
|||
|
|||
// If has previously been sent a warning, check to see if this user has |
|||
// attendance updated since the last time the notification was sent. |
|||
if (!empty($record->timesent)) { |
|||
$sql = "SELECT * |
|||
FROM {attendance_log} l |
|||
JOIN {attendance_sessions} s ON s.id = l.sessionid |
|||
WHERE s.attendanceid = ? AND studentid = ? AND timetaken > ?"; |
|||
if (!$DB->record_exists_sql($sql, array($record->aid, $record->userid, $record->timesent))) { |
|||
continue; // Skip this record and move to the next user. |
|||
} |
|||
} |
|||
|
|||
// Convert variables in emailcontent. |
|||
$record = attendance_template_variables($record); |
|||
$user = $DB->get_record('user', array('id' => $record->userid)); |
|||
$from = \core_user::get_noreply_user(); |
|||
$oldforcelang = force_current_language($user->lang); |
|||
|
|||
$emailcontent = format_text($record->emailcontent, $record->emailcontentformat); |
|||
$emailsubject = format_text($record->emailsubject, FORMAT_HTML); |
|||
email_to_user($user, $from, $emailsubject, $emailcontent, $emailcontent); |
|||
|
|||
force_current_language($oldforcelang); |
|||
$sentnotifications[$record->userid][] = $record->aid; |
|||
$numsentusers++; |
|||
} |
|||
} |
|||
// Only send one warning to this user from each attendance in this run. - flag any higher percent notifications as sent. |
|||
if (!empty($record->thirdpartyemails)) { |
|||
$sendto = explode(',', $record->thirdpartyemails); |
|||
$record->percent = round($record->percent * 100)."%"; |
|||
$context = \context_module::instance($record->cmid); |
|||
foreach ($sendto as $senduser) { |
|||
if (empty($senduser)) { |
|||
// Probably an extra comma in the thirdpartyusers field. |
|||
continue; |
|||
} |
|||
// Check user is allowed to receive warningemails. |
|||
if (has_capability('mod/attendance:warningemails', $context, $senduser)) { |
|||
if (empty($thirdpartynotifications[$senduser])) { |
|||
$thirdpartynotifications[$senduser] = array(); |
|||
} |
|||
if (!isset($thirdpartynotifications[$senduser][$record->aid . '_' . $record->userid])) { |
|||
$thirdpartynotifications[$senduser][$record->aid . '_' . $record->userid] |
|||
= get_string('thirdpartyemailtext', 'attendance', $record); |
|||
} |
|||
} else { |
|||
mtrace("user".$senduser. "does not have capablity in cm".$record->cmid); |
|||
} |
|||
} |
|||
} |
|||
$notify = new \stdClass(); |
|||
$notify->userid = $record->userid; |
|||
$notify->notifyid = $record->notifyid; |
|||
$notify->timesent = $now; |
|||
$DB->insert_record('attendance_warning_done', $notify); |
|||
} |
|||
if (!empty($numsentusers)) { |
|||
mtrace($numsentusers ." user emails sent"); |
|||
} |
|||
if (!empty($thirdpartynotifications)) { |
|||
foreach ($thirdpartynotifications as $sendid => $notifications) { |
|||
$user = $DB->get_record('user', array('id' => $sendid)); |
|||
$from = \core_user::get_noreply_user(); |
|||
$oldforcelang = force_current_language($user->lang); |
|||
|
|||
$emailcontent = implode("\n", $notifications); |
|||
$emailcontent .= "\n\n".get_string('thirdpartyemailtextfooter', 'attendance'); |
|||
$emailcontent = format_text($emailcontent); |
|||
$emailsubject = get_string('thirdpartyemailsubject', 'attendance'); |
|||
|
|||
email_to_user($user, $from, $emailsubject, $emailcontent, $emailcontent); |
|||
force_current_language($oldforcelang); |
|||
$numsentthird++; |
|||
} |
|||
if (!empty($numsentthird)) { |
|||
mtrace($numsentthird ." thirdparty emails sent"); |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,124 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Attendance course summary report. |
|||
* |
|||
* @package mod_attendance |
|||
* @copyright 2017 onwards Dan Marsden http://danmarsden.com |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
require_once('../../config.php'); |
|||
require_once($CFG->libdir.'/adminlib.php'); |
|||
require_once($CFG->dirroot.'/mod/attendance/lib.php'); |
|||
require_once($CFG->dirroot.'/mod/attendance/locallib.php'); |
|||
require_once($CFG->libdir.'/tablelib.php'); |
|||
require_once($CFG->libdir.'/coursecatlib.php'); |
|||
|
|||
$category = optional_param('category', 0, PARAM_INT); |
|||
$download = optional_param('download', '', PARAM_ALPHA); |
|||
$sort = optional_param('tsort', '', PARAM_ALPHA); |
|||
$fromcourse = optional_param('fromcourse', 0, PARAM_INT); |
|||
|
|||
$admin = false; |
|||
if (empty($fromcourse)) { |
|||
$admin = true; |
|||
admin_externalpage_setup('managemodules'); |
|||
} else { |
|||
require_login($fromcourse); |
|||
} |
|||
|
|||
if (empty($category)) { |
|||
$context = context_system::instance(); |
|||
$courses = array(); // Show all courses. |
|||
} else { |
|||
$context = context_coursecat::instance($category); |
|||
$coursecat = coursecat::get($category); |
|||
$courses = $coursecat->get_courses(array('recursive' => true, 'idonly' => true)); |
|||
} |
|||
// Check permissions. |
|||
require_capability('mod/attendance:viewsummaryreports', $context); |
|||
|
|||
$exportfilename = 'attendancecoursesummary.csv'; |
|||
|
|||
$PAGE->set_url('/mod/attendance/coursesummary.php', array('category' => $category)); |
|||
|
|||
$PAGE->set_heading($SITE->fullname); |
|||
|
|||
$table = new flexible_table('attendancecoursesummary'); |
|||
$table->define_baseurl($PAGE->url); |
|||
|
|||
if (!$table->is_downloading($download, $exportfilename)) { |
|||
echo $OUTPUT->header(); |
|||
$heading = get_string('coursesummary', 'mod_attendance'); |
|||
if (!empty($category)) { |
|||
$heading .= " (".$coursecat->name.")"; |
|||
} |
|||
echo $OUTPUT->heading($heading); |
|||
if ($admin) { |
|||
// Only show tabs if displaying via the admin page. |
|||
$tabmenu = attendance_print_settings_tabs('coursesummary'); |
|||
echo $tabmenu; |
|||
} |
|||
$url = new moodle_url('/mod/attendance/coursesummary.php', array('category' => $category, 'fromcourse' => $fromcourse)); |
|||
|
|||
if ($admin) { |
|||
$options = coursecat::make_categories_list('mod/attendance:viewsummaryreports'); |
|||
echo $OUTPUT->single_select($url, 'category', $options, $category); |
|||
} |
|||
|
|||
} |
|||
|
|||
$table->define_columns(array('course', 'percentage')); |
|||
$table->define_headers(array(get_string('course'), |
|||
get_string('averageattendance', 'attendance'))); |
|||
$table->sortable(true); |
|||
$table->no_sorting('course'); |
|||
$table->set_attribute('cellspacing', '0'); |
|||
$table->set_attribute('class', 'generaltable generalbox'); |
|||
$table->show_download_buttons_at(array(TABLE_P_BOTTOM)); |
|||
$table->setup(); |
|||
|
|||
// Work out direction of sort required. |
|||
$sortcolumns = $table->get_sort_columns(); |
|||
// Now do sorting if specified. |
|||
|
|||
$orderby = ' ORDER BY percentage ASC'; |
|||
if (!empty($sort)) { |
|||
$direction = ' DESC'; |
|||
if (!empty($sortcolumns[$sort]) && $sortcolumns[$sort] == SORT_ASC) { |
|||
$direction = ' ASC'; |
|||
} |
|||
$orderby = " ORDER BY $sort $direction"; |
|||
|
|||
} |
|||
|
|||
$records = attendance_course_users_points($courses, $orderby); |
|||
foreach ($records as $record) { |
|||
if (!$table->is_downloading($download, $exportfilename)) { |
|||
$url = new moodle_url('/mod/attendance/index.php', array('id' => $record->courseid)); |
|||
$name = html_writer::link($url, $record->coursename); |
|||
} else { |
|||
$name = $record->coursename; |
|||
} |
|||
$table->add_data(array($name, round($record->percentage * 100)."%")); |
|||
} |
|||
$table->finish_output(); |
|||
|
|||
if (!$table->is_downloading()) { |
|||
echo $OUTPUT->footer(); |
|||
} |
@ -0,0 +1,36 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Attendance event handler definition. |
|||
* |
|||
* @package mod_attendance |
|||
* @category event |
|||
* @copyright 2017 Dan Marsden |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
defined('MOODLE_INTERNAL') || die(); |
|||
|
|||
// List of observers. |
|||
$observers = array( |
|||
|
|||
array( |
|||
'eventname' => '\core\event\course_content_deleted', |
|||
'callback' => 'mod_attendance_observer::course_content_deleted', |
|||
), |
|||
|
|||
); |
@ -0,0 +1,44 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Attendance module tasks. |
|||
* |
|||
* @package mod_attendance |
|||
* @copyright 2017 Dan Marsden |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
defined('MOODLE_INTERNAL') || die(); |
|||
|
|||
$tasks = array( |
|||
array( |
|||
'classname' => 'mod_attendance\task\auto_mark', |
|||
'blocking' => 0, |
|||
'minute' => '8', |
|||
'hour' => '*', |
|||
'day' => '*', |
|||
'dayofweek' => '*', |
|||
'month' => '*'), |
|||
array( |
|||
'classname' => 'mod_attendance\task\notify', |
|||
'blocking' => 0, |
|||
'minute' => '30', |
|||
'hour' => '1', |
|||
'day' => '*', |
|||
'dayofweek' => '*', |
|||
'month' => '*') |
|||
); |
@ -0,0 +1,131 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Allows default status set to be modified. |
|||
* |
|||
* @package mod_attendance |
|||
* @copyright 2017 Dan Marsden http://danmarsden.com |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
|
|||
require_once(__DIR__.'/../../config.php'); |
|||
require_once($CFG->libdir.'/adminlib.php'); |
|||
require_once($CFG->dirroot.'/mod/attendance/lib.php'); |
|||
require_once($CFG->dirroot.'/mod/attendance/locallib.php'); |
|||
|
|||
$action = optional_param('action', null, PARAM_INT); |
|||
$statusid = optional_param('statusid', null, PARAM_INT); |
|||
admin_externalpage_setup('managemodules'); |
|||
$url = new moodle_url('/mod/attendance/defaultstatus.php', array('statusid' => $statusid, 'action' => $action)); |
|||
|
|||
// Check sesskey if we are performing an action. |
|||
if (!empty($action)) { |
|||
require_sesskey(); |
|||
} |
|||
|
|||
$output = $PAGE->get_renderer('mod_attendance'); |
|||
echo $OUTPUT->header(); |
|||
echo $OUTPUT->heading(get_string('defaultstatus', 'mod_attendance')); |
|||
$tabmenu = attendance_print_settings_tabs('defaultstatus'); |
|||
echo $tabmenu; |
|||
|
|||
// TODO: Would be good to combine this code block with the one in preferences to avoid duplication. |
|||
$errors = array(); |
|||
switch ($action) { |
|||
case mod_attendance_preferences_page_params::ACTION_ADD: |
|||
$newacronym = optional_param('newacronym', null, PARAM_TEXT); |
|||
$newdescription = optional_param('newdescription', null, PARAM_TEXT); |
|||
$newgrade = optional_param('newgrade', 0, PARAM_RAW); |
|||
$newstudentavailability = optional_param('newstudentavailability', null, PARAM_INT); |
|||
$newgrade = unformat_float($newgrade); |
|||
|
|||
// Default value uses setnumber/attendanceid = 0. |
|||
$status = new stdClass(); |
|||
$status->attendanceid = 0; |
|||
$status->acronym = $newacronym; |
|||
$status->description = $newdescription; |
|||
$status->grade = $newgrade; |
|||
$status->studentavailability = $newstudentavailability; |
|||
$status->setnumber = 0; |
|||
attendance_add_status($status); |
|||
|
|||
break; |
|||
case mod_attendance_preferences_page_params::ACTION_DELETE: |
|||
$confirm = optional_param('confirm', null, PARAM_INT); |
|||
$statuses = attendance_get_statuses(0, false); |
|||
$status = $statuses[$statusid]; |
|||
|
|||
if (isset($confirm)) { |
|||
attendance_remove_status($status); |
|||
echo $OUTPUT->notification(get_string('statusdeleted', 'attendance'), 'success'); |
|||
break; |
|||
} |
|||
|
|||
$message = get_string('deletecheckfull', '', get_string('variable', 'attendance')); |
|||
$message .= str_repeat(html_writer::empty_tag('br'), 2); |
|||
$message .= $status->acronym.': '. |
|||
($status->description ? $status->description : get_string('nodescription', 'attendance')); |
|||
$confirmurl = $url; |
|||
$confirmurl->param('confirm', 1); |
|||
|
|||
echo $OUTPUT->confirm($message, $confirmurl, $url); |
|||
echo $OUTPUT->footer(); |
|||
exit; |
|||
case mod_attendance_preferences_page_params::ACTION_HIDE: |
|||
$statuses = attendance_get_statuses(0, false); |
|||
$status = $statuses[$statusid]; |
|||
attendance_update_status($status, null, null, null, 0); |
|||
break; |
|||
case mod_attendance_preferences_page_params::ACTION_SHOW: |
|||
$statuses = attendance_get_statuses(0, false); |
|||
$status = $statuses[$statusid]; |
|||
attendance_update_status($status, null, null, null, 1); |
|||
break; |
|||
case mod_attendance_preferences_page_params::ACTION_SAVE: |
|||
$acronym = required_param_array('acronym', PARAM_TEXT); |
|||
$description = required_param_array('description', PARAM_TEXT); |
|||
$grade = required_param_array('grade', PARAM_RAW); |
|||
$studentavailability = optional_param_array('studentavailability', '0', PARAM_RAW); |
|||
$unmarkedstatus = optional_param('setunmarked', null, PARAM_INT); |
|||
foreach ($grade as &$val) { |
|||
$val = unformat_float($val); |
|||
} |
|||
$statuses = attendance_get_statuses(0, false); |
|||
|
|||
foreach ($acronym as $id => $v) { |
|||
$status = $statuses[$id]; |
|||
$setunmarked = false; |
|||
if ($unmarkedstatus == $id) { |
|||
$setunmarked = true; |
|||
} |
|||
if (!isset($studentavailability[$id]) || !is_numeric($studentavailability[$id])) { |
|||
$studentavailability[$id] = 0; |
|||
} |
|||
$errors[$id] = attendance_update_status($status, $acronym[$id], $description[$id], $grade[$id], |
|||
null, null, null, $studentavailability[$id], $setunmarked); |
|||
} |
|||
echo $OUTPUT->notification(get_string('eventstatusupdated', 'attendance'), 'success'); |
|||
|
|||
break; |
|||
} |
|||
|
|||
$statuses = attendance_get_statuses(0, false); |
|||
$prefdata = new attendance_default_statusset($statuses, $errors); |
|||
echo $output->render($prefdata); |
|||
|
|||
echo $OUTPUT->footer(); |
@ -0,0 +1,94 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Import attendance sessions. |
|||
* |
|||
* @package mod_attendance |
|||
* @author Chris Wharton <chriswharton@catalyst.net.nz> |
|||
* @copyright 2017 Catalyst IT |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
define('NO_OUTPUT_BUFFERING', true); |
|||
|
|||
require_once(__DIR__ . '/../../../config.php'); |
|||
require_once($CFG->libdir . '/adminlib.php'); |
|||
require_once($CFG->dirroot . '/mod/attendance/lib.php'); |
|||
require_once($CFG->dirroot . '/mod/attendance/locallib.php'); |
|||
|
|||
admin_externalpage_setup('managemodules'); |
|||
$pagetitle = get_string('importsessions', 'attendance'); |
|||
|
|||
$context = context_system::instance(); |
|||
|
|||
$url = new moodle_url('/mod/attendance/import/sessions.php'); |
|||
|
|||
$PAGE->set_context($context); |
|||
$PAGE->set_url($url); |
|||
$PAGE->set_title($pagetitle); |
|||
$PAGE->set_pagelayout('admin'); |
|||
$PAGE->set_heading($pagetitle); |
|||
|
|||
echo $OUTPUT->header(); |
|||
echo $OUTPUT->heading(get_string('importsessions', 'attendance')); |
|||
$tabmenu = attendance_print_settings_tabs('importsessions'); |
|||
echo $tabmenu; |
|||
|
|||
$form = null; |
|||
if (optional_param('needsconfirm', 0, PARAM_BOOL)) { |
|||
$form = new \mod_attendance\form\import\sessions($url->out(false)); |
|||
} else if (optional_param('confirm', 0, PARAM_BOOL)) { |
|||
$importer = new \mod_attendance\import\sessions(); |
|||
$form = new \mod_attendance\form\import\sessions_confirm(null, $importer); |
|||
} else { |
|||
$form = new \mod_attendance\form\import\sessions($url->out(false)); |
|||
} |
|||
|
|||
if ($form->is_cancelled()) { |
|||
$form = new \mod_attendance\form\import\sessions($url->out(false)); |
|||
} else if ($data = $form->get_data()) { |
|||
require_sesskey(); |
|||
if ($data->confirm) { |
|||
$importid = $data->importid; |
|||
$importer = new \mod_attendance\import\sessions(null, null, null, $importid, $data, true); |
|||
|
|||
$error = $importer->get_error(); |
|||
if ($error) { |
|||
$form = new \mod_attendance\form\import\sessions($url->out(false)); |
|||
$form->set_import_error($error); |
|||
} else { |
|||
$sessions = $importer->import(); |
|||
mod_attendance_notifyqueue::show(); |
|||
echo $OUTPUT->continue_button($url); |
|||
die(); |
|||
} |
|||
} else { |
|||
$text = $form->get_file_content('importfile'); |
|||
$encoding = $data->encoding; |
|||
$delimiter = $data->delimiter_name; |
|||
$importer = new \mod_attendance\import\sessions($text, $encoding, $delimiter, 0, null, true); |
|||
$confirmform = new \mod_attendance\form\import\sessions_confirm(null, $importer); |
|||
$form = $confirmform; |
|||
$pagetitle = get_string('confirmcolumnmappings', 'attendance'); |
|||
} |
|||
} |
|||
|
|||
echo $OUTPUT->heading($pagetitle); |
|||
|
|||
$form->display(); |
|||
|
|||
echo $OUTPUT->footer(); |
@ -0,0 +1,51 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Displays help via AJAX call or in a new page |
|||
* |
|||
* Use {@link core_renderer::help_icon()} or {@link addHelpButton()} to display |
|||
* the help icon. |
|||
* |
|||
* @copyright 2017 Dan Marsden |
|||
* @package mod_attendance |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
require_once(dirname(__FILE__).'/../../config.php'); |
|||
|
|||
$session = required_param('session', PARAM_INT); |
|||
$session = $DB->get_record('attendance_sessions', array('id' => $session), '*', MUST_EXIST); |
|||
|
|||
$cm = get_coursemodule_from_instance('attendance', $session->attendanceid); |
|||
require_login($cm->course, $cm); |
|||
|
|||
$context = context_module::instance($cm->id); |
|||
$capabilities = array('mod/attendance:manageattendances', 'mod/attendance:takeattendances', 'mod/attendance:changeattendances'); |
|||
if (!has_any_capability($capabilities, $context)) { |
|||
exit; |
|||
} |
|||
|
|||
$PAGE->set_url('/mod/attendance/password.php'); |
|||
$PAGE->set_pagelayout('popup'); |
|||
|
|||
$PAGE->set_context(context_system::instance()); |
|||
|
|||
$PAGE->set_title(get_string('password', 'attendance')); |
|||
|
|||
echo $OUTPUT->header(); |
|||
echo html_writer::span($session->studentpassword, 'student-password'); |
|||
echo $OUTPUT->footer(); |
@ -0,0 +1,50 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Displays help via AJAX call or in a new page |
|||
* |
|||
* Use {@link core_renderer::help_icon()} or {@link addHelpButton()} to display |
|||
* the help icon. |
|||
* |
|||
* @copyright 2017 Dan Marsden |
|||
* @package mod_attendance |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
define('AJAX_SCRIPT', true); |
|||
require_once(dirname(__FILE__).'/../../config.php'); |
|||
|
|||
$session = required_param('session', PARAM_INT); |
|||
$session = $DB->get_record('attendance_sessions', array('id' => $session), '*', MUST_EXIST); |
|||
|
|||
$cm = get_coursemodule_from_instance('attendance', $session->attendanceid); |
|||
require_login($cm->course, $cm); |
|||
|
|||
$context = context_module::instance($cm->id); |
|||
$capabilities = array('mod/attendance:manageattendances', 'mod/attendance:takeattendances', 'mod/attendance:changeattendances'); |
|||
if (!has_any_capability($capabilities, $context)) { |
|||
exit; |
|||
} |
|||
|
|||
$PAGE->set_url('/mod/attendance/password.php'); |
|||
$PAGE->set_pagelayout('popup'); |
|||
|
|||
$PAGE->set_context(context_system::instance()); |
|||
|
|||
$data->heading = ''; |
|||
$data->text = html_writer::span($session->studentpassword, 'student-password'); |
|||
|
|||
echo json_encode($data); |
Before Width: | Height: | Size: 638 B After Width: | Height: | Size: 638 B |
@ -0,0 +1,92 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Reset Calendar events. |
|||
* |
|||
* @package mod_attendance |
|||
* @copyright 2017 onwards Dan Marsden http://danmarsden.com |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
require_once('../../config.php'); |
|||
require_once($CFG->libdir.'/adminlib.php'); |
|||
require_once($CFG->dirroot.'/mod/attendance/lib.php'); |
|||
require_once($CFG->dirroot.'/mod/attendance/locallib.php'); |
|||
|
|||
$action = optional_param('action', '', PARAM_ALPHA); |
|||
|
|||
admin_externalpage_setup('managemodules'); |
|||
$context = context_system::instance(); |
|||
|
|||
// Check permissions. |
|||
require_capability('mod/attendance:viewreports', $context); |
|||
|
|||
$exportfilename = 'attendance-absentee.csv'; |
|||
|
|||
$PAGE->set_url('/mod/attendance/resetcalendar.php'); |
|||
|
|||
$PAGE->set_heading($SITE->fullname); |
|||
|
|||
echo $OUTPUT->header(); |
|||
echo $OUTPUT->heading(get_string('resetcalendar', 'mod_attendance')); |
|||
$tabmenu = attendance_print_settings_tabs('resetcalendar'); |
|||
echo $tabmenu; |
|||
|
|||
if (get_config('attendance', 'enablecalendar')) { |
|||
// Check to see if all sessions have calendar events. |
|||
if ($action == 'create' && confirm_sesskey()) { |
|||
$sessions = $DB->get_recordset('attendance_sessions', array('caleventid' => 0)); |
|||
foreach ($sessions as $session) { |
|||
attendance_create_calendar_event($session); |
|||
if ($session->caleventid) { |
|||
$DB->update_record('attendance_sessions', $session); |
|||
} |
|||
} |
|||
$sessions->close(); |
|||
echo $OUTPUT->notification(get_string('eventscreated', 'mod_attendance'), 'notifysuccess'); |
|||
} else { |
|||
if ($DB->record_exists('attendance_sessions', array('caleventid' => 0))) { |
|||
$createurl = new moodle_url('/mod/attendance/resetcalendar.php', array('action' => 'create')); |
|||
$returnurl = new moodle_url('/admin/settings.php', array('section' => 'modsettingattendance')); |
|||
|
|||
echo $OUTPUT->confirm(get_string('resetcaledarcreate', 'mod_attendance'), $createurl, $returnurl); |
|||
} else { |
|||
echo $OUTPUT->box(get_string("noeventstoreset", "mod_attendance")); |
|||
} |
|||
} |
|||
} else { |
|||
if ($action == 'delete' && confirm_sesskey()) { |
|||
$caleventids = $DB->get_records_select_menu('attendance_sessions', 'caleventid > 0', array(), |
|||
'', 'caleventid, caleventid as id2'); |
|||
$DB->delete_records_list('event', 'id', $caleventids); |
|||
$DB->execute("UPDATE {attendance_sessions} set caleventid = 0"); |
|||
echo $OUTPUT->notification(get_string('eventsdeleted', 'mod_attendance'), 'notifysuccess'); |
|||
} else { |
|||
// Check to see if there are any events that need to be deleted. |
|||
if ($DB->record_exists_select('attendance_sessions', 'caleventid > 0')) { |
|||
$deleteurl = new moodle_url('/mod/attendance/resetcalendar.php', array('action' => 'delete')); |
|||
$returnurl = new moodle_url('/admin/settings.php', array('section' => 'modsettingattendance')); |
|||
|
|||
echo $OUTPUT->confirm(get_string('resetcaledardelete', 'mod_attendance'), $deleteurl, $returnurl); |
|||
} else { |
|||
echo $OUTPUT->box(get_string("noeventstoreset", "mod_attendance")); |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
echo $OUTPUT->footer(); |
@ -0,0 +1,21 @@ |
|||
{{! |
|||
@template attendance/attendance_password_icon |
|||
|
|||
attendance_password icon. |
|||
|
|||
Example context (json): |
|||
{ |
|||
"title": "Help with something", |
|||
"url": "http://example.org/help", |
|||
"linktext": "", |
|||
"icon":{ |
|||
"attributes": [ |
|||
{"name": "src", "value": "../pix/key.svg"}, |
|||
{"name": "alt", "value": "Password icon"} |
|||
] |
|||
} |
|||
} |
|||
}} |
|||
<span class="helptooltip"> |
|||
<a href="{{url}}" title={{#quote}}{{title}}{{/quote}} aria-haspopup="true" target="_blank">{{#icon}}{{>core/pix_icon}}{{/icon}}{{#linktext}}{{.}}{{/linktext}}</a> |
|||
</span> |
@ -0,0 +1,28 @@ |
|||
{{! |
|||
@template attendance/attendance_password_icon Boost Example. |
|||
This is an example of a template you could copy into a boost based theme to use proper popover. |
|||
At the moment we cannot specify different templates to use in plugin so we use |
|||
a cross-compatible link based pop-up for the password. |
|||
|
|||
attendance_password icon. |
|||
|
|||
Example context (json): |
|||
{ |
|||
"title": "Help with something", |
|||
"url": "http://example.org/help", |
|||
"linktext": "", |
|||
"icon":{ |
|||
"attributes": [ |
|||
{"name": "class", "value": "iconhelp"}, |
|||
{"name": "src", "value": "../../../pix/help.svg"}, |
|||
{"name": "alt", "value": "Help icon"} |
|||
] |
|||
} |
|||
} |
|||
}} |
|||
<a class="btn btn-link p-a-0" role="button" |
|||
data-container="body" data-toggle="popover" |
|||
data-placement="{{#ltr}}left{{/ltr}}{{^ltr}}right{{/ltr}}" data-content="<span class='student-pass'>{{text}}</span> {{completedoclink}}" |
|||
data-html="true" tabindex="0" data-trigger="focus"> |
|||
{{#pix}}key, attendance, {{alt}}{{/pix}} |
|||
</a> |
@ -0,0 +1,31 @@ |
|||
@mod @mod_attendance |
|||
Feature: Admin can set default status set for use in new attendance |
|||
|
|||
Background: |
|||
Given the following "courses" exist: |
|||
| 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 | |
|||
And the following "course enrolments" exist: |
|||
| course | user | role | timestart | |
|||
| C1 | teacher1 | editingteacher | ##yesterday## | |
|||
And I log in as "admin" |
|||
And I navigate to "Attendance" node in "Site administration > Plugins" |
|||
And I follow "Default status set" |
|||
And I set the field with xpath "//*[@id='preferencesform']/table/tbody/tr[2]/td[3]/input" to "customstatusdescription" |
|||
And I click on "Update" "button" in the "#preferencesform" "css_element" |
|||
And I should see "Status updated" |
|||
And I log out |
|||
|
|||
@javascript |
|||
Scenario: Modified default status set added to new attendance |
|||
Given I log in as "teacher1" |
|||
And I follow "Course 1" |
|||
And I turn editing mode on |
|||
And I add a "Attendance" to section "1" and I fill the form with: |
|||
| Name | Attendance1 | |
|||
And I follow "Attendance1" |
|||
And I follow "Status set" |
|||
Then the field with xpath "//*[@id='preferencesform']/table/tbody/tr[2]/td[3]/input" matches value "customstatusdescription" |
@ -0,0 +1,203 @@ |
|||
<?php |
|||
// This file is part of Moodle - http://moodle.org/ |
|||
// |
|||
// Moodle is free software: you can redistribute it and/or modify |
|||
// it under the terms of the GNU General Public License as published by |
|||
// the Free Software Foundation, either version 3 of the License, or |
|||
// (at your option) any later version. |
|||
// |
|||
// Moodle is distributed in the hope that it will be useful, |
|||
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
// GNU General Public License for more details. |
|||
// |
|||
// You should have received a copy of the GNU General Public License |
|||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
|||
|
|||
/** |
|||
* Allows default warnings to be modified. |
|||
* |
|||
* @package mod_attendance |
|||
* @copyright 2017 Dan Marsden http://danmarsden.com |
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
|||
*/ |
|||
|
|||
require_once(__DIR__.'/../../config.php'); |
|||
require_once($CFG->libdir.'/adminlib.php'); |
|||
require_once($CFG->libdir.'/formslib.php'); |
|||
require_once($CFG->dirroot.'/mod/attendance/lib.php'); |
|||
require_once($CFG->dirroot.'/mod/attendance/locallib.php'); |
|||
|
|||
$action = optional_param('action', '', PARAM_ALPHA); |
|||
$notid = optional_param('notid', 0, PARAM_INT); |
|||
$id = optional_param('id', 0, PARAM_INT); |
|||
|
|||
$url = new moodle_url('/mod/attendance/warnings.php'); |
|||
|
|||
// This page is used for configuring default set and for configuring attendance level set. |
|||
if (empty($id)) { |
|||
// This is the default status set - show appropriate admin stuff and check admin permissions. |
|||
admin_externalpage_setup('managemodules'); |
|||
|
|||
$output = $PAGE->get_renderer('mod_attendance'); |
|||
echo $OUTPUT->header(); |
|||
echo $OUTPUT->heading(get_string('defaultwarnings', 'mod_attendance')); |
|||
$tabmenu = attendance_print_settings_tabs('defaultwarnings'); |
|||
echo $tabmenu; |
|||
|
|||
} else { |
|||
// This is an attendance level config. |
|||
$cm = get_coursemodule_from_id('attendance', $id, 0, false, MUST_EXIST); |
|||
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); |
|||
$att = $DB->get_record('attendance', array('id' => $cm->instance), '*', MUST_EXIST); |
|||
|
|||
require_login($course, false, $cm); |
|||
$context = context_module::instance($cm->id); |
|||
require_capability('mod/attendance:changepreferences', $context); |
|||
|
|||
$att = new mod_attendance_structure($att, $cm, $course, $PAGE->context); |
|||
|
|||
$PAGE->set_url($url); |
|||
$PAGE->set_title($course->shortname. ": ".$att->name); |
|||
$PAGE->set_heading($course->fullname); |
|||
$PAGE->navbar->add($att->name); |
|||
|
|||
$output = $PAGE->get_renderer('mod_attendance'); |
|||
$tabs = new attendance_tabs($att, attendance_tabs::TAB_WARNINGS); |
|||
echo $output->header(); |
|||
echo $output->heading(get_string('attendanceforthecourse', 'attendance').' :: ' .format_string($course->fullname)); |
|||
echo $output->render($tabs); |
|||
|
|||
} |
|||
|
|||
$mform = new mod_attendance_add_warning_form($url, array('notid' => $notid, 'id' => $id)); |
|||
|
|||
if ($data = $mform->get_data()) { |
|||
if (empty($data->notid)) { |
|||
// Insert new record. |
|||
$notify = new stdClass(); |
|||
if (empty($id)) { |
|||
$notify->idnumber = 0; |
|||
} else { |
|||
$notify->idnumber = $att->id; |
|||
} |
|||
|
|||
$notify->warningpercent = $data->warningpercent; |
|||
$notify->warnafter = $data->warnafter; |
|||
$notify->maxwarn = $data->maxwarn; |
|||
$notify->emailuser = empty($data->emailuser) ? 0 : $data->emailuser; |
|||
$notify->emailsubject = $data->emailsubject; |
|||
$notify->emailcontent = $data->emailcontent['text']; |
|||
$notify->emailcontentformat = $data->emailcontent['format']; |
|||
$notify->thirdpartyemails = ''; |
|||
if (!empty($data->thirdpartyemails)) { |
|||
$notify->thirdpartyemails = implode(',', $data->thirdpartyemails); |
|||
} |
|||
$existingrecord = $DB->record_exists('attendance_warning', array('idnumber' => $notify->idnumber, |
|||
'warningpercent' => $notify->warningpercent, |
|||
'warnafter' => $notify->warnafter)); |
|||
if (empty($existingrecord)) { |
|||
$DB->insert_record('attendance_warning', $notify); |
|||
echo $OUTPUT->notification(get_string('warningupdated', 'mod_attendance'), 'success'); |
|||
} else { |
|||
echo $OUTPUT->notification(get_string('warningfailed', 'mod_attendance'), 'warning'); |
|||
} |
|||
|
|||
} else { |
|||
$notify = $DB->get_record('attendance_warning', array('id' => $data->notid)); |
|||
if (!empty($id) && $data->idnumber != $att->id) { |
|||
// Someone is trying to update a record for a different attendance. |
|||
print_error('invalidcoursemodule'); |
|||
} else { |
|||
$notify = new stdClass(); |
|||
$notify->id = $data->notid; |
|||
$notify->idnumber = $data->idnumber; |
|||
$notify->warningpercent = $data->warningpercent; |
|||
$notify->warnafter = $data->warnafter; |
|||
$notify->maxwarn = $data->maxwarn; |
|||
$notify->emailuser = empty($data->emailuser) ? 0 : $data->emailuser; |
|||
$notify->emailsubject = $data->emailsubject; |
|||
$notify->emailcontentformat = $data->emailcontent['format']; |
|||
$notify->emailcontent = $data->emailcontent['text']; |
|||
$notify->thirdpartyemails = ''; |
|||
if (!empty($data->thirdpartyemails)) { |
|||
$notify->thirdpartyemails = implode(',', $data->thirdpartyemails); |
|||
} |
|||
$existingrecord = $DB->get_record('attendance_warning', array('idnumber' => $notify->idnumber, |
|||
'warningpercent' => $notify->warningpercent, 'warnafter' => $notify->warnafter)); |
|||
if (empty($existingrecord) || $existingrecord->id == $notify->id) { |
|||
$DB->update_record('attendance_warning', $notify); |
|||
echo $OUTPUT->notification(get_string('warningupdated', 'mod_attendance'), 'success'); |
|||
} else { |
|||
echo $OUTPUT->notification(get_string('warningfailed', 'mod_attendance'), 'error'); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
if ($action == 'delete' && !empty($notid)) { |
|||
if (!optional_param('confirm', false, PARAM_BOOL)) { |
|||
$cancelurl = $url; |
|||
$url->params(array('action' => 'delete', 'notid' => $notid, 'sesskey' => sesskey(), 'confirm' => true, 'id' => $id)); |
|||
echo $OUTPUT->confirm(get_string('deletewarningconfirm', 'mod_attendance'), $url, $cancelurl); |
|||
echo $OUTPUT->footer(); |
|||
exit; |
|||
} else { |
|||
require_sesskey(); |
|||
$params = array('id' => $notid); |
|||
if (!empty($att)) { |
|||
// Add id/level to array. |
|||
$params['idnumber'] = $att->id; |
|||
} |
|||
$DB->delete_records('attendance_warning', $params); |
|||
echo $OUTPUT->notification(get_string('warningdeleted', 'mod_attendance'), 'success'); |
|||
} |
|||
} |
|||
if ($action == 'update' && !empty($notid)) { |
|||
$existing = $DB->get_record('attendance_warning', array('id' => $notid)); |
|||
$content = $existing->emailcontent; |
|||
$existing->emailcontent = array(); |
|||
$existing->emailcontent['text'] = $content; |
|||
$existing->emailcontent['format'] = $existing->emailcontentformat; |
|||
$existing->notid = $existing->id; |
|||
$existing->id = $id; |
|||
$mform->set_data($existing); |
|||
$mform->display(); |
|||
} else if ($action == 'add' && confirm_sesskey()) { |
|||
$mform->display(); |
|||
} else { |
|||
if (empty($id)) { |
|||
$warningdesc = get_string('warningdesc', 'mod_attendance'); |
|||
$idnumber = 0; |
|||
} else { |
|||
$warningdesc = get_string('warningdesc_course', 'mod_attendance'); |
|||
$idnumber = $att->id; |
|||
} |
|||
echo $OUTPUT->box($warningdesc, 'generalbox attendancedesc', 'notice'); |
|||
$existingnotifications = $DB->get_records('attendance_warning', |
|||
array('idnumber' => $idnumber), |
|||
'warningpercent'); |
|||
|
|||
if (!empty($existingnotifications)) { |
|||
$table = new html_table(); |
|||
$table->head = array(get_string('warningthreshold', 'mod_attendance'), |
|||
get_string('numsessions', 'mod_attendance'), |
|||
get_string('emailsubject', 'mod_attendance'), |
|||
''); |
|||
foreach ($existingnotifications as $notification) { |
|||
$url->params(array('action' => 'delete', 'notid' => $notification->id, 'id' => $id)); |
|||
$actionbuttons = $OUTPUT->action_icon($url, new pix_icon('t/delete', |
|||
get_string('delete', 'attendance')), null, null); |
|||
$url->params(array('action' => 'update', 'notid' => $notification->id, 'id' => $id)); |
|||
$actionbuttons .= $OUTPUT->action_icon($url, new pix_icon('t/edit', |
|||
get_string('update', 'attendance')), null, null); |
|||
$table->data[] = array($notification->warningpercent, $notification->warnafter, |
|||
$notification->emailsubject, $actionbuttons); |
|||
} |
|||
echo html_writer::table($table); |
|||
} |
|||
$addurl = new moodle_url('/mod/attendance/warnings.php', array('action' => 'add', 'id' => $id)); |
|||
echo $OUTPUT->single_button($addurl, get_string('addwarning', 'mod_attendance')); |
|||
|
|||
} |
|||
|
|||
echo $OUTPUT->footer(); |
Loading…
Reference in new issue