From e537d43422adc04d838966a790f8f0a28dca54ea Mon Sep 17 00:00:00 2001 From: caiobdoneda Date: Sun, 22 May 2016 14:22:48 -0400 Subject: [PATCH] implementing web service support --- classes/attendance_webservices_handler.php | 130 ++++++++++++++++++ db/services.php | 59 ++++++++ externallib.php | 124 +++++++++++++++++ tests/attendance_webservices_test.php | 148 +++++++++++++++++++++ version.php | 3 +- 5 files changed, 462 insertions(+), 2 deletions(-) create mode 100644 classes/attendance_webservices_handler.php create mode 100644 db/services.php create mode 100644 externallib.php create mode 100644 tests/attendance_webservices_test.php diff --git a/classes/attendance_webservices_handler.php b/classes/attendance_webservices_handler.php new file mode 100644 index 0000000..d7fdd5a --- /dev/null +++ b/classes/attendance_webservices_handler.php @@ -0,0 +1,130 @@ +. +/** + * + * @package local_attendance + * @copyright 2015 Caio Bressan Doneda + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once(dirname(__FILE__).'/../../../config.php'); +require_once(dirname(__FILE__).'/../locallib.php'); +require_once(dirname(__FILE__).'/structure.php'); +require_once(dirname(__FILE__).'/../../../lib/sessionlib.php'); +require_once(dirname(__FILE__).'/../../../lib/datalib.php'); + +class attendance_handler { + /** + * For this user, this method searches in all the courses that this user has permission to take attendance, + * looking for today sessions and returns the courses with the sessions. + */ + public static function get_courses_with_today_sessions($userid) { + $usercourses = enrol_get_users_courses($userid); + $attendanceinstance = get_all_instances_in_courses('attendance', $usercourses); + + $coursessessions = array(); + + foreach ($attendanceinstance as $attendance) { + $context = context_course::instance($attendance->course); + if (has_capability('mod/attendance:takeattendances', $context, $userid)) { + $course = $usercourses[$attendance->course]; + $course->attendance_instance = array(); + + $att = new stdClass(); + $att->id = $attendance->id; + $att->course = $attendance->course; + $att->name = $attendance->name; + $att->grade = $attendance->grade; + + $cm = new stdClass(); + $cm->id = $attendance->coursemodule; + + $att = new mod_attendance_structure($att, $cm, $course, $context); + $course->attendance_instance[$att->id] = array(); + $course->attendance_instance[$att->id]['name'] = $att->name; + $todaysessions = $att->get_today_sessions(); + + if (!empty($todaysessions)) { + $course->attendance_instance[$att->id]['today_sessions'] = $todaysessions; + $coursessessions[$course->id] = $course; + } + } + } + + return self::prepare_data($coursessessions); + } + + private static function prepare_data($coursessessions) { + $courses = array(); + + foreach ($coursessessions as $c) { + $courses[$c->id] = new stdClass(); + $courses[$c->id]->shortname = $c->shortname; + $courses[$c->id]->fullname = $c->fullname; + $courses[$c->id]->attendance_instances = $c->attendance_instance; + } + + return $courses; + } + + /* + ** For this session, returns all the necessary data to take an attendance + */ + public static function get_session($sessionid) { + global $DB; + + $session = $DB->get_record('attendance_sessions', array('id' => $sessionid)); + $session->courseid = $DB->get_field('attendance', 'course', array('id' => $session->attendanceid)); + $session->statuses = attendance_get_statuses($session->attendanceid, true, $session->statusset); + $coursecontext = context_course::instance($session->courseid); + $session->users = get_enrolled_users($coursecontext, 'mod/attendance:canbelisted', 0, 'u.id, u.firstname, u.lastname'); + $session->attendance_log = array(); + + if ($attendancelog = $DB->get_records('attendance_log', array('sessionid' => $sessionid), + '', 'studentid, statusid, remarks, id')) { + $session->attendance_log = $attendancelog; + } + + return $session; + } + + public static function update_user_status($sessionid, $studentid, $takenbyid, $statusid, $statusset) { + global $DB; + + $record = new stdClass(); + $record->statusset = $statusset; + $record->sessionid = $sessionid; + $record->timetaken = time(); + $record->takenby = $takenbyid; + $record->statusid = $statusid; + $record->studentid = $studentid; + + if ($attendancelog = $DB->get_record('attendance_log', array('sessionid' => $sessionid, 'studentid' => $studentid))) { + $record->id = $attendancelog->id; + $DB->update_record('attendance_log', $record); + } else { + $DB->insert_record('attendance_log', $record); + } + + if ($attendancesession = $DB->get_record('attendance_sessions', array('id' => $sessionid))) { + $attendancesession->lasttaken = time(); + $attendancesession->lasttakenby = $takenbyid; + $attendancesession->timemodified = time(); + + $DB->update_record('attendance_sessions', $attendancesession); + } + } +} diff --git a/db/services.php b/db/services.php new file mode 100644 index 0000000..ef9ce5f --- /dev/null +++ b/db/services.php @@ -0,0 +1,59 @@ +. + +/** + * Web service local plugin attendance external functions and service definitions. + * + * @package localwsattendance + * @copyright 2015 Caio Bressan Doneda + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + + /** + * We defined the web service functions to install. + */ + $functions = array( + 'mod_wsattendance_get_courses_with_today_sessions' => array( + 'classname' => 'mod_wsattendance_external', + 'methodname' => 'get_courses_with_today_sessions', + 'classpath' => 'mod/attendance/externallib.php', + 'description' => 'Method that retrieves courses with today sessions of a teacher.', + 'type' => 'read', + ), + 'mod_wsattendance_get_session' => array( + 'classname' => 'mod_wsattendance_external', + 'methodname' => 'get_session', + 'classpath' => 'mod/attendance/externallib.php', + 'description' => 'Method that retrieves the session data', + 'type' => 'read', + ), + + 'mod_wsattendance_update_user_status' => array( + 'classname' => 'mod_wsattendance_external', + 'methodname' => 'update_user_status', + 'classpath' => 'mod/attendance/externallib.php', + 'description' => 'Method that updates the user status in a session.', + 'type' => 'write', + ) + ); + + + // We define the services to install as pre-build services. A pre-build service is not editable by administrator. + $services = array('Attendance' => array('functions' => array('mod_wsattendance_get_courses_with_today_sessions', + 'mod_wsattendance_get_session', + 'mod_wsattendance_update_user_status'), + 'restrictedusers' => 0, + 'enabled' => 1)); diff --git a/externallib.php b/externallib.php new file mode 100644 index 0000000..eabe7ee --- /dev/null +++ b/externallib.php @@ -0,0 +1,124 @@ +. +/** + * + * @package local_attendance + * @copyright 2015 Caio Bressan Doneda + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +require_once("$CFG->libdir/externallib.php"); +require_once(dirname(__FILE__).'/classes/attendance_webservices_handler.php'); + +class mod_wsattendance_external extends external_api { + + public static function get_courses_with_today_sessions_parameters() { + return new external_function_parameters ( + array('userid' => new external_value(PARAM_INT, 'User id.', VALUE_DEFAULT, 0))); + } + + public static function get_courses_with_today_sessions($userid) { + return attendance_handler::get_courses_with_today_sessions($userid); + } + + private static function get_session_structure() { + $session = array('id' => new external_value(PARAM_INT, 'Session id.'), + 'attendanceid' => new external_value(PARAM_INT, 'Attendance id.'), + 'groupid' => new external_value(PARAM_INT, 'Group id.'), + 'sessdate' => new external_value(PARAM_INT, 'Session date.'), + 'duration' => new external_value(PARAM_INT, 'Session duration.'), + 'lasttaken' => new external_value(PARAM_INT, 'Session last taken time.'), + 'lasttakenby' => new external_value(PARAM_INT, 'ID of the last user that took this session.'), + 'timemodified' => new external_value(PARAM_INT, 'Time modified.'), + 'description' => new external_value(PARAM_TEXT, 'Session description.'), + 'descriptionformat' => new external_value(PARAM_INT, 'Session description format.'), + 'studentscanmark' => new external_value(PARAM_INT, 'Students can mark their own presence.'), + 'statusset' => new external_value(PARAM_INT, 'Session statusset.')); + + return $session; + } + + public static function get_courses_with_today_sessions_returns() { + $todaysessions = self::get_session_structure(); + + $attendanceinstances = array('name' => new external_value(PARAM_TEXT, 'Attendance name.'), + 'today_sessions' => new external_multiple_structure( + new external_single_structure($todaysessions))); + + $courses = array('shortname' => new external_value(PARAM_TEXT, 'short name of a moodle course.'), + 'fullname' => new external_value(PARAM_TEXT, 'full name of a moodle course.'), + 'attendance_instances' => new external_multiple_structure( + new external_single_structure($attendanceinstances))); + + return new external_multiple_structure(new external_single_structure(($courses))); + } + + public static function get_session_parameters() { + return new external_function_parameters ( + array('sessionid' => new external_value(PARAM_INT, 'session id'))); + } + + public static function get_session($sessionid) { + return attendance_handler::get_session($sessionid); + } + + public static function get_session_returns() { + $statuses = array('id' => new external_value(PARAM_INT, 'Status id.'), + 'attendanceid' => new external_value(PARAM_INT, 'Attendance id.'), + 'acronym' => new external_value(PARAM_TEXT, 'Status acronym.'), + 'description' => new external_value(PARAM_TEXT, 'Status description.'), + 'grade' => new external_value(PARAM_FLOAT, 'Status grade.'), + 'visible' => new external_value(PARAM_INT, 'Status visibility.'), + 'deleted' => new external_value(PARAM_INT, 'informs if this session was deleted.'), + 'setnumber' => new external_value(PARAM_INT, 'Set number.')); + + $users = array('id' => new external_value(PARAM_INT, 'User id.'), + 'firstname' => new external_value(PARAM_TEXT, 'User first name.'), + 'lastname' => new external_value(PARAM_TEXT, 'User last name.')); + + $attendancelog = array('studentid' => new external_value(PARAM_INT, 'Student id.'), + 'statusid' => new external_value(PARAM_TEXT, 'Status id (last time).'), + 'remarks' => new external_value(PARAM_TEXT, 'Last remark.'), + 'id' => new external_value(PARAM_TEXT, 'log id.')); + + $session = self::get_session_structure(); + $session['courseid'] = new external_value(PARAM_INT, 'Course moodle id.'); + $session['statuses'] = new external_multiple_structure(new external_single_structure($statuses)); + $session['attendance_log'] = new external_multiple_structure(new external_single_structure($attendancelog)); + $session['users'] = new external_multiple_structure(new external_single_structure($users)); + + return new external_single_structure($session); + } + + public static function update_user_status_parameters() { + return new external_function_parameters( + array('sessionid' => new external_value(PARAM_INT, 'Session id'), + 'studentid' => new external_value(PARAM_INT, 'Student id'), + 'takenbyid' => new external_value(PARAM_INT, 'Id of the user who took this session'), + 'statusid' => new external_value(PARAM_INT, 'Status id'), + 'statusset' => new external_value(PARAM_TEXT, 'Status set of session'))); + } + + public static function update_user_status($sessionid, $studentid, $takenbyid, $statusid, $statusset) { + return attendance_handler::update_user_status($sessionid, $studentid, $takenbyid, $statusid, $statusset); + } + + public static function update_user_status_returns() { + return new external_value(PARAM_TEXT, 'Http code'); + } +} diff --git a/tests/attendance_webservices_test.php b/tests/attendance_webservices_test.php new file mode 100644 index 0000000..cd3c364 --- /dev/null +++ b/tests/attendance_webservices_test.php @@ -0,0 +1,148 @@ +. +/** + * + * @package local_attendance + * @copyright 2015 Caio Bressan Doneda + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +if (!defined('MOODLE_INTERNAL')) { + die('Direct access to this script is forbidden.'); +} + +global $CFG; + +// Include the code to test. +require_once($CFG->dirroot . '/mod/attendance/classes/attendance_webservices_handler.php'); +require_once($CFG->dirroot . '/mod/attendance/classes/structure.php'); + +/** This class contains the test cases for the functions in attendance_webservices_handler.php. */ +class attendance_webservices_tests extends advanced_testcase { + protected $category; + protected $course; + protected $attendance; + protected $teacher; + protected $sessions; + + public function setUp() { + global $DB; + + $this->category = $this->getDataGenerator()->create_category(); + $this->course = $this->getDataGenerator()->create_course(array('category' => $this->category->id)); + + $record = new stdClass(); + $record->course = $this->course->id; + $record->name = "Attendance"; + $record->grade = 100; + + $DB->insert_record('attendance', $record); + + $this->getDataGenerator()->create_module('attendance', array('course' => $this->course->id)); + + $moduleid = $DB->get_field('modules', 'id', array('name' => 'attendance')); + $cm = $DB->get_record('course_modules', array('course' => $this->course->id, 'module' => $moduleid)); + $context = context_course::instance($this->course->id); + $att = $DB->get_record('attendance', array('id' => $cm->instance), '*', MUST_EXIST); + $this->attendance = new mod_attendance_structure($att, $cm, $this->course, $context); + + $this->create_and_enrol_users(); + + $this->setUser($this->teacher); + + $sessions = array(); + $session = new stdClass(); + $session->sessdate = time(); + $session->duration = 6000; + $session->description = ""; + $session->descriptionformat = 1; + $session->descriptionitemid = 0; + $session->timemodified = time(); + $session->statusset = 0; + $session->groupid = 0; + + // Creating two sessions. + $this->sessions[] = $session; + + $this->attendance->add_sessions($this->sessions); + } + + /** Creating 10 students and 1 teacher. */ + protected function create_and_enrol_users() { + for ($i = 0; $i < 10; $i++) { + $student = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($student->id, $this->course->id, 5); // Enrol as student. + } + + $this->teacher = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, 3); // Enrol as teacher. + } + + public function test_get_courses_with_today_sessions() { + $this->resetAfterTest(true); + + // Just adding the same session again to check if the method returns the right amount of instances. + $this->attendance->add_sessions($this->sessions); + + $courseswithsessions = attendance_handler::get_courses_with_today_sessions($this->teacher->id); + + $this->assertTrue(is_array($courseswithsessions)); + $this->assertEquals(count($courseswithsessions), 1); + $course = array_pop($courseswithsessions); + $this->assertEquals($course->fullname, $this->course->fullname); + $attendanceinstance = array_pop($course->attendance_instances); + $this->assertEquals(count($attendanceinstance['today_sessions']), 2); + } + + public function test_get_session() { + $this->resetAfterTest(true); + + $courseswithsessions = attendance_handler::get_courses_with_today_sessions($this->teacher->id); + + $course = array_pop($courseswithsessions); + $attendanceinstance = array_pop($course->attendance_instances); + $session = array_pop($attendanceinstance['today_sessions']); + + $sessioninfo = attendance_handler::get_session($session->id); + + $this->assertEquals($this->attendance->id, $sessioninfo->attendanceid); + $this->assertEquals($session->id, $sessioninfo->id); + $this->assertEquals(count($sessioninfo->users), 10); + } + + public function test_update_user_status() { + $this->resetAfterTest(true); + + $courseswithsessions = attendance_handler::get_courses_with_today_sessions($this->teacher->id); + + $course = array_pop($courseswithsessions); + $attendanceinstance = array_pop($course->attendance_instances); + $session = array_pop($attendanceinstance['today_sessions']); + + $sessioninfo = attendance_handler::get_session($session->id); + + $student = array_pop($sessioninfo->users); + $status = array_pop($sessioninfo->statuses); + $statusset = $sessioninfo->statusset; + attendance_handler::update_user_status($session->id, $student->id, $this->teacher->id, $status->id, $statusset); + + $sessioninfo = attendance_handler::get_session($session->id); + $log = $sessioninfo->attendance_log; + $studentlog = $log[$student->id]; + + $this->assertEquals($status->id, $studentlog->statusid); + } +} diff --git a/version.php b/version.php index 0dfd611..8d75817 100644 --- a/version.php +++ b/version.php @@ -22,10 +22,9 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -$plugin->version = 2016052000; +$plugin->version = 2016052200; $plugin->requires = 2015051100; $plugin->release = '3.1.0.2'; $plugin->maturity = MATURITY_STABLE; $plugin->cron = 0; $plugin->component = 'mod_attendance'; -